使用密码保护 LibreOffice 或 OpenOffice ODT 文件免受 Bash 影响

使用密码保护 LibreOffice 或 OpenOffice ODT 文件免受 Bash 影响

从流行的 GNU/Linux 发行版中的 Bash 终端,如何将不受密码保护的 [OpenDocument Text (.odt)](OpenDocument Text) 文档转换为受密码保护的文档?

不幸的是,LibreOffice 手册页甚至不包含字符串“password”,因此这里没有太多帮助。

我不想将文件包装在加密容器中,例如压缩文件这需要先将其解压,然后才能由 LibreOffice 打开。重要的是,文件的收件人无需使用 LibreOffice 和知道文件密码之外的任何东西即可打开文件。

如果可能的话,我更愿意使用 LibreOffice 本身和/或标准 GNU/Linux 实用程序来实现所需的结果。否则,我宁愿只使用通常为 GNU/Linux 发行版打包的自由软件应用程序。

答案1

我创建的模块是一个快速破解;没有错误检查,因此您可能会毁掉您的宝贵文件。使用风险由您自己承担,手头有可靠的备份,并且切勿使用 root 权限运行此程序!

太尔;博士:

  1. 下载模块内容这里并将其保存在某处。
  2. 通过工具->宏->组织宏->libreoffice basic启动Libreoffice并进入宏组织。
  3. 确保从左侧的宏列表中,“LibreOffice Macros”容器中有一个名为“Tools”的库(需要其中的宏)
  4. 选择对话框右侧的“组织者”
  5. 打开容器“我的宏”,选择“标准”,然后在右侧选择“新建”
  6. 将模块命名为“saveWithPassword”
  7. 突出显示新创建的模块后,选择“编辑”。这将打开 IDE,并显示新模块
  8. 确保您选择了正确的模块,然后删除编辑器窗口的内容。
  9. 使用任何 GUI 编辑器(例如 )打开下载的模块文件gedit,选择全部,然后将完整的源代码剪切并粘贴到 LibreOffice 编辑器窗口中。保存并关闭,就完成了。
  10. 如果你熟悉编程和调试,你可以打开一个.odt文件,打开宏IDE(如上),并单步执行宏,查看变量的内容等。

现在,如何使用宏?

假设有一个应使用相同密码保护的 .odt 文件列表。受保护的文件应保存在不同的目标文件夹中(必须存在)以保持原始文件不变。然后你打电话

$ lowriter --invisible <list of .odt files> macro:///standard.saveWithPasswd.saveWithPasswd

(假设您确实按照建议创建了模块)。加载文件后,宏将启动,系统将要求您提供目标目录和密码。然后,文档将保存在目标目录中,并使用提供的密码进行保护。

如果您不想在 Windows 中打开所有文档,还有第二种(静默)方法:

确保没有正在LibreOffice运行的实例。然后运行

$ export password=<the password to use>
$ export target=<full path to the target directory>
$ lowriter --headless <list of .odt files> macro:///standard.saveWithPasswd.saveWithPasswd

现在了解详细信息

主要功能是写入文件,受密码保护。有不同的方法可以做到这一点;如果你只是记录将要交互完成的事情,你最终会得到类似的结果

document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

dim args1(2) as new com.sun.star.beans.PropertyValue
args1(0).Name = "URL"
args1(0).Value = "file:///home/user/Untitled%201.odt"
args1(1).Name = "FilterName"
args1(1).Value = "writer8"
args1(2).Name = "EncryptionData"
args1(2).Value = Array(Array("PackageSHA256UTF8EncryptionKey",Array(-14,-81,-47,-54,-53,84,65,-91,-26,90,122,70,10,95,-104,-104,-73,-71,-117,8,-86,99,35,-94,-27,60,-117,-102,-106,-122,-51,-122)),Array("PackageSHA1UTF8EncryptionKey",Array(24,97,84,113,43,45,95,103,-111,-40,91,-102,9,-121,-71,-113,-94,49,119,-100)),Array("PackageSHA1MS1252EncryptionKey",Array(24,97,84,113,43,45,95,103,-111,-40,91,-102,9,-121,-71,-113,-94,49,119,-100)))

dispatcher.executeDispatch(document, ".uno:SaveAs", "", 0, args1())

什么太复杂了。

