Ejemplo n.º 1
0
    def test_update_phrase(self):
        config = opp_config.OppConfig(self.conf_filepath)

        # Add user
        utils.execute("opp-db --config_file %s add-user -uu -pp "
                      "--phrase=123456" % self.conf_filepath)

        old = aescipher.AESCipher("123456")
        new = aescipher.AESCipher("654321")

        # Add category and item using old passphrase
        session = api.get_scoped_session(config)
        category = models.Category(name=old.encrypt("cat1"))
        item = models.Item(name=old.encrypt("item1"),
                           url=old.encrypt("url1"),
                           account=old.encrypt("account1"),
                           username=old.encrypt("username1"),
                           password=old.encrypt("password1"),
                           blob=old.encrypt("blob1"))
        with session.begin():
            user = api.user_get_by_username(session, 'u')
            category.user = user
            item.user = user
            api.category_create(session, [category])
            api.item_create(session, [item])

        # Update passphrase
        utils.execute("opp-db --config_file %s update-phrase -uu -pp "
                      "--old_phrase=123456 --new_phrase=654321" %
                      self.conf_filepath)

        # Check data using new passphrase
        session = api.get_scoped_session(config)
        with session.begin():
            user = api.user_get_by_username(session, 'u')
            category = api.category_getall(session, user)[0]
            self.assertEqual(new.decrypt(category.name), "cat1")
            item = api.item_getall(session, user)[0]
            self.assertEqual(new.decrypt(item.name), "item1")
            self.assertEqual(new.decrypt(item.url), "url1")
            self.assertEqual(new.decrypt(item.account), "account1")
            self.assertEqual(new.decrypt(item.username), "username1")
            self.assertEqual(new.decrypt(item.password), "password1")
            self.assertEqual(new.decrypt(item.blob), "blob1")

        # Cleanup
        utils.execute("opp-db --config_file %s del-user -uu -pp"
                      " --remove_data" % self.conf_filepath)
        self._assert_user_does_not_exist('u')
Ejemplo n.º 2
0
    def _do_post(self, phrase):
        cat_list, error = self._check_payload(expect_list=True)
        if error:
            return error

        cipher = aescipher.AESCipher(phrase)
        categories = []
        for cat in cat_list:
            # Make sure category id is parsed from request
            try:
                cat_id = cat['id']
            except KeyError:
                return self.error("Missing category id in list!")
            if not cat_id:
                return self.error("Empty category id in list!")

            # Make sure category is parsed from request
            try:
                category = cat['name']
            except KeyError:
                return self.error("Missing category name in list!")
            if not category:
                return self.error("Empty category name in list!")

            try:
                blob = cipher.encrypt(category)
                categories.append(models.Category(id=cat_id, name=blob))
            except TypeError:
                return self.error("Invalid category name in list!")

        try:
            api.category_update(categories, session=self.session)
            return {'result': "success"}
        except Exception:
            return self.error("Unable to update categories in the database!")
Ejemplo n.º 3
0
    def respond(self, require_phrase=True):
        """
            This is the main function called by the request processing logic
            to generate a response for a particular endpoint call.
        """
        # Validate passphrase if required
        if require_phrase:
            try:
                phrase = self.request.headers['x-opp-phrase']
            except KeyError:
                raise OppError("Passphrase header missing!")

            cipher = aescipher.AESCipher(phrase)
            try:
                if cipher.decrypt(self.user.phrase_check) != "OK":
                    raise OppError("Incorrect passphrase supplied!")
            except UnicodeDecodeError:
                raise OppError("Incorrect passphrase supplied!")
        else:
            phrase = None

        with self.session.begin():
            if self.request.method == "GET":
                response = self._do_get(phrase)
            elif self.request.method == "PUT":
                response = self._do_put(phrase)
            elif self.request.method == "POST":
                response = self._do_post(phrase)
            elif self.request.method == "DELETE":
                response = self._do_delete()
            else:
                raise OppError("Method not supported!")

        return response
Ejemplo n.º 4
0
    def _do_get(self, phrase):
        """
        Fetch all categories and items data for a particular user.

        :param phrase: decryption passphrase

        :returns: success result along with categories and items arrays
        """
        cat_array = []
        item_array = []
        cipher = aescipher.AESCipher(phrase)
        try:
            categories = api.category_getall(self.session, self.user)
            for category in categories:
                cat_array.append(category.extract(cipher, with_items=False))

            items = api.item_getall(self.session, self.user)
            for item in items:
                item_array.append(item.extract(cipher, with_category=False))
        except UnicodeDecodeError:
            raise bh.OppError("Unable to decrypt data!")
        except Exception:
            raise bh.OppError("Unable to fetch from the database!")

        return {
            'result': 'success',
            'categories': cat_array,
            'items': item_array
        }
Ejemplo n.º 5
0
    def _do_put(self, phrase):
        """
        Create a list of items, given an array of item parameters, with
        option to specify auto-generation of common or unique passwords
        for each item.

        :param phrase: decryption passphrase

        :returns: success result along with array of newly created items
        """
        payload_dicts = [{
            'name': "items",
            'is_list': True,
            'required': True
        }, {
            'name': "auto_pass",
            'is_list': False,
            'required': False
        }, {
            'name': "unique",
            'is_list': False,
            'required': False
        }, {
            'name': "genopts",
            'is_list': False,
            'required': False
        }]
        item_list, auto_pass, unique, genopts = self._check_payload(
            payload_dicts)

        if auto_pass is True:
            # Retrieve words dictionary
            words = self._get_words(genopts)

            # Generate common password for all items
            if unique is not True:
                common_password = self._gen_pwd(words, genopts)

        cipher = aescipher.AESCipher(phrase)
        items = []
        for row in item_list:
            if auto_pass is True:
                if unique is True:
                    password = self._gen_pwd(words, genopts)
                else:
                    password = common_password
            else:
                password = None

            items.append(self.make_item(row, cipher, password))

        try:
            items = api.item_create(self.session, items)
            response = []
            for item in items:
                response.append(item.extract(cipher))
            return {'result': 'success', 'items': response}
        except Exception:
            raise bh.OppError("Unable to add new items to the database!")
Ejemplo n.º 6
0
    def _do_get(self, phrase):
        response = []
        cipher = aescipher.AESCipher(phrase)
        categories = api.category_getall(session=self.session)
        for category in categories:
            response.append(category.extract(cipher))

        return {'result': "success", 'categories': response}
Ejemplo n.º 7
0
    def _do_get(self, phrase):
        response = []
        cipher = aescipher.AESCipher(phrase)
        items = api.item_getall(session=self.session)
        for item in items:
            response.append(item.extract(cipher))

        return {'result': 'success', 'items': response}
Ejemplo n.º 8
0
    def _do_post(self, phrase):
        item_list, error = self._check_payload(expect_list=True)
        if error:
            return error

        cipher = aescipher.AESCipher(phrase)
        items = []
        for row in item_list:
            # Make sure item id is parsed from request
            try:
                item_id = row['id']
            except KeyError:
                return self.error("Missing item id in list!")
            if not item_id:
                return self.error("Empty item id in list!")

            # Extract various item data into a list
            name = self._parse_or_set_empty(row, 'name')
            url = self._parse_or_set_empty(row, 'url')
            account = self._parse_or_set_empty(row, 'account')
            username = self._parse_or_set_empty(row, 'username')
            password = self._parse_or_set_empty(row, 'password')
            blob = self._parse_or_set_empty(row, 'blob')
            category_id = self._parse_or_set_empty(row, 'category_id')
            full_row = [name, url, account, username, password, blob]

            try:
                # TODO: (alex) deteremine if ok to insert completely empty item
                encoded_row = [
                    base64.b64encode(x.encode()).decode() for x in full_row
                ]
                encrypted_blob = cipher.encrypt("~".join(encoded_row))
                [name, url, account, username, password,
                 blob] = self._chunk6(encrypted_blob.decode())
                items.append(
                    models.Item(id=item_id,
                                name=name,
                                url=url,
                                account=account,
                                username=username,
                                password=password,
                                blob=blob,
                                category_id=category_id))
            except (AttributeError, TypeError):
                return self.error("Invalid item data in list!")

        try:
            api.item_update(items, session=self.session)
            return {'result': "success"}
        except Exception:
            return self.error("Unable to update items in the database!")
Ejemplo n.º 9
0
def update_phrase(config, u, p, old_phrase, new_phrase):
    if len(new_phrase) < 6:
        sys.exit("Error: passphrase must be at least 6 characters long!")
    try:
        old_cipher = aescipher.AESCipher(old_phrase)
        new_cipher = aescipher.AESCipher(new_phrase)
        s = api.get_scoped_session(config.conf)
        with s.begin():
            user = api.user_get_by_username(s, u)
            if not user:
                sys.exit("Error: user does not exist!")
            if not utils.checkpw(p, user.password):
                sys.exit("Error: incorrect password!")
            try:
                if old_cipher.decrypt(user.phrase_check) != "OK":
                    sys.exit("Error: incorrect old passphrase supplied!")
            except UnicodeDecodeError:
                sys.exit("Error: incorrect old passphrase supplied!")

            printv(config, "Updating user information")
            user.phrase_check = new_cipher.encrypt("OK")
            api.user_update(s, user)
            printv(config, "Updating user's categories")
            categories = api.category_getall(s, user)
            for category in categories:
                category.recrypt(old_cipher, new_cipher)
            api.category_update(s, categories)
            printv(config, "Updating user's items")
            items = api.item_getall(s, user)
            for item in items:
                item.recrypt(old_cipher, new_cipher)
            api.item_update(s, items)
            print("All of user's data has been successfuly "
                  "re-encrypted with the new passphrase.")
    except Exception as e:
        sys.exit("Error: %s" % str(e))
Ejemplo n.º 10
0
    def _do_put(self, phrase):
        """
        Create a new user.

        :param phrase: not used

        :returns: success result
        """
        payload_dicts = [{
            'name': "username",
            'is_list': False,
            'required': True
        }, {
            'name': "password",
            'is_list': False,
            'required': True
        }, {
            'name': "phrase",
            'is_list': False
        }]
        payload_objects = self._check_payload(payload_dicts)

        u = self._validate(payload_objects[0], 'username')
        p = self._validate(payload_objects[1], 'password')
        phrase = self._validate(payload_objects[2], 'phrase')
        if len(phrase) < 6:
            raise bh.OppError("Passphrase must be at least 6 characters long!")

        try:
            cipher = aescipher.AESCipher(phrase)
            ok = cipher.encrypt("OK")
            user = api.user_get_by_username(self.session, u)
            if user:
                raise bh.OppError("User already exists!")
            hashed = utils.hashpw(p)
            user = models.User(username=u, password=hashed, phrase_check=ok)
            api.user_create(self.session, user)
            user = api.user_get_by_username(self.session, u)
            if user:
                return {'result': 'success'}
            else:
                raise bh.OppError("Unable to add user: '******'" % u)
        except bh.OppError as e:
            raise bh.OppError(e.error, e.desc, e.status, e.headers)
        except Exception:
            raise bh.OppError("Unable to add user: '******'" % u)
Ejemplo n.º 11
0
    def _do_get(self, phrase):
        """
        Fetch all user's items.

        :param phrase: decryption passphrase

        :returns: success result along with decrypted items array
        """
        response = []
        cipher = aescipher.AESCipher(phrase)
        try:
            items = api.item_getall(self.session, self.user)
            for item in items:
                response.append(item.extract(cipher))
        except UnicodeDecodeError:
            raise bh.OppError("Unable to decrypt data!")
        except Exception:
            raise bh.OppError("Unable to fetch items from the database!")
        return {'result': 'success', 'items': response}
Ejemplo n.º 12
0
def add_user(config, u, p, phrase):
    if len(phrase) < 6:
        sys.exit("Error: passphrase must be at least 6 characters long!")
    try:
        cipher = aescipher.AESCipher(phrase)
        ok = cipher.encrypt("OK")
        s = api.get_scoped_session(config.conf)
        with s.begin():
            user = api.user_get_by_username(s, u)
            if user:
                sys.exit("Error: user already exists!")
            hashed = utils.hashpw(p)
            user = models.User(username=u, password=hashed, phrase_check=ok)
            api.user_create(s, user)
            user = api.user_get_by_username(s, u)
            if user:
                print("Successfully added new user: '******'" % u)
            else:
                print("Error: unable to add user: '******'" % u)
    except Exception as e:
        sys.exit("Error: %s" % str(e))
Ejemplo n.º 13
0
    def _do_put(self, phrase):
        cat_list, error = self._check_payload(expect_list=True)
        if error:
            return error

        cipher = aescipher.AESCipher(phrase)
        categories = []
        for cat in cat_list:
            # Check for empty category name
            if not cat:
                return self.error("Empty category name in list!")
            try:
                blob = cipher.encrypt(cat)
                categories.append(models.Category(name=blob))
            except TypeError:
                return self.error("Invalid category name in list!")

        try:
            api.category_create(categories, session=self.session)
            return {'result': "success"}
        except Exception:
            return self.error("Unable to add new categories to the database!")
Ejemplo n.º 14
0
 def test_encrypt_decrypt_unicode_data(self):
     cipher = aescipher.AESCipher("secret passphrase")
     encrypted = cipher.encrypt(u"Привет Мир!")
     decrypted = cipher.decrypt(encrypted)
     self.assertEqual(decrypted, u"Привет Мир!")
Ejemplo n.º 15
0
 def test_encrypt_decrypt(self):
     cipher = aescipher.AESCipher("secret passphrase")
     encrypted = cipher.encrypt("My Secret Message")
     decrypted = cipher.decrypt(encrypted)
     self.assertEqual(decrypted, "My Secret Message")
Ejemplo n.º 16
0
    def _do_post(self, phrase):
        """
        Update a list of items. Similar options to create except that
        item id is required for each item in the list.

        :param phrase: decryption passphrase

        :returns: success result
        """
        payload_dicts = [{
            'name': "items",
            'is_list': True,
            'required': True
        }, {
            'name': "auto_pass",
            'is_list': False,
            'required': False
        }, {
            'name': "unique",
            'is_list': False,
            'required': False
        }, {
            'name': "genopts",
            'is_list': False,
            'required': False
        }]
        item_list, auto_pass, unique, genopts = self._check_payload(
            payload_dicts)

        if auto_pass is True:
            # Retrieve words dictionary
            words = self._get_words(genopts)

            # Generate common password for all items if needed
            if unique is not True:
                common_password = self._gen_pwd(words, genopts)

        cipher = aescipher.AESCipher(phrase)
        items = []
        for row in item_list:
            # Make sure item id is parsed from request
            try:
                item_id = row['id']
            except KeyError:
                raise bh.OppError("Missing item id in list!")
            if not item_id:
                raise bh.OppError("Empty item id in list!")

            if auto_pass is True:
                if unique is True:
                    password = self._gen_pwd(words, genopts)
                else:
                    password = common_password
            else:
                password = None

            items.append(self.make_item(row, cipher, password, item_id))

        try:
            api.item_update(self.session, items)
            response = []
            for item in items:
                response.append(item.extract(cipher))
            return {'result': 'success', 'items': response}
        except Exception:
            raise bh.OppError("Unable to update items in the database!")