[Solved] Trying to change passwords of odt+ods files via CLI

Java, C++, C#, Delphi... - Using the UNO bridges
Post Reply
s3a
Posts: 4
Joined: Tue May 11, 2021 9:19 am

[Solved] Trying to change passwords of odt+ods files via CLI

Post by s3a »

Hello to everyone who's reading this. :)

I don't know if this is the right place to post this question, but does anyone know how to use the GNU / Linux command-line interface to change passwords of odt (and ods, etc.) files (assuming that it is possible to do)?

I wasn't able to get it done with the libreoffice, lowriter and unoconv CLI utilities. (I'm trying to change passwords of files in bulk with a script.)

Any input would be greatly appreciated!

P.S.
Technically, I'm using LibreOffice, but I see no reason why this would be different from OpenOffice.
Last edited by MrProgrammer on Tue May 18, 2021 1:11 am, edited 4 times in total.
Reason: Add green tick
LibreOffice 1:7.0.4-3 and Debian GNU / Linux
User avatar
robleyd
Moderator
Posts: 5055
Joined: Mon Aug 19, 2013 3:47 am
Location: Murbko, Australia

Re: Trying to change passwords of odt and ods files via the

Post by robleyd »

There are several ways in which passwords might be used for files - which are you referring to?
Cheers
David
OS - Slackware 15 64 bit
Apache OpenOffice 4.1.15
LibreOffice 24.2.1.2; SlackBuild for 24.2.1 by Eric Hameleers
User avatar
Villeroy
Volunteer
Posts: 31269
Joined: Mon Oct 08, 2007 1:35 am
Location: Germany

Re: Trying to change passwords of odt and ods files via the

Post by Villeroy »

If we are talking about the password which encrypts an office document, you have to start LibreOffice in listening mode and write a Python script which connects to the listening office, opens and re-saves each document.
Please, edit this topic's initial post and add "[Solved]" to the subject line if your problem has been solved.
Ubuntu 18.04 with LibreOffice 6.0, latest OpenOffice and LibreOffice
User avatar
Villeroy
Volunteer
Posts: 31269
Joined: Mon Oct 08, 2007 1:35 am
Location: Germany

Re: Trying to change passwords of odt and ods files via the

Post by Villeroy »

 Edit: I found the error in my Office class and fixed the code block. 
The following script works when I run it as a macro but fails when I run it as a stand-alone script ("memory access error" in loadComponentFromURL) and as stand-alone script as well.
There are 4 global variables:

1. g_Connection which is not used when the code is run in macro context. See comment text in the code.
2. g_Pattern = '/tmp/test/*.od?' specifies the path and name pattern
3. g_OldPwd is the password to open the files
4. g_NewPwd is the password to store the files

Store it under ~/.config/libreoffice/4/user/Scripts/python/reencrypt.py (where ~/.config/libreoffice/4/user/ is the path of your user profile)
Start the office from a terminal and call Tools>Macros>Organize>Python... browse "MyMacros">reencrypt > reEncrypt_Macro and push the [Run] button
On the terminal you get an output for each file, either Success: filename or ###FAIL: filename

Code: Select all

import glob
import uno
from com.sun.star.awt.MessageBoxType import MESSAGEBOX, INFOBOX, WARNINGBOX, ERRORBOX, QUERYBOX
from com.sun.star.awt.MessageBoxButtons import BUTTONS_OK, BUTTONS_OK_CANCEL, BUTTONS_ABORT_IGNORE_RETRY, BUTTONS_YES_NO_CANCEL, BUTTONS_YES_NO, BUTTONS_RETRY_CANCEL, DEFAULT_BUTTON_OK, DEFAULT_BUTTON_CANCEL, DEFAULT_BUTTON_RETRY, DEFAULT_BUTTON_YES, DEFAULT_BUTTON_NO, DEFAULT_BUTTON_IGNORE
from com.sun.star.awt.MessageBoxResults import CANCEL, OK, YES, NO, RETRY, IGNORE

#################################
'''
if you call the office suite like this:
 soffice --accept="socket,host=localhost,port=2002;urp;StarOffice.ServiceManager"
then
g_Connect = "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext"
'''
g_Connect = "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext"
g_Pattern = '/tmp/test/*.od?'
g_OldPwd = 'bar'
g_NewPwd = 'foo'
#################################