在[2] 5.8.3中我找到了更简单的解决方案:

Dim args(0) As New com.sun.star.beans.PropertyValue
Dim sURL$
args(0).Name ="Password"
args(0).Value = "test"
sURL=ConvertToURL("/andrew0/home/andy/test.odt")
ThisComponent.storeToURL(sURL, args())

现在要做的大部分工作是

  • 将密码和目标文件名/目录传递给宏
  • 迭代打开的文档
  • 使用环境变量和对话
  • 查找并使用现有的库函数

我将更深入地描述该模块的某些部分(我认为其余部分是微不足道的):

GlobalScope.BasicLibraries.loadLibrary("Tools")

这将加载全局LibreOffice库“Tools”。其中的一些宏用于处理字符串等。

oComponents = StarDesktop.getComponents()
oDocs = oComponents.createEnumeration()
Do While oDocs.hasMoreElements()
  oDoc = oDocs.nextElement()
  .
  . 
Loop

这会迭代当前打开的文档/框架。至于测试和调试,IDE 也打开了,我必须测试框架是否确实包含有效文档:

sUrl     = oDoc.getUrl()
If sUrl <> "" Then

现在,如果文档定义了 URL(不要在此处测试它是否确实存在...),则会创建一个新 URL,并使用密码保存文档:

sName    = FileNameoutofPath(sUrl)
sName    = myTargetDir & "/" & sName
sUrl     = ConvertToURL(sName)
aArgs(0).Name = "Password"
aArgs(0).Value = myPassword
oDoc.storeToURL(sURL, aArgs())
oDoc.close(true)

这里使用“Tools”库的函数。特别是当lowriter使用 option调用时--headless,文档必须在最后关闭,否则lowriter不会终止。

我无法设法将“密码”和“目标目录”作为参数传递给模块,因此我使用两种方式:作为 shell 环境变量,因为这可以完全自动化,以及作为对话输入。

使用“Environ”功能和默认的“InputBox”获取密码非常简单。如果您想在输入时隐藏密码,则必须创建自己的对话框。

选择目标文件夹有点棘手,因为这不是简单的运行时函数:

oFileDialog = CreateUnoService("com.sun.star.ui.dialogs.FolderPicker")
oUcb = createUnoService("com.sun.star.ucb.SimpleFileAccess")
InitPath = GetPathSettings("Work")
If oUcb.Exists(InitPath) Then
  oFileDialog.SetDisplayDirectory(InitPath)
End If

如果您决定使用静态“InitPath”(“FolderPicker”打开时开始的路径),您可以定义它并剪切从oUcb =到 的所有内容End If,除了oFileDialog.SetDisplayDirectory。从命令行运行时,您还可以设置InitPath = Environ("PWD").现在,起始文件夹是您在设置中定义为“我的文档”文件夹的文件夹LibreOffice

oFileDialog.SetTitle(sTitle)
iAccept = oFileDialog.Execute()
If iAccept = 1 Then
  sPath = oFileDialog.Directory
  getFolderName = sPath
End If

我认为这是不言自明的。但要注意,这里没有错误检查 - 如果取消文件对话框,则不会定义 TargetPath。这应该会导致宏完全中断,或者您必须定义一个while循环而不是Ifin askForTarget

Do While myTargetDir = "" 
  myTargetDir = getFolderName("Please select output directory") 
Loop

你明白了...

我能想到的修改有很多。首先,进行错误检查以确保不会覆盖原始文件(例如测试是否TargetDir为空)或造成其他损害。或者,使用原始文件名、目标和密码创建一个文本文件,并将其传递给宏以按顺序完成(您明白了吗?)。或者,您将所有原始文档放在一个文件夹中,将该文件夹路径传递给宏,然后迭代目录列表(也有示例)。

在研究过程中,我发现(并使用)了一些很好的文档,其中有很多示例:

[1]OpenOffice 宏解释经过安德鲁·皮托尼亚克(也有德语版本)

[2] 同一作者的宏示例:描述的例子未经测试的宏

[3]LibreOffice API 文档

和问题/答案,例如https://ask.libreoffice.org/en/question/29997/how-to-run-a-macro-on-multiple-files-batch/

最后,谢谢你的提问和耐心。重回宏编程真是太有趣了,我重新学习了一些知识,学到了很多新东西。

相关内容