【问题标题】:Decrypt on open, encrypt on save with Sublime使用 Sublime 打开时解密,保存时加密
【发布时间】:2019-11-26 15:30:53
【问题描述】:

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

  • 在加载时解密每个带有.crypt 扩展名的文件,提示输入密码
  • 在保存时对其进行加密(如果在加载期间已经询问过密码,则不会重新询问密码;仅在将要保存的新文件时询问密码)

在下面的代码中,加密方法很简单: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')

我遇到了这些我不知道如何解决的问题:

  • 我们用 CTRL + S 多次重新保存,文件被重新保存,即重新加密。示例:

    plaintext = 'abc'
    password = 2
    after one CTRL+S, content = 'cde'
    after one more CTRS+S, content = 'efg'
    after one more CTRS+S, content = 'ghi' etc.
    

    我尝试使用def on_post_save(view): 解决此问题,并在保存操作后恢复未加密的明文。它有点工作,但是,即使文件被保存并且没有进行任何更改,Sublime 认为文件被修改了! (因为未加密的明文已经替换了保存的加密版本的文件)。

  • 加载.crypt文件时,密文显示在编辑器窗口,如何隐藏直到提示输入密码?

【问题讨论】:

标签: sublimetext3 sublimetext2 sublimetext sublime-text-plugin


【解决方案1】:

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

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

我尝试使用def on_post_save(view): 解决此问题,并在保存操作后恢复未加密的明文。它有点工作,但是,即使文件被保存并且没有进行任何更改,Sublime 也会认为文件被修改了! (因为未加密的明文已经替换了保存的加密版本的文件)。

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

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

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

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

您可以通过将视图设置为 scratch 然后对其应用视图设置并拥有一个仅在启用该视图设置并删除 @987654334 时触发的 on_modified 事件侦听器来解决此问题@state(和设置),以便缓冲区在您进行修改之前似乎未修改。

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

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

当一个.crypt文件被加载时,密文显示在编辑器窗口中,在提示输入密码之前如何隐藏?

一种方法是准备一个具有相同前景和背景字符的配色方案,并覆盖view 中的color_scheme 设置,直到输入密码后,您可以将其删除。这会将数据隐藏起来。

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

【讨论】:

  • 感谢您的回答。简而言之,为此拥有一个良好且无缝的 UI/UX 并不容易... 这里的另一种方法是通过将文件写入磁盘来进行文件加密以节省自己 [...]会留下文件的未加密版本:是的,这是一个大问题;即使我os.remove(...) 未加密的文件,任何人都可以“取消删除”它。简而言之,出于安全原因,我希望未加密的数据永远写入磁盘存储。 (未加密:仅在 RAM 中)。知道如何解决这些问题吗?
  • 主要问题是只有save 命令可以打开文件选择器对话框,并且您不能将缓冲区标记为干净。因此,为您的命令设置文件名的所有途径都必须使用on_pre_save 或以不同的方式获取文件名并且根本不使用save 命令,这是有问题的。除此之外,一旦您的view 具有分配的文件名,您就可以轻松地覆盖保存键绑定以运行不同的命令,以便您负责保存,但这让您不得不处理脏状态如上所述的文件。
  • 谢谢@OdatNurd。有没有办法“解耦”保存在磁盘上的字节(即磁盘上的文件test.crypt)和编辑器“视图”的内容?即视图 always 保持未加密状态,无需使用 self.view.replace(edit, region, ciphertext) 之类的技巧,但在保存操作期间,要保存到磁盘的缓冲区被修改,视图不变。只会修改“序列化到磁盘”,但不会修改视图。 Sublime 可以做到这一点吗?
  • 据我所知,无法破坏view 与其支持文件之间的关联,因此您必须确保根本没有连接(通过使用您自己的自定义@ 987654347@ 命令),以便 view 永远不会与文件关联。
  • 哦好主意@OdatNurd:有没有办法覆盖原来的save / 防止Sublime 本身将文件保存到磁盘?即要求 Sublime 在保存时在磁盘上写入任何内容?然后我会在on_pre_saveon_post_save 期间实现自己的actuel write-to-disk IO 操作。这个解决方案可以让我避免 hack self.view.replace(edit, region, ciphertext) 造成其他问题(例如 "dirty" 等)。
猜你喜欢
  • 1970-01-01
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-17
  • 1970-01-01
相关资源
最近更新 更多