class Office:
    '''Frequently used office objects and useful methods'''
    def __init__(self, connect_string = '', local_context = uno.getComponentContext()):
        if connect_string:
            # soffice.bin --accept="socket,host=localhost,port=2002;urp;StarOffice.ServiceManager"
            resolver = local_context.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", local_context )
            self.ctx = resolver.resolve(connect_string)
        else:
            self.ctx = local_context
        self.smgr = self.ctx.ServiceManager
        self.tk = self.smgr.createInstance('com.sun.star.awt.Toolkit')
        self.StarDesktop = self.smgr.createInstance('com.sun.star.frame.Desktop')
        self.win = None

    def getDocument(self):
        return self.StarDesktop.CurrentFrame.Controller.getModel()
        
    def createUnoService(self, name,):
        return self.smgr.createInstance(name)
        
    def getURLStruct(self, sURL):
        url = uno.createUnoStruct('com.sun.star.util.URL')
        srv = self.createUnoService('com.sun.star.util.URLTransformer')
        url.Complete = sURL
        x = uno.invoke(srv,"parseStrict",(uno.Any('com.sun.star.util.URL',url),))
        return x[0]==True and x[1] or Null        
        
    def getPropertyValue(self, n, v):
        p = uno.createUnoStruct('com.sun.star.beans.PropertyValue')
        p.Name = n
        p.Value = v
        return p

    def setMsgboxWindow(self, win):
        self.win = win

    def msgbox(self,title='<Dummy>',msg='<Hello World>',etyp=MESSAGEBOX,ebtn=BUTTONS_OK):
        mbox = self.tk.createMessageBox(self.win,etyp,ebtn,title,msg)
        return mbox.execute()        
    
    def mri(self, obj):
        mri = self.createUnoService("mytools.Mri")
        mri.inspect(obj)

def reEncrypt_Macro(**args):
    reEncrypt('')

def reEncrypt(sCon):
    ofc = Office(sCon)
    pv1 = ofc.getPropertyValue("Password", g_OldPwd)
    pv2 = ofc.getPropertyValue("Password", g_NewPwd)
    dtp = ofc.StarDesktop
    g = glob.iglob(g_Pattern)
    for f in g:
        url = uno.systemPathToFileUrl(f)
        try:
            doc = dtp.loadComponentFromURL(url, '_blank', 0, (pv1,))
            doc.storeAsURL(url, (pv2,))
        except:
            print('### FAIL: ' + f)
        else:
            doc.close(False)
            print('SUCCESS: ' + f)
            
if __name__ == "__main__":
    reEncrypt(g_Connect)

g_exportedScripts = reEncrypt_Macro,
I ran this several times changing the passwords between "foo" and "bar" and vice versa. When the files are unencrypted, the password is ignored.

In CLI mode it was intended to be started works like this:

Code: Select all

cd ~/.config/libreoffice/4/user/Scripts/python/
libreoffice --accept="socket,host=localhost,port=2002;urp;StarOffice.ServiceManager" &
python3 reencrypt.py
and the output is

Code: Select all

func=xmlSecCheckVersionExt:file=xmlsec.c:line=188:obj=unknown:subj=unknown:error=19:invalid version:mode=abi compatible;expected minor version=2;real minor version=2;expected subminor version=25;real subminor version=26
SUCCESS: /tmp/test/Untitled 1.ods
func=xmlSecCheckVersionExt:file=xmlsec.c:line=188:obj=unknown:subj=unknown:error=19:invalid version:mode=abi compatible;expected minor version=2;real minor version=2;expected subminor version=25;real subminor version=26
SUCCESS: /tmp/test/USA_Budget_-1789_2017.ods
func=xmlSecCheckVersionExt:file=xmlsec.c:line=188:obj=unknown:subj=unknown:error=19:invalid version:mode=abi compatible;expected minor version=2;real minor version=2;expected subminor version=25;real subminor version=26
SUCCESS: /tmp/test/musterbrief_auskunftsersuchen_und_widerruf.odt
func=xmlSecCheckVersionExt:file=xmlsec.c:line=188:obj=unknown:subj=unknown:error=19:invalid version:mode=abi compatible;expected minor version=2;real minor version=2;expected subminor version=25;real subminor version=26
SUCCESS: /tmp/test/untitled_1.ods
func=xmlSecCheckVersionExt:file=xmlsec.c:line=188:obj=unknown:subj=unknown:error=19:invalid version:mode=abi compatible;expected minor version=2;real minor version=2;expected subminor version=25;real subminor version=26
SUCCESS: /tmp/test/Logfile.odt
func=xmlSecCheckVersionExt:file=xmlsec.c:line=188:obj=unknown:subj=unknown:error=19:invalid version:mode=abi compatible;expected minor version=2;real minor version=2;expected subminor version=25;real subminor version=26
SUCCESS: /tmp/test/untitled_0.odt
func=xmlSecCheckVersionExt:file=xmlsec.c:line=188:obj=unknown:subj=unknown:error=19:invalid version:mode=abi compatible;expected minor version=2;real minor version=2;expected subminor version=25;real subminor version=26
SUCCESS: /tmp/test/Untitled 1.odt
func=xmlSecCheckVersionExt:file=xmlsec.c:line=188:obj=unknown:subj=unknown:error=19:invalid version:mode=abi compatible;expected minor version=2;real minor version=2;expected subminor version=25;real subminor version=26
SUCCESS: /tmp/test/O2_Kündigung.odt
Please, edit this topic's initial post and add "[Solved]" to the subject line if your problem has been solved.
Ubuntu 18.04 with LibreOffice 6.0, latest OpenOffice and LibreOffice
s3a
Posts: 4
Joined: Tue May 11, 2021 9:19 am

