Repository: privacyidea/privacyidea

Issue:
Python 3 support for tools
Currently not all tools work with python 3. We should fix them and add some basic testing:
- [x] ``privacyidea-standalone``
- [x] ``privacyidea-diag``
- [x] ``privacyidea-migrate-linotp.py``
- [ ] ~~`privacyidea-decrypt-safeword.py`~~
- [ ] ~~`privacyidea-find-oath.py`~~
- [x] `privacyidea-queue-huey`


Discussion:
Very good idea and very important to keep track. (However, there are some more important tools like 

* [x] privacyidea-diag
* [x] privacyidea-token-janitor

as these are used in bigger installations more often - or do these already work?
The privacyidea-token-janitor works well.

@plettich today I realized, that the migrate-linotp script does not work, if you do a reencrypt.
It happens here:
https://github.com/privacyidea/privacyidea/blob/master/tools/privacyidea-migrate-linotp.py#L142

Probably the output of aes_cbc_decrypt is not allowed for unhexlify.


Resolving patch:
diff --git a/tools/privacyidea-migrate-linotp.py b/tools/privacyidea-migrate-linotp.py
--- a/tools/privacyidea-migrate-linotp.py
+++ b/tools/privacyidea-migrate-linotp.py
@@ -133,15 +133,12 @@ def __init__(self, config_file):
 def reencrypt(enc_data, iv, old_key, new_key):
     # decrypt LinOTP
     iv = binascii.unhexlify(iv)
-    input = binascii.unhexlify(enc_data)
-    output = aes_cbc_decrypt(old_key, iv, input)
-    eof = len(output) - 1
-    if eof == -1:
+    input_data = binascii.unhexlify(enc_data)
+    output = aes_cbc_decrypt(old_key, iv, input_data)
+    if not output:
         raise Exception('invalid encoded secret!')
     # unpad
-    while output[eof] == '\0':
-        eof -= 1
-    output = output[0:eof-1]
+    output = output.rstrip(b'\0')
     data = binascii.unhexlify(output)
 
     # encrypt anew
@@ -526,16 +523,16 @@ def insert_chunks(conn, table, values, chunk_size=100000, record_name="records")
 def usage():
     print("""
 privacyidea-migrate-linotp.py --generate-example-config [--config <config file>]
-    
+
     --generate-example-config, -g   Output an example config file. 
                                     This is a JSON file, that needs to be passed
                                     to this command.
-                                    
+
     --config, -c <file>             The config file, that contains the complete
                                     configuration.
-                                    
-{0!s}                                    
-    """.format(__doc__))
+
+{0!s}
+""".format(__doc__))
 
 
 def read_enckey(encfile):


Test patch:
diff --git a/tests/test_scripts.py b/tests/test_scripts.py
--- a/tests/test_scripts.py
+++ b/tests/test_scripts.py
@@ -12,6 +12,7 @@
 SCRIPTS = [
     'creategoogleauthenticator-file',
     'getgooglecodes',
+    'privacyidea-convert-base32.py',
     'privacyidea-create-ad-users',
     'privacyidea-create-certificate',
     'privacyidea-create-pwidresolver-user',
@@ -37,12 +38,6 @@
     '../pi-manage'
 ]
 
-SCRIPTS_FAIL = [
-    'privacyidea-convert-base32.py',
-    'privacyidea-decrypt-safeword.py',
-    'privacyidea-find-oath'
-]
-
 
 @unittest.skipIf(sys.version_info < (3, 0),
                  'Scripts can currently only be tested with Python 3')
@@ -55,12 +50,3 @@ def test_01_loading_scripts(self):
                 spec = spec_from_loader(loader.name, loader)
                 mod = module_from_spec(spec)
                 loader.exec_module(mod)
-
-    @unittest.expectedFailure
-    def test_02_failing_scripts(self):
-        for script in SCRIPTS_FAIL:
-            with self.subTest(script=script):
-                loader = SourceFileLoader(script, os.path.join('tools', script))
-                spec = spec_from_loader(loader.name, loader)
-                mod = module_from_spec(spec)
-                loader.exec_module(mod)