Hello community,

here is the log from the commit of package python-msoffcrypto-tool for 
openSUSE:Factory checked in at 2019-09-13 14:58:21
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-msoffcrypto-tool (Old)
 and      /work/SRC/openSUSE:Factory/.python-msoffcrypto-tool.new.7948 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-msoffcrypto-tool"

Fri Sep 13 14:58:21 2019 rev:2 rq:730104 version:4.10.1

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-msoffcrypto-tool/python-msoffcrypto-tool.changes
  2019-08-05 10:38:57.599315894 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-msoffcrypto-tool.new.7948/python-msoffcrypto-tool.changes
        2019-09-13 14:58:27.273277582 +0200
@@ -1,0 +2,6 @@
+Wed Sep 11 11:10:17 UTC 2019 - Tomáš Chvátal <[email protected]>
+
+- Update to 4.10.1:
+  * ship license file
+
+-------------------------------------------------------------------

Old:
----
  LICENSE.txt
  msoffcrypto-tool-4.10.0.tar.gz

New:
----
  msoffcrypto-tool-4.10.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-msoffcrypto-tool.spec ++++++
--- /var/tmp/diff_new_pack.LtwLzT/_old  2019-09-13 14:58:29.033277656 +0200
+++ /var/tmp/diff_new_pack.LtwLzT/_new  2019-09-13 14:58:29.033277656 +0200
@@ -18,14 +18,13 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-msoffcrypto-tool
-Version:        4.10.0
+Version:        4.10.1
 Release:        0
 Summary:        Library for decrypting MS Office files
 License:        MIT
 Group:          Development/Languages/Python
 URL:            https://github.com/nolze/msoffcrypto-tool
 Source:         
https://files.pythonhosted.org/packages/source/m/msoffcrypto-tool/msoffcrypto-tool-%{version}.tar.gz
-Source1:        
https://raw.githubusercontent.com/nolze/msoffcrypto-tool/master/LICENSE.txt
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
@@ -48,7 +47,6 @@
 %setup -q -n msoffcrypto-tool-%{version}
 # Delete empty file as of v4.10.0
 wc -c msoffcrypto/method/xor_obfuscation.py | sed -n '/^0/{s/^0\s//;p}' | 
xargs rm
-cp %{SOURCE1} .
 
 %build
 %python_build

++++++ msoffcrypto-tool-4.10.0.tar.gz -> msoffcrypto-tool-4.10.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msoffcrypto-tool-4.10.0/LICENSE.txt 
new/msoffcrypto-tool-4.10.1/LICENSE.txt
--- old/msoffcrypto-tool-4.10.0/LICENSE.txt     1970-01-01 01:00:00.000000000 
+0100
+++ new/msoffcrypto-tool-4.10.1/LICENSE.txt     2019-08-02 04:38:36.000000000 
+0200
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2015 nolze
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msoffcrypto-tool-4.10.0/MANIFEST.in 
new/msoffcrypto-tool-4.10.1/MANIFEST.in
--- old/msoffcrypto-tool-4.10.0/MANIFEST.in     2019-04-14 05:38:42.000000000 
+0200
+++ new/msoffcrypto-tool-4.10.1/MANIFEST.in     2019-08-02 04:38:36.000000000 
+0200
@@ -1,4 +1,5 @@
 include README.md
+include LICENSE.txt
 include .noserc
 
 # include test source and data files
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msoffcrypto-tool-4.10.0/PKG-INFO 
new/msoffcrypto-tool-4.10.1/PKG-INFO
--- old/msoffcrypto-tool-4.10.0/PKG-INFO        2019-04-14 05:39:19.000000000 
+0200
+++ new/msoffcrypto-tool-4.10.1/PKG-INFO        2019-08-02 04:39:13.000000000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: msoffcrypto-tool
-Version: 4.10.0
+Version: 4.10.1
 Summary: A Python tool and library for decrypting MS Office files with 
passwords or other keys
 Home-page: https://github.com/nolze/msoffcrypto-tool
 Author: nolze
@@ -38,13 +38,20 @@
         ### As CLI tool (with password)
         
         ```
-        msoffcrypto-tool -p Passw0rd encrypted.docx decrypted.docx
+        msoffcrypto-tool encrypted.docx decrypted.docx -p Passw0rd
+        ```
+        
+        Password is prompted if you omit the password argument value:
+        
+        ```bash
+        $ msoffcrypto-tool encrypted.docx decrypted.docx -p
+        Password:
         ```
         
         Test if the file is encrypted or not (exit code 0 or 1 is returned):
         
         ```
-        msoffcrypto-tool --test -v document.doc
+        msoffcrypto-tool document.doc --test -v
         ```
         
         ### As library
@@ -91,7 +98,7 @@
         * [ ] Excel 95 Encryption (Excel 95 and prior)
         * [ ] PowerPoint 95 Encryption (PowerPoint 95 and prior)
         
-        PRs welcome!
+        PRs are welcome!
         
         ## Tests
         
@@ -118,7 +125,7 @@
         * [x] Add the password prompt mode for CLI
         * [ ] Redesign APIs (v5.0.0)
         * [ ] Improve error types (v5.0.0)
-        * [ ] Use `ctypes.Structure`
+        * [ ] Use a kind of `ctypes.Structure`
         * [ ] Support encryption
         
         ## See also
@@ -136,6 +143,7 @@
         
         * herumi/msoffice <https://github.com/herumi/msoffice>
         * DocRecrypt 
<https://blogs.technet.microsoft.com/office_resource_kit/2013/01/23/now-you-can-reset-or-remove-a-password-from-a-word-excel-or-powerpoint-filewith-office-2013/>
+        * Apache POI - the Java API for Microsoft Documents 
<https://poi.apache.org/>
         
         ## Use cases and mentions
         
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msoffcrypto-tool-4.10.0/README.md 
new/msoffcrypto-tool-4.10.1/README.md
--- old/msoffcrypto-tool-4.10.0/README.md       2019-04-14 05:38:42.000000000 
+0200
+++ new/msoffcrypto-tool-4.10.1/README.md       2019-08-02 04:38:36.000000000 
+0200
@@ -30,13 +30,20 @@
 ### As CLI tool (with password)
 
 ```
-msoffcrypto-tool -p Passw0rd encrypted.docx decrypted.docx
+msoffcrypto-tool encrypted.docx decrypted.docx -p Passw0rd
+```
+
+Password is prompted if you omit the password argument value:
+
+```bash
+$ msoffcrypto-tool encrypted.docx decrypted.docx -p
+Password:
 ```
 
 Test if the file is encrypted or not (exit code 0 or 1 is returned):
 
 ```
-msoffcrypto-tool --test -v document.doc
+msoffcrypto-tool document.doc --test -v
 ```
 
 ### As library
@@ -83,7 +90,7 @@
 * [ ] Excel 95 Encryption (Excel 95 and prior)
 * [ ] PowerPoint 95 Encryption (PowerPoint 95 and prior)
 
-PRs welcome!
+PRs are welcome!
 
 ## Tests
 
@@ -110,7 +117,7 @@
 * [x] Add the password prompt mode for CLI
 * [ ] Redesign APIs (v5.0.0)
 * [ ] Improve error types (v5.0.0)
-* [ ] Use `ctypes.Structure`
+* [ ] Use a kind of `ctypes.Structure`
 * [ ] Support encryption
 
 ## See also
@@ -128,6 +135,7 @@
 
 * herumi/msoffice <https://github.com/herumi/msoffice>
 * DocRecrypt 
<https://blogs.technet.microsoft.com/office_resource_kit/2013/01/23/now-you-can-reset-or-remove-a-password-from-a-word-excel-or-powerpoint-filewith-office-2013/>
+* Apache POI - the Java API for Microsoft Documents <https://poi.apache.org/>
 
 ## Use cases and mentions
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msoffcrypto-tool-4.10.0/msoffcrypto/__init__.py 
new/msoffcrypto-tool-4.10.1/msoffcrypto/__init__.py
--- old/msoffcrypto-tool-4.10.0/msoffcrypto/__init__.py 2019-04-14 
05:38:42.000000000 +0200
+++ new/msoffcrypto-tool-4.10.1/msoffcrypto/__init__.py 2019-08-02 
04:38:36.000000000 +0200
@@ -2,7 +2,7 @@
 import zipfile
 
 
-__version__ = "4.10.0"
+__version__ = "4.10.1"
 
 
 def OfficeFile(file):
@@ -15,11 +15,15 @@
         BaseOfficeFile object.
 
     Examples:
-        >>> f = open("tests/inputs/example_password.docx", "rb")
-        >>> officefile = OfficeFile(f)
-        >>> officefile.keyTypes
+        >>> with open("tests/inputs/example_password.docx", "rb") as f:
+        ...     officefile = OfficeFile(f)
+        ...     officefile.keyTypes
         ('password', 'private_key', 'secret_key')
+
+    Given file handle will not be closed, the file position will most certainly
+    change.
     '''
+    file.seek(0)     # required by isOleFile
     if olefile.isOleFile(file):
         ole = olefile.OleFileIO(file)
     elif zipfile.is_zipfile(file):  # Heuristic
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msoffcrypto-tool-4.10.0/msoffcrypto/format/doc97.py 
new/msoffcrypto-tool-4.10.1/msoffcrypto/format/doc97.py
--- old/msoffcrypto-tool-4.10.0/msoffcrypto/format/doc97.py     2019-04-14 
05:38:42.000000000 +0200
+++ new/msoffcrypto-tool-4.10.1/msoffcrypto/format/doc97.py     2019-08-02 
04:38:36.000000000 +0200
@@ -275,7 +275,7 @@
 class Doc97File(base.BaseOfficeFile):
     def __init__(self, file):
         self.file = file
-        ole = olefile.OleFileIO(file)
+        ole = olefile.OleFileIO(file)  # do not close this, would close file
         self.ole = ole
         self.format = "doc97"
         self.keyTypes = ['password']
@@ -283,7 +283,8 @@
         self.salt = None
 
         # https://msdn.microsoft.com/en-us/library/dd944620(v=office.12).aspx
-        fib = _parseFib(ole.openstream('wordDocument'))
+        with ole.openstream('wordDocument') as stream:
+            fib = _parseFib(stream)
 
         # https://msdn.microsoft.com/en-us/library/dd923367(v=office.12).aspx
         tablename = '1Table' if fib.base.fWhichTblStm == 1 else '0Table'
@@ -305,31 +306,31 @@
             else:  # elif fib.base.fObfuscation == 0:
                 encryptionHeader_size = fib.base.IKey
                 logger.debug("encryptionHeader_size: 
{}".format(hex(encryptionHeader_size)))
-                table = self.ole.openstream(self.info.tablename)
-                encryptionHeader = table
-                encryptionVersionInfo = table.read(4)
-                vMajor, vMinor = unpack("<HH", encryptionVersionInfo)
-                logger.debug("Version: {} {}".format(vMajor, vMinor))
-                if vMajor == 0x0001 and vMinor == 0x0001:  # RC4
-                    info = _parse_header_RC4(encryptionHeader)
-                    if DocumentRC4.verifypw(password, info['salt'], 
info['encryptedVerifier'], info['encryptedVerifierHash']):
-                        self.type = 'rc4'
-                        self.key = password
-                        self.salt = info['salt']
+                with self.ole.openstream(self.info.tablename) as table:
+                    encryptionHeader = table          # TODO why create a 2nd 
reference to same stream?
+                    encryptionVersionInfo = table.read(4)
+                    vMajor, vMinor = unpack("<HH", encryptionVersionInfo)
+                    logger.debug("Version: {} {}".format(vMajor, vMinor))
+                    if vMajor == 0x0001 and vMinor == 0x0001:  # RC4
+                        info = _parse_header_RC4(encryptionHeader)
+                        if DocumentRC4.verifypw(password, info['salt'], 
info['encryptedVerifier'], info['encryptedVerifierHash']):
+                            self.type = 'rc4'
+                            self.key = password
+                            self.salt = info['salt']
+                        else:
+                            raise Exception("Failed to verify password")
+                    elif vMajor in [0x0002, 0x0003, 0x0004] and vMinor == 
0x0002:  # RC4 CryptoAPI
+                        info = _parse_header_RC4CryptoAPI(encryptionHeader)
+                        if DocumentRC4CryptoAPI.verifypw(password, 
info['salt'], info['keySize'],
+                                                         
info['encryptedVerifier'], info['encryptedVerifierHash']):
+                            self.type = 'rc4_cryptoapi'
+                            self.key = password
+                            self.salt = info['salt']
+                            self.keySize = info['keySize']
+                        else:
+                            raise Exception("Failed to verify password")
                     else:
-                        raise Exception("Failed to verify password")
-                elif vMajor in [0x0002, 0x0003, 0x0004] and vMinor == 0x0002:  
# RC4 CryptoAPI
-                    info = _parse_header_RC4CryptoAPI(encryptionHeader)
-                    if DocumentRC4CryptoAPI.verifypw(password, info['salt'], 
info['keySize'],
-                                                     
info['encryptedVerifier'], info['encryptedVerifierHash']):
-                        self.type = 'rc4_cryptoapi'
-                        self.key = password
-                        self.salt = info['salt']
-                        self.keySize = info['keySize']
-                    else:
-                        raise Exception("Failed to verify password")
-                else:
-                    raise Exception("Unsupported encryption method")
+                        raise Exception("Unsupported encryption method")
 
     def decrypt(self, ofile):
         # fd, _ofile_path = tempfile.mkstemp()
@@ -337,11 +338,6 @@
         # shutil.copyfile(os.path.realpath(self.file.name), _ofile_path)
         # outole = olefile.OleFileIO(_ofile_path, write_mode=True)
 
-        _ofile = tempfile.TemporaryFile()
-        self.file.seek(0)
-        shutil.copyfileobj(self.file, _ofile)
-        outole = olefile.OleFileIO(_ofile, write_mode=True)
-
         obuf1 = io.BytesIO()
         fibbase = FibBase(
             wIdent=self.info.fib.base.wIdent,
@@ -383,27 +379,29 @@
         obuf1.seek(0)
         obuf1.write(header)
 
-        worddocument = self.ole.openstream('wordDocument')
-        worddocument.seek(len(header))
-        header = worddocument.read(FIB_LENGTH - len(header))
-        worddocument.seek(0)
-        logger.debug(len(header))
-        obuf1.write(header)
+        with self.ole.openstream('wordDocument') as worddocument:
+            worddocument.seek(len(header))
+            header = worddocument.read(FIB_LENGTH - len(header))
+            worddocument.seek(0)
+            logger.debug(len(header))
+            obuf1.write(header)
 
-        if self.type == "rc4":
-            dec1 = DocumentRC4.decrypt(self.key, self.salt, worddocument)
-        elif self.type == "rc4_cryptoapi":
-            dec1 = DocumentRC4CryptoAPI.decrypt(self.key, self.salt, 
self.keySize, worddocument)
-        dec1.seek(FIB_LENGTH)
-        obuf1.write(dec1.read())
-        obuf1.seek(0)
+            if self.type == "rc4":
+                dec1 = DocumentRC4.decrypt(self.key, self.salt, worddocument)
+            elif self.type == "rc4_cryptoapi":
+                dec1 = DocumentRC4CryptoAPI.decrypt(self.key, self.salt, 
self.keySize, worddocument)
+            dec1.seek(FIB_LENGTH)
+            obuf1.write(dec1.read())
+            obuf1.seek(0)
 
         # TODO: Preserve header
         obuf2 = io.BytesIO()
         if self.type == "rc4":
-            dec2 = DocumentRC4.decrypt(self.key, self.salt, 
self.ole.openstream(self.info.tablename))
+            with self.ole.openstream(self.info.tablename) as stream:
+                dec2 = DocumentRC4.decrypt(self.key, self.salt, stream)
         elif self.type == "rc4_cryptoapi":
-            dec2 = DocumentRC4CryptoAPI.decrypt(self.key, self.salt, 
self.keySize, self.ole.openstream(self.info.tablename))
+            with self.ole.openstream(self.info.tablename) as stream:
+                dec2 = DocumentRC4CryptoAPI.decrypt(self.key, self.salt, 
self.keySize, stream)
         obuf2.write(dec2.read())
         obuf2.seek(0)
 
@@ -411,22 +409,29 @@
         if self.ole.exists('Data'):
             obuf3 = io.BytesIO()
             if self.type == "rc4":
-                dec3 = DocumentRC4.decrypt(self.key, self.salt, 
self.ole.openstream('Data'))
+                with self.ole.openstream('Data') as data_stream:
+                    dec3 = DocumentRC4.decrypt(self.key, self.salt, 
data_stream)
             elif self.type == "rc4_cryptoapi":
-                dec3 = DocumentRC4CryptoAPI.decrypt(self.key, self.salt, 
self.keySize, self.ole.openstream('Data'))
+                with self.ole.openstream('Data') as data_stream:
+                    dec3 = DocumentRC4CryptoAPI.decrypt(self.key, self.salt, 
self.keySize, data_stream)
             obuf3.write(dec3.read())
             obuf3.seek(0)
 
-        outole.write_stream('wordDocument', obuf1.read())
-        outole.write_stream(self.info.tablename, obuf2.read())
-        if obuf3:
-            outole.write_stream('Data', obuf3.read())
+        with tempfile.TemporaryFile() as _ofile:
+            self.file.seek(0)
+            shutil.copyfileobj(self.file, _ofile)
+            outole = olefile.OleFileIO(_ofile, write_mode=True)
+
+            outole.write_stream('wordDocument', obuf1.read())
+            outole.write_stream(self.info.tablename, obuf2.read())
+            if obuf3:
+                outole.write_stream('Data', obuf3.read())
 
-        # _ofile = open(_ofile_path, 'rb')
+            # _ofile = open(_ofile_path, 'rb')
 
-        _ofile.seek(0)
+            _ofile.seek(0)
 
-        shutil.copyfileobj(_ofile, ofile)
+            shutil.copyfileobj(_ofile, ofile)
 
     def is_encrypted(self):
         return self.info.fib.base.fEncrypted
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msoffcrypto-tool-4.10.0/msoffcrypto/format/ooxml.py 
new/msoffcrypto-tool-4.10.1/msoffcrypto/format/ooxml.py
--- old/msoffcrypto-tool-4.10.0/msoffcrypto/format/ooxml.py     2019-04-14 
05:38:42.000000000 +0200
+++ new/msoffcrypto-tool-4.10.1/msoffcrypto/format/ooxml.py     2019-08-02 
04:38:36.000000000 +0200
@@ -74,10 +74,12 @@
         self.format = "ooxml"
         file.seek(0)  # TODO: Investigate the effect (required for 
olefile.isOleFile)
         # olefile cannot process non password protected ooxml files.
+        # TODO: this code is duplicate of OfficeFile(). Merge?
         if olefile.isOleFile(file):
             ole = olefile.OleFileIO(file)
             self.file = ole
-            self.type, self.info = 
_parseinfo(self.file.openstream('EncryptionInfo'))
+            with self.file.openstream('EncryptionInfo') as stream:
+                self.type, self.info = _parseinfo(stream)
             logger.debug("OOXMLFile.type: {}".format(self.type))
             self.secret_key = None
             if self.type == 'agile':
@@ -134,14 +136,16 @@
 
     def decrypt(self, ofile):
         if self.type == 'agile':
-            obuf = ECMA376Agile.decrypt(
-                self.secret_key, self.info['keyDataSalt'],
-                self.info['keyDataHashAlgorithm'],
-                self.file.openstream('EncryptedPackage')
-            )
+            with self.file.openstream('EncryptedPackage') as stream:
+                obuf = ECMA376Agile.decrypt(
+                    self.secret_key, self.info['keyDataSalt'],
+                    self.info['keyDataHashAlgorithm'],
+                    stream
+                )
             ofile.write(obuf)
         elif self.type == 'standard':
-            obuf = ECMA376Standard.decrypt(self.secret_key, 
self.file.openstream('EncryptedPackage'))
+            with self.file.openstream('EncryptedPackage') as stream:
+                obuf = ECMA376Standard.decrypt(self.secret_key, stream)
             ofile.write(obuf)
 
         # If the file is successfully decrypted, there must be a valid OOXML 
file, i.e. a valid zip file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msoffcrypto-tool-4.10.0/msoffcrypto/format/ppt97.py 
new/msoffcrypto-tool-4.10.1/msoffcrypto/format/ppt97.py
--- old/msoffcrypto-tool-4.10.0/msoffcrypto/format/ppt97.py     2019-04-14 
05:38:42.000000000 +0200
+++ new/msoffcrypto-tool-4.10.1/msoffcrypto/format/ppt97.py     2019-08-02 
04:38:36.000000000 +0200
@@ -492,13 +492,14 @@
 class Ppt97File(base.BaseOfficeFile):
     def __init__(self, file):
         self.file = file
-        ole = olefile.OleFileIO(file)
+        ole = olefile.OleFileIO(file)  # do not close this, would close file
         self.ole = ole
         self.format = "ppt97"
         self.keyTypes = ['password']
         self.key = None
         self.salt = None
 
+        # streams closed in destructor:
         currentuser = ole.openstream('Current User')
         powerpointdocument = ole.openstream('PowerPoint Document')
 
@@ -508,6 +509,14 @@
             powerpointdocument=powerpointdocument,
         )
 
+    def __del__(self):
+        """Destructor, closes opened streams."""
+        if hasattr(self, 'data') and self.data:
+            if self.data.currentuser:
+                self.data.currentuser.close()
+            if self.data.powerpointdocument:
+                self.data.powerpointdocument.close()
+
     def load_key(self, password=None):
         persistobjectdirectory = construct_persistobjectdirectory(self.data)
         logger.debug("[*] persistobjectdirectory: 
{}".format(persistobjectdirectory))
@@ -547,11 +556,6 @@
             raise Exception("Failed to verify password")
 
     def decrypt(self, ofile):
-        _ofile = tempfile.TemporaryFile()
-        self.file.seek(0)
-        shutil.copyfileobj(self.file, _ofile)
-        outole = olefile.OleFileIO(_ofile, write_mode=True)
-
         # Current User Stream
         self.data.currentuser.seek(0)
         currentuser = _parseCurrentUser(self.data.currentuser)
@@ -580,7 +584,7 @@
 
         buf = _packCurrentUser(currentuser_new)
         buf.seek(0)
-        outole.write_stream('Current User', buf.read())
+        currentuser_buf = buf
 
         # List of encrypted parts: 
https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-ppt/b0963334-4408-4621-879a-ef9c54551fd8
 
@@ -712,14 +716,22 @@
         logger.debug("[*] powerpointdocument_size={}, 
len(dec_buf.read())={}".format(powerpointdocument_size, len(dec_buf.read())))
 
         dec_buf.seek(0)
-        outole.write_stream('PowerPoint Document', dec_buf.read())
+        powerpointdocument_dec_buf = dec_buf
 
         # TODO: Pictures Stream
         # TODO: Encrypted Summary Info Stream
 
-        # Finalize
-        _ofile.seek(0)
-        shutil.copyfileobj(_ofile, ofile)
+        with tempfile.TemporaryFile() as _ofile:
+            self.file.seek(0)
+            shutil.copyfileobj(self.file, _ofile)
+            outole = olefile.OleFileIO(_ofile, write_mode=True)
+
+            outole.write_stream('Current User', currentuser_buf.read())
+            outole.write_stream('PowerPoint Document', 
powerpointdocument_dec_buf.read())
+
+            # Finalize
+            _ofile.seek(0)
+            shutil.copyfileobj(_ofile, ofile)
 
         return
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msoffcrypto-tool-4.10.0/msoffcrypto/format/xls97.py 
new/msoffcrypto-tool-4.10.1/msoffcrypto/format/xls97.py
--- old/msoffcrypto-tool-4.10.0/msoffcrypto/format/xls97.py     2019-04-14 
05:38:42.000000000 +0200
+++ new/msoffcrypto-tool-4.10.1/msoffcrypto/format/xls97.py     2019-08-02 
04:38:36.000000000 +0200
@@ -445,20 +445,25 @@
 class Xls97File(base.BaseOfficeFile):
     def __init__(self, file):
         self.file = file
-        ole = olefile.OleFileIO(file)
+        ole = olefile.OleFileIO(file)  # do not close this, would close file
         self.ole = ole
         self.format = "xls97"
         self.keyTypes = ['password']
         self.key = None
         self.salt = None
 
-        workbook = ole.openstream('Workbook')
+        workbook = ole.openstream('Workbook')    # closed in destructor
 
         Data = namedtuple('Data', ['workbook'])
         self.data = Data(
             workbook=workbook,
         )
 
+    def __del__(self):
+        """Destructor, closes opened stream."""
+        if hasattr(self, 'data') and self.data and self.data.workbook:
+            self.data.workbook.close()
+
     def load_key(self, password=None):
         self.data.workbook.seek(0)
         workbook = _BIFFStream(self.data.workbook)
@@ -519,11 +524,6 @@
         # shutil.copyfile(os.path.realpath(self.file.name), _ofile_path)
         # outole = olefile.OleFileIO(_ofile_path, write_mode=True)
 
-        _ofile = tempfile.TemporaryFile()
-        self.file.seek(0)
-        shutil.copyfileobj(self.file, _ofile)
-        outole = olefile.OleFileIO(_ofile, write_mode=True)
-
         # List of encrypted parts: 
https://msdn.microsoft.com/en-us/library/dd905723(v=office.12).aspx
 
         # Workbook stream
@@ -576,13 +576,20 @@
         # f.write(dec.read())
         # dec.seek(0)
 
-        outole.write_stream('Workbook', dec.read())
+        workbook_dec = dec
+
+        with tempfile.TemporaryFile() as _ofile:
+            self.file.seek(0)
+            shutil.copyfileobj(self.file, _ofile)
+            outole = olefile.OleFileIO(_ofile, write_mode=True)
+
+            outole.write_stream('Workbook', workbook_dec.read())
 
-        # _ofile = open(_ofile_path, 'rb')
+            # _ofile = open(_ofile_path, 'rb')
 
-        _ofile.seek(0)
+            _ofile.seek(0)
 
-        shutil.copyfileobj(_ofile, ofile)
+            shutil.copyfileobj(_ofile, ofile)
 
         return
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/msoffcrypto-tool-4.10.0/msoffcrypto_tool.egg-info/PKG-INFO 
new/msoffcrypto-tool-4.10.1/msoffcrypto_tool.egg-info/PKG-INFO
--- old/msoffcrypto-tool-4.10.0/msoffcrypto_tool.egg-info/PKG-INFO      
2019-04-14 05:39:19.000000000 +0200
+++ new/msoffcrypto-tool-4.10.1/msoffcrypto_tool.egg-info/PKG-INFO      
2019-08-02 04:39:13.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: msoffcrypto-tool
-Version: 4.10.0
+Version: 4.10.1
 Summary: A Python tool and library for decrypting MS Office files with 
passwords or other keys
 Home-page: https://github.com/nolze/msoffcrypto-tool
 Author: nolze
@@ -38,13 +38,20 @@
         ### As CLI tool (with password)
         
         ```
-        msoffcrypto-tool -p Passw0rd encrypted.docx decrypted.docx
+        msoffcrypto-tool encrypted.docx decrypted.docx -p Passw0rd
+        ```
+        
+        Password is prompted if you omit the password argument value:
+        
+        ```bash
+        $ msoffcrypto-tool encrypted.docx decrypted.docx -p
+        Password:
         ```
         
         Test if the file is encrypted or not (exit code 0 or 1 is returned):
         
         ```
-        msoffcrypto-tool --test -v document.doc
+        msoffcrypto-tool document.doc --test -v
         ```
         
         ### As library
@@ -91,7 +98,7 @@
         * [ ] Excel 95 Encryption (Excel 95 and prior)
         * [ ] PowerPoint 95 Encryption (PowerPoint 95 and prior)
         
-        PRs welcome!
+        PRs are welcome!
         
         ## Tests
         
@@ -118,7 +125,7 @@
         * [x] Add the password prompt mode for CLI
         * [ ] Redesign APIs (v5.0.0)
         * [ ] Improve error types (v5.0.0)
-        * [ ] Use `ctypes.Structure`
+        * [ ] Use a kind of `ctypes.Structure`
         * [ ] Support encryption
         
         ## See also
@@ -136,6 +143,7 @@
         
         * herumi/msoffice <https://github.com/herumi/msoffice>
         * DocRecrypt 
<https://blogs.technet.microsoft.com/office_resource_kit/2013/01/23/now-you-can-reset-or-remove-a-password-from-a-word-excel-or-powerpoint-filewith-office-2013/>
+        * Apache POI - the Java API for Microsoft Documents 
<https://poi.apache.org/>
         
         ## Use cases and mentions
         
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/msoffcrypto-tool-4.10.0/msoffcrypto_tool.egg-info/SOURCES.txt 
new/msoffcrypto-tool-4.10.1/msoffcrypto_tool.egg-info/SOURCES.txt
--- old/msoffcrypto-tool-4.10.0/msoffcrypto_tool.egg-info/SOURCES.txt   
2019-04-14 05:39:19.000000000 +0200
+++ new/msoffcrypto-tool-4.10.1/msoffcrypto_tool.egg-info/SOURCES.txt   
2019-08-02 04:39:13.000000000 +0200
@@ -1,4 +1,5 @@
 .noserc
+LICENSE.txt
 MANIFEST.in
 README.md
 setup.py
@@ -27,6 +28,7 @@
 tests/__init__.py
 tests/test_cli.sh
 tests/test_compare_known_output.py
+tests/test_file_handle.py
 tests/inputs/ecma376standard_password.docx
 tests/inputs/example_password.docx
 tests/inputs/example_password.xlsx
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msoffcrypto-tool-4.10.0/tests/test_file_handle.py 
new/msoffcrypto-tool-4.10.1/tests/test_file_handle.py
--- old/msoffcrypto-tool-4.10.0/tests/test_file_handle.py       1970-01-01 
01:00:00.000000000 +0100
+++ new/msoffcrypto-tool-4.10.1/tests/test_file_handle.py       2019-08-02 
04:38:36.000000000 +0200
@@ -0,0 +1,44 @@
+"""Check that given file handles are not closed."""
+
+
+import unittest
+from os.path import join, dirname
+
+from msoffcrypto import OfficeFile
+
+
+#: directory with input
+DATA_DIR = join(dirname(__file__), 'inputs')
+
+
+class FileHandleTest(unittest.TestCase):
+    """See module doc."""
+
+    def test_file_handle_open(self):
+        """Check that file handles are open after is_encrypted()."""
+        for suffix in 'doc', 'ppt', 'xls':
+            path = join(DATA_DIR, 'plain.' + suffix)
+
+            with open(path, 'rb') as file_handle:
+                ofile = OfficeFile(file_handle)
+
+                # do something with ofile
+                self.assertEqual(ofile.is_encrypted(), False)
+
+                # check that file handle is still open
+                self.assertFalse(file_handle.closed)
+
+                # destroy OfficeFile, calls destructor
+                del ofile
+
+                # check that file handle is still open
+                self.assertFalse(file_handle.closed)
+
+            # just for completeness:
+            # check that file handle is now closed
+            self.assertTrue(file_handle.closed)
+
+
+# if someone calls this as script, run unittests
+if __name__ == '__main__':
+    unittest.main()


Reply via email to