Re: Trying to change passwords of odt and ods files via the

Post by s3a »

Sorry for the delay, and thanks for responding!

I put a test odt file with a (regular / AES 256-bit, non-GPG / PGP) password in /tmp, but nothing happens with the file (as far as I can tell).:

Code: Select all

s3a@debian:~$ cd ~/.config/libreoffice/4/s3a/Scripts/python/
s3a@debian:~/.config/libreoffice/4/s3a/Scripts/python$ ls
reencrypt.py
s3a@debian:~/.config/libreoffice/4/s3a/Scripts/python$ libreoffice --accept="socket,host=localhost,port=2002;urp;StarOffice.ServiceManager" &
[1] 55707
s3a@debian:~/.config/libreoffice/4/s3a/Scripts/python$ python3 reencrypt.py 
[1]+  Done                    libreoffice --accept="socket,host=localhost,port=2002;urp;StarOffice.ServiceManager"
s3a@debian:~/.config/libreoffice/4/s3a/Scripts/python$ 
I vaguely recall there being some kind of error message involving gtk xapp or something like that, so I also did

Code: Select all

apt-get update && apt-get install -y python3-xapp xapps-common gir1.2-xapp-1.0 libxapp-dev libxapp1
, but it still doesn't do anything to the odt file in /tmp (as far as I can tell).

P.S.
This is for regular passwords, which I think are encrypted with AES 256 bits, not the GPG/PGP encryption.
LibreOffice 1:7.0.4-3 and Debian GNU / Linux
User avatar
Villeroy
Volunteer
Posts: 31269
Joined: Mon Oct 08, 2007 1:35 am
Location: Germany

Re: Trying to change passwords of odt and ods files via the

Post by Villeroy »

How can I know how you encrypted your documents?

This is what I was assuming and what most users mean when they are talking about password protected documents:
Load a new document, text or spreadsheet.
menu:File>Save As...
Check the password option.
Choose the path you have specified in the script variable g_Pattern. File type is Open Document Text (odt) or spreadsheet (ods) respectively.

When prompted for password and password confirmation, enter the password you have specified in the script variable g_OldPwd.
The password protected ods/odt document is a zip archive with encrypted contents.
Run the script or macro.
Open the document again using the password you have specified in the script variable g_NewPwd.
Please, edit this topic's initial post and add "[Solved]" to the subject line if your problem has been solved.
Ubuntu 18.04 with LibreOffice 6.0, latest OpenOffice and LibreOffice
s3a
Posts: 4
Joined: Tue May 11, 2021 9:19 am

Re: Trying to change passwords of odt and ods files via the

Post by s3a »

Oops!

Sorry, I was (and am :() very tired; I didn't notice that the directory was /tmp/test; I kept seeing it as just /tmp.

This code you made for me is not only helpful for solving the main problem of this thread, but perhaps also for getting me to understand how to interface with LibreOffice and/or OpenOffice in code (as I analyze it more thoroughly later)!

Thanks again!
LibreOffice 1:7.0.4-3 and Debian GNU / Linux
User avatar
Villeroy
Volunteer
Posts: 31269
Joined: Mon Oct 08, 2007 1:35 am
Location: Germany

Re: [SOLVED] Trying to change passwords of odt+ods files via

Post by Villeroy »

Running Linux, I would not use OpenOffice for anything like this.
Just in case you want to try, there are subtile differences.

Code: Select all

cd ~/.openoffice/4/user/Scripts/python/
/opt/openoffice4/program/soffice -accept="socket,host=localhost,port=2002;urp;StarOffice.ServiceManager" &
/opt/openoffice4/program/python reencrypt.py
Storing the script in the profile folder is only important if you want to call it as a macro from within the running office.
The OpenOffice executable uses Sun style arguments with a single dash.
You have to call the Python runtime which is shipped with the office suite.

And yes, a serious Python program would take the variables as arguments. I just copied some macro code, a helper class and added some hard coded arguments.
Please, edit this topic's initial post and add "[Solved]" to the subject line if your problem has been solved.
Ubuntu 18.04 with LibreOffice 6.0, latest OpenOffice and LibreOffice
s3a
Posts: 4
Joined: Tue May 11, 2021 9:19 am

Re: [SOLVED] Trying to change passwords of odt+ods files via

Post by s3a »

Sorry for the delay again, but I just wanted to say thanks for that extra information. You've been immensely helpful. :)
LibreOffice 1:7.0.4-3 and Debian GNU / Linux
Post Reply