使用 Sublime 在打开时解密,在保存时加密

Decrypt on open, encrypt on save with Sublime

我正在编写一个简单的插件:

在下面的代码中,加密方法很简单:password是一个整数,加密移位+password的每个字符;解密移位 -password 的每个字符(即减去 password 到每个字符的值)。这不是真正的加密,也不是安全的方法;当然我稍后会用 AES 加密或类似的方式替换它,但是这个例子,这足以展示我在这个问题中遇到的问题。

import sublime_plugin, sublime

password = None

class PromptCryptCommand(sublime_plugin.WindowCommand):
    def run(self):
        panel = self.window.show_input_panel("Enter password", "2", self.on_done, None, None)

    def on_done(self, pwd):
        global password
        password = int(pwd)
        self.window.run_command(action)

class EncryptCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        region = sublime.Region(0, self.view.size())
        plaintext = self.view.substr(region)
        ciphertext = ''.join([chr(ord(c)+password) for c in plaintext])
        self.view.replace(edit, region, ciphertext)

class DecryptCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        region = sublime.Region(0, self.view.size())
        ciphertext = self.view.substr(region)
        plaintext = ''.join([chr(ord(c)-password) for c in ciphertext])
        self.view.replace(edit, region, plaintext)

class LoadSaveListener(sublime_plugin.EventListener):
    def on_load(self, view):
        global action
        if view.file_name().endswith(".crypt"):
            action = 'decrypt'
            view.window().run_command('prompt_crypt')

    def on_pre_save(self, view):
        global action
        if view.file_name().endswith(".crypt"):
            if password == None:  # password not entered yet, let's prompt for it
                action = 'encrypt'
                view.window().run_command('prompt_crypt')
            else:  # password already asked when file was loaded, 
                view.window().run_command('encrypt')

我有这些不知道如何解决的问题:

总的来说,这样的东西并不像我们希望的那样干净和无缝;底层系统假定 view 与磁盘上的文件相关联,并且应直接跟踪任何修改。因此,尝试使用未出现在该文件中的内容来表示与文件关联的 view 的内容是有问题的。

虽然它不是那么无缝,但就像让一个命令在后台执行它自己的加密保存(这会留下两个文件)并捕获视图的内容,关闭它并从中重新创建适合的原始文件更符合 Sublime 期望事情如何运作。

I tried to solve this with def on_post_save(view): and restore the unencrypted plaintext after a save operation. It kind of works, but then, even if the file is saved and no change has been done, then Sublime thinks the file is modified! (because unencrypted plaintext has replaced the saved encrypted version of the file).

对缓冲区进行任何类型的修改都会将其标记为 dirty,这就是发生这种情况的原因。只有两件事可以从文件中删除此状态。

其中比较明显的是save命令;一旦 Sublime 将数据保存到磁盘,它就会从文件中删除 dirty 标志,

另一种是使用view.set_scratch(True)view标记为临时视图;草稿视图根本不显示任何类型的修改状态,因此您可以使用它来暂时关闭表示文件已修改的标记。

一个问题是,一旦文件被标记为 scratch,无论您进行多少更改,它都不会显示为已修改。此外,这只会阻止 Sublime 将状态渲染为脏;一旦删除了暂存状态,脏状态将 return(即使视图处于暂存模式时 view.is_dirty() 将 return False)。

您可以在一定程度上解决这个问题,方法是将视图设置为 scratch,然后对其应用视图设置,并让 on_modified 事件侦听器仅在该视图设置为启用并删除 scratch 状态(和设置),以便在您进行修改之前缓冲区看起来未被修改。

这并非没有问题;例如,您可以撤消将文件的加密版本替换为纯文本版本的操作,这可能是可取的,也可能是不可取的。

这里的另一种方法是通过手动将文件写入磁盘而不是让 Sublime 为您完成文件加密来保存自己;在那种情况下,您可以完全控制并且不需要更改缓冲区的内容,因此它只会在应该变脏时变脏。不利的一面是,这会留下一个未加密的文件版本(尽管您可以根据需要删除它 on_close)。

When a .crypt file is loaded, the ciphertext is displayed in the editor window, how to hide this until the password is entered in the prompt?

一种方法是准备一个具有相同前景和背景字符的配色方案,并在输入密码之前覆盖 view 中的 color_scheme 设置,此时点你可以删除它。这会隐藏数据。

另一种方法是从文件中捕获数据,然后使用 view.close() 关闭选项卡(您可能还需要捕获其他信息,例如文件名)。然后您将能够创建一个新的空视图并用解密的数据填充它(尽管您仍然需要执行与上述相同的技巧以使其看起来不脏。