# Copyright (c) 2015, JINGROW and Contributors
# License: MIT. See LICENSE
from cryptography.fernet import Fernet

import jingrow
from jingrow.tests.utils import JingrowTestCase
from jingrow.utils.password import check_password, decrypt, encrypt, passlibctx, update_password


class TestPassword(JingrowTestCase):
	def setUp(self):
		jingrow.delete_pg("Email Account", "Test Email Account Password")
		jingrow.delete_pg("Email Account", "Test Email Account Password-new")

	def test_encrypted_password(self):
		pg = self.make_email_account()

		new_password = "test-password"
		pg.password = new_password
		pg.save()

		self.assertEqual(pg.password, "*" * len(new_password))

		password_list = get_password_list(pg)

		auth_password = password_list[0].get("password", "")

		# encrypted
		self.assertTrue(auth_password != new_password)

		# decrypted
		self.assertEqual(pg.get_password(), new_password)

		return pg, new_password

	def make_email_account(self, name="Test Email Account Password"):
		if not jingrow.db.exists("Email Account", name):
			return jingrow.get_pg(
				{
					"pagetype": "Email Account",
					"domain": "example.com",
					"email_account_name": name,
					"append_to": "Email",
					"smtp_server": "test.example.com",
					"pop3_server": "pop.test.example.com",
					"email_id": "test-password@example.com",
					"password": "password",
				}
			).insert()

		else:
			return jingrow.get_pg("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(pagetype="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(jingrow.AuthenticationError, check_password, user, new_password)

	def test_password_on_rename_user(self):
		password = "test-rename-password"

		pg = self.make_email_account()
		pg.password = password
		pg.save()

		old_name = pg.name
		new_name = old_name + "-new"
		jingrow.rename_pg(pg.pagetype, old_name, new_name)

		new_pg = jingrow.get_pg(pg.pagetype, new_name)
		self.assertEqual(new_pg.get_password(), password)
		self.assertTrue(not get_password_list(pg))

		jingrow.rename_pg(pg.pagetype, new_name, old_name)
		self.assertTrue(get_password_list(pg))

	def test_password_on_delete(self):
		pg = self.make_email_account()
		pg.delete()

		self.assertTrue(not get_password_list(pg))

	def test_password_unset(self):
		pg = self.make_email_account()

		pg.password = "asdf"
		pg.save()
		self.assertEqual(pg.get_password(raise_exception=False), "asdf")

		pg.password = ""
		pg.save()
		self.assertEqual(pg.get_password(raise_exception=False), None)

	def test_custom_encryption_key(self):
		text = "Jingrow 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(pg):
	return jingrow.db.sql(
		"""SELECT `password`
			FROM `__Auth`
			WHERE `pagetype`=%s
			AND `name`=%s
			AND `fieldname`='password' LIMIT 1""",
		(pg.get("pagetype"), pg.get("name")),
		as_dict=1,
	)
