From 0043ce9937485ce975271365b2094f783db2e9bf Mon Sep 17 00:00:00 2001
From: František Zatloukal <fzatlouk@redhat.com>
Date: Nov 28 2018 09:27:38 +0000
Subject: [PATCH 1/3] Merge branch 'master' into feature/python3


---

diff --git a/vault/serializers/api_v1.py b/vault/serializers/api_v1.py
index a01dbaf..554f646 100644
--- a/vault/serializers/api_v1.py
+++ b/vault/serializers/api_v1.py
@@ -31,8 +31,6 @@ class Serializer(BaseSerializer):
             active=o.active,
             value=o.value,
         )
-        rv = {}
-        rv[o.name] = o.value
 
         return {key: self.serialize(value) for key, value in rv.iteritems()}
 
@@ -43,7 +41,7 @@ class Serializer(BaseSerializer):
             active=o.active,
             description=o.description,
 #            roles=o.roles,
-            secrets=[s for s in o.secrets if s.active],
+            secrets=dict([(s.name, s.value) for s in o.secrets if s.active]),
         )
 
         return {key: self.serialize(value) for key, value in rv.iteritems()}

From 6abd7551ce396a6b7096d4593f447374c84df9a9 Mon Sep 17 00:00:00 2001
From: František Zatloukal <fzatlouk@redhat.com>
Date: Nov 28 2018 12:02:58 +0000
Subject: [PATCH 2/3] Fix Python 3 issues in the code


Use Python 3 on Fedora

---

diff --git a/init_db.sh b/init_db.sh
old mode 100644
new mode 100755
index 516be00..be8e645
--- a/init_db.sh
+++ b/init_db.sh
@@ -2,7 +2,7 @@
 # this is a simple script to aid in the setup of a new db for F18
 
 # init db
-python run_cli.py -d init_db
+python3 run_cli.py -d init_db
 
 # insert mock data
-python run_cli.py -d  mock_data
+python3 run_cli.py -d  mock_data
diff --git a/run_cli.py b/run_cli.py
index 3b49441..185c714 100644
--- a/run_cli.py
+++ b/run_cli.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 #
 # Copyright 2014, Red Hat, Inc
 #
diff --git a/runapp.py b/runapp.py
index 6510268..b26b66c 100644
--- a/runapp.py
+++ b/runapp.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 #
 # runapp.py - script to facilitate running the vault app from the CLI
 #
diff --git a/setup.py b/setup.py
index 9ed77a8..aaaa0e5 100644
--- a/setup.py
+++ b/setup.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 from setuptools import setup
 import codecs
diff --git a/vault.spec b/vault.spec
index 946381d..1d3908e 100644
--- a/vault.spec
+++ b/vault.spec
@@ -9,27 +9,22 @@ Source0:        https://releases.pagure.org/%{name}/%{name}-%{version}.tar.gz
 
 BuildArch:      noarch
 
-Requires:       python2-alembic
-Requires:       python2-flask
-Requires:       python2-flask-httpauth
-%if 0%{?fedora} <= 27
-Requires:       python-flask-login
-Requires:	python-flask-wtf
-%else
-Requires:       python2-flask-login
-Requires:	python2-flask-wtf
-%endif
-Requires:       python2-flask-oidc
-Requires:       python2-flask-restful
-Requires:       python2-flask-sqlalchemy
-Requires:       python2-crypto
-
-BuildRequires:  python2-devel
-BuildRequires:  python2-setuptools
+Requires:       python3-alembic
+Requires:       python3-flask
+Requires:       python3-flask-httpauth
+Requires:       python3-flask-login
+Requires:       python3-flask-wtf
+Requires:       python3-flask-oidc
+Requires:       python3-flask-restful
+Requires:       python3-flask-sqlalchemy
+Requires:       python3-crypto
+
+BuildRequires:  python3-devel
+BuildRequires:  python3-setuptools
 
 
 %description
-Vault stores and controls encrypted data like passwords, 
+Vault stores and controls encrypted data like passwords,
 API keys or other secrets.
 Implements bucket-based access control, and secret versioning.
 %prep
@@ -41,10 +36,10 @@ Implements bucket-based access control, and secret versioning.
 rm -f %{buildroot}%{_sysconfdir}/vault/*.py{c,o}
 
 %build
-%py2_build
+%py3_build
 
 %install
-%py2_install
+%py3_install
 
 # apache and wsgi settings
 install -d %{buildroot}%{_datadir}/vault/conf
@@ -62,8 +57,8 @@ install -p -m 0644 conf/settings.py.example %{buildroot}%{_sysconfdir}/vault/set
 %files
 %doc README.md
 %license LICENSE
-%{python2_sitelib}/vault
-%{python2_sitelib}/*.egg-info
+%{python3_sitelib}/vault
+%{python3_sitelib}/*.egg-info
 
 %{_bindir}/vault
 %dir %{_sysconfdir}/vault
diff --git a/vault/controllers/admin.py b/vault/controllers/admin.py
index b85ffe9..da0f6c5 100644
--- a/vault/controllers/admin.py
+++ b/vault/controllers/admin.py
@@ -18,7 +18,7 @@
 #    Josef Skladanka <jskladan@redhat.com>
 
 from flask import Blueprint, render_template, abort
-from flask.ext.login import login_required, current_user
+from flask_login import login_required, current_user
 
 
 admin = Blueprint('admin', __name__)
diff --git a/vault/controllers/login_page.py b/vault/controllers/login_page.py
index 15d3176..261e428 100644
--- a/vault/controllers/login_page.py
+++ b/vault/controllers/login_page.py
@@ -19,12 +19,12 @@
 
 import flask
 from flask import Blueprint, render_template, redirect, flash, url_for, request
-from flask.ext.wtf import Form
+from flask_wtf import Form
 from wtforms import TextField, PasswordField, HiddenField
 from wtforms.validators import Required
 import flask_login
-from flask.ext.login import login_user, logout_user
-from flask.ext.login import current_user, AnonymousUserMixin
+from flask_login import login_user, logout_user
+from flask_login import current_user, AnonymousUserMixin
 
 import munch
 
diff --git a/vault/controllers/main.py b/vault/controllers/main.py
index 18d9d41..8eadd78 100644
--- a/vault/controllers/main.py
+++ b/vault/controllers/main.py
@@ -23,8 +23,8 @@ from flask import Blueprint, render_template, request, jsonify, redirect, flash,
 import werkzeug.exceptions
 from sqlalchemy.orm import exc as orm_exc
 
-from flask.ext.restful import reqparse
-from flask.ext.login import login_user, logout_user, login_required, current_user
+from flask_restful import reqparse
+from flask_login import login_user, logout_user, login_required, current_user
 from werkzeug.exceptions import HTTPException
 from werkzeug.exceptions import BadRequest as JSONBadRequest
 
@@ -146,7 +146,7 @@ def show_buckets():
 
 
 
-from flask.ext.wtf import Form
+from flask_wtf import Form
 from wtforms import Label, TextField, SelectField, TextAreaField, HiddenField, FieldList, FormField
 from wtforms.validators import Required
 
diff --git a/vault/models/secrets.py b/vault/models/secrets.py
index 717f52e..0339b2b 100644
--- a/vault/models/secrets.py
+++ b/vault/models/secrets.py
@@ -30,23 +30,28 @@ from vault import db, app
 from vault.serializers import DBSerialize
 from .user import User
 
-pad = lambda s: s + (AES.block_size - len(s) % AES.block_size) * chr(AES.block_size - len(s) % AES.block_size)
+pad = lambda s: s + (AES.block_size - len(s) % AES.block_size) * chr(AES.block_size - len(s) % AES.block_size).encode("utf-8")
 unpad = lambda s: s[:-ord(s[len(s)-1:])]
 
 MASTERKEY = base64.b64decode(app.config['MASTERKEY'])
 
 def encrypt(value, key):
+    if isinstance(value, str):
+        value = value.encode("utf-8")
     iv = Random.new().read(AES.block_size)
     cipher = AES.new(key, AES.MODE_CBC, iv)
     ciphertext = (iv + cipher.encrypt(pad(value)))
     return base64.b64encode(ciphertext)
 
 
-def decrypt(ciphertext, key):
+def decrypt(ciphertext, key, output_bytes=False):
     ciphertext = base64.b64decode(ciphertext)
     dec_iv = ciphertext[:AES.block_size]
     dec_cipher = AES.new(key, AES.MODE_CBC, dec_iv)
-    return unpad(dec_cipher.decrypt(ciphertext[16:]))
+    if output_bytes:
+        return unpad(dec_cipher.decrypt(ciphertext[16:]))
+    else:
+        return unpad(dec_cipher.decrypt(ciphertext[16:])).decode("utf-8")
 
 
 class Secret(db.Model, DBSerialize):
@@ -102,7 +107,7 @@ class Bucket(db.Model, DBSerialize):
     @property
     def access_key(self):
         if not hasattr(self, '_access_key'):
-            self._access_key = decrypt(self.ciphertext, MASTERKEY)
+            self._access_key = decrypt(self.ciphertext, MASTERKEY, output_bytes=True)
         return self._access_key
 
     @property
diff --git a/vault/models/user.py b/vault/models/user.py
index ca0b75d..d14b931 100644
--- a/vault/models/user.py
+++ b/vault/models/user.py
@@ -18,7 +18,7 @@
 #    Josef Skladanka <jskladan@redhat.com>
 
 from vault import db
-from flask.ext.login import UserMixin
+from flask_login import UserMixin
 from werkzeug.security import generate_password_hash, check_password_hash
 
 USERNAME_OIDC_GROUP_PREFIX = u"FAS GROUP: "
diff --git a/vault/serializers/__init__.py b/vault/serializers/__init__.py
index 6482ea3..c10a91e 100644
--- a/vault/serializers/__init__.py
+++ b/vault/serializers/__init__.py
@@ -19,6 +19,10 @@
 
 from datetime import date, datetime
 
+try:
+    basestring
+except NameError:
+    basestring = (str, bytes)
 
 class DBSerialize(object):
     pass
@@ -38,10 +42,14 @@ class BaseSerializer(object):
 
         if isinstance(value, dict):
             ret = {}
-            for k, v in value.iteritems():
+            for k, v in value.items():
                 ret[k] = self.serialize(v, **kwargs)
             return ret
 
+        #in py3 string-like types have __iter__ causing endless loops
+        if isinstance(value, basestring):
+            return value
+
         # convert iterables to list of serialized stuff
         if hasattr(value, '__iter__'):
             ret = []
diff --git a/vault/serializers/api_v1.py b/vault/serializers/api_v1.py
index 554f646..b380580 100644
--- a/vault/serializers/api_v1.py
+++ b/vault/serializers/api_v1.py
@@ -32,7 +32,7 @@ class Serializer(BaseSerializer):
             value=o.value,
         )
 
-        return {key: self.serialize(value) for key, value in rv.iteritems()}
+        return {key: self.serialize(value) for key, value in rv.items()}
 
     def _serialize_Bucket(self, o, **kwargs):
         rv = dict(
@@ -44,7 +44,7 @@ class Serializer(BaseSerializer):
             secrets=dict([(s.name, s.value) for s in o.secrets if s.active]),
         )
 
-        return {key: self.serialize(value) for key, value in rv.iteritems()}
+        return {key: self.serialize(value) for key, value in rv.items()}
 
 
     def _serialize_BucketRoles(self, o, **kwargs):
@@ -53,4 +53,4 @@ class Serializer(BaseSerializer):
             role=o.role,
         )
 
-        return {key: self.serialize(value) for key, value in rv.iteritems()}
+        return {key: self.serialize(value) for key, value in rv.items()}

From e0802fbf2ad03edcd521c84483dbe35d1199c4df Mon Sep 17 00:00:00 2001
From: František Zatloukal <fzatlouk@redhat.com>
Date: Jan 22 2019 14:32:44 +0000
Subject: [PATCH 3/3] Add missing dep: python3-munch


---

diff --git a/vault.spec b/vault.spec
index 1d3908e..1619bb3 100644
--- a/vault.spec
+++ b/vault.spec
@@ -18,6 +18,7 @@ Requires:       python3-flask-oidc
 Requires:       python3-flask-restful
 Requires:       python3-flask-sqlalchemy
 Requires:       python3-crypto
+Requires:       python3-munch
 
 BuildRequires:  python3-devel
 BuildRequires:  python3-setuptools

