Sublimetext3 打开时解密,使用升华保存时加密

Sublimetext3 打开时解密,使用升华保存时加密,sublimetext3,sublimetext2,sublimetext,sublime-text-plugin,Sublimetext3,Sublimetext2,Sublimetext,Sublime Text Plugin,我正在编写一个简单的插件: 加载时使用.crypt扩展名解密每个文件,并提示输入密码 在保存时对其进行加密(如果在加载过程中已询问密码,则不重新请求密码;如果是将要保存的新文件,则仅询问密码) 在下面的代码中,加密方法很简单:密码是一个整数,加密会移动+密码的每个字符;解密将-password的每个字符移位(即,将password减去每个字符的值)。这既不是真正的加密,也不是安全的方法;当然,稍后我会用AES加密或类似的方法来替换它,但是这个例子,足以展示我在这个问题中遇到的问题 impor

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

  • 加载时使用
    .crypt
    扩展名解密每个文件,并提示输入密码
  • 在保存时对其进行加密(如果在加载过程中已询问密码,则不重新请求密码;如果是将要保存的新文件,则仅询问密码)
在下面的代码中,加密方法很简单:
密码
是一个整数,加密会移动
+密码
的每个字符;解密将
-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解决这个问题:
    在保存操作后还原未加密的明文。这是一种工作方式,但是,即使文件已保存且未做任何更改,升华也会认为文件已被修改!(因为未加密的明文已替换文件保存的加密版本)

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


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

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

我试图用
def on_post_save(视图):
解决这个问题,并在保存操作后恢复未加密的明文。这是一种工作方式,但是,即使文件已保存且未做任何更改,升华也会认为文件已被修改!(因为未加密的明文已替换文件保存的加密版本)

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

更明显的是
save
命令;升华将数据保存到磁盘后,将从文件中删除
标志

另一种方法是使用
视图将
视图标记为暂存视图。设置_scratch(True)
;作为临时视图的视图根本不显示任何类型的修改状态,因此可以使用此选项暂时关闭表示文件已修改的标记

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

通过将视图设置为
scratch
,然后对其应用一个视图设置,并在修改后的
事件侦听器上设置一个
,该侦听器仅在启用该视图设置并删除
scratch
状态(和设置)时触发,可以在一定程度上解决此问题因此,在进行修改之前,缓冲区似乎未被修改

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

这里的另一种选择是,通过手动将文件写入磁盘,而不是让Sublime为您进行文件加密,从而保存您自己;在这种情况下,您可以完全控制缓冲区,并且不需要更改缓冲区的内容,因此它只有在应该变脏的时候才会变脏。不利的一面是,这会留下未加密版本的文件(尽管如果需要,您可以在关闭时删除它)

当加载.crypt文件时,密文将显示在编辑器窗口中,如何将其隐藏,直到在提示中输入密码为止

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


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

感谢您的回答。因此,简而言之,拥有一个良好且无缝的UI/UX并不容易……另一种方法是通过将文件写入磁盘来执行文件加密以节省您自己的时间[…]缺点是这会留下未加密的文件版本:是的,这是一个大问题;即使我
os.remove(…)
未加密的文件,那么任何人都可以“取消删除”它。简言之,出于安全原因,我希望未加密的数据永远不会写入磁盘存储