The license.txt file has been replaced with LICENSE for quite a while now. INAL but it didn't seem accurate to say "hey, checkout license.txt although there's no such file". Apart from this, there were inconsistencies in the headers altogether...this change brings consistency.
123 lines
3.5 KiB
Python
123 lines
3.5 KiB
Python
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
|
# License: MIT. See LICENSE
|
|
import frappe
|
|
import unittest
|
|
from frappe.utils.password import update_password, check_password, passlibctx, encrypt, decrypt
|
|
from cryptography.fernet import Fernet
|
|
class TestPassword(unittest.TestCase):
|
|
def setUp(self):
|
|
frappe.delete_doc('Email Account', 'Test Email Account Password')
|
|
frappe.delete_doc('Email Account', 'Test Email Account Password-new')
|
|
|
|
def test_encrypted_password(self):
|
|
doc = self.make_email_account()
|
|
|
|
new_password = 'test-password'
|
|
doc.password = new_password
|
|
doc.save()
|
|
|
|
self.assertEqual(doc.password, '*' * len(new_password))
|
|
|
|
password_list = get_password_list(doc)
|
|
|
|
auth_password = password_list[0].get('password', '')
|
|
|
|
# encrypted
|
|
self.assertTrue(auth_password != new_password)
|
|
|
|
# decrypted
|
|
self.assertEqual(doc.get_password(), new_password)
|
|
|
|
return doc, new_password
|
|
|
|
def make_email_account(self, name='Test Email Account Password'):
|
|
if not frappe.db.exists('Email Account', name):
|
|
return frappe.get_doc({
|
|
'doctype': 'Email Account',
|
|
'domain': 'example.com',
|
|
'email_account_name': name,
|
|
'append_to': 'Communication',
|
|
'smtp_server': 'test.example.com',
|
|
'pop3_server': 'pop.test.example.com',
|
|
'email_id': 'test-password@example.com',
|
|
'password': 'password',
|
|
}).insert()
|
|
|
|
else:
|
|
return frappe.get_doc('Email Account', name)
|
|
|
|
def test_hashed_password(self, user='test@example.com'):
|
|
old_password = 'Eastern_43A1W'
|
|
new_password = 'Eastern_43A1W-new'
|
|
|
|
update_password(user, new_password)
|
|
|
|
auth = get_password_list(dict(doctype='User', name=user))[0]
|
|
|
|
# is not plain text
|
|
self.assertTrue(auth.password != new_password)
|
|
|
|
# is valid hashing
|
|
self.assertTrue(passlibctx.verify(new_password, auth.password))
|
|
|
|
self.assertTrue(check_password(user, new_password))
|
|
|
|
# revert back to old
|
|
update_password(user, old_password)
|
|
self.assertTrue(check_password(user, old_password))
|
|
|
|
# shouldn't work with old password
|
|
self.assertRaises(frappe.AuthenticationError, check_password, user, new_password)
|
|
|
|
def test_password_on_rename_user(self):
|
|
password = 'test-rename-password'
|
|
|
|
doc = self.make_email_account()
|
|
doc.password = password
|
|
doc.save()
|
|
|
|
old_name = doc.name
|
|
new_name = old_name + '-new'
|
|
frappe.rename_doc(doc.doctype, old_name, new_name)
|
|
|
|
new_doc = frappe.get_doc(doc.doctype, new_name)
|
|
self.assertEqual(new_doc.get_password(), password)
|
|
self.assertTrue(not get_password_list(doc))
|
|
|
|
frappe.rename_doc(doc.doctype, new_name, old_name)
|
|
self.assertTrue(get_password_list(doc))
|
|
|
|
def test_password_on_delete(self):
|
|
doc = self.make_email_account()
|
|
doc.delete()
|
|
|
|
self.assertTrue(not get_password_list(doc))
|
|
|
|
def test_password_unset(self):
|
|
doc = self.make_email_account()
|
|
|
|
doc.password = 'asdf'
|
|
doc.save()
|
|
self.assertEqual(doc.get_password(raise_exception=False), 'asdf')
|
|
|
|
doc.password = ''
|
|
doc.save()
|
|
self.assertEqual(doc.get_password(raise_exception=False), None)
|
|
|
|
def test_custom_encryption_key(self):
|
|
text = 'Frappe Framework'
|
|
custom_encryption_key = Fernet.generate_key().decode()
|
|
|
|
encrypted_text = encrypt(text, encryption_key=custom_encryption_key)
|
|
decrypted_text = decrypt(encrypted_text, encryption_key=custom_encryption_key)
|
|
|
|
self.assertEqual(text, decrypted_text)
|
|
|
|
pass
|
|
|
|
def get_password_list(doc):
|
|
return frappe.db.sql("""SELECT `password`
|
|
FROM `__Auth`
|
|
WHERE `doctype`=%s
|
|
AND `name`=%s
|
|
AND `fieldname`='password' LIMIT 1""", (doc.get('doctype'), doc.get('name')), as_dict=1)
|