I am trying to build a Tkinter GUI password manager that saves the encrypted passwords on a SQLite Database; and it returns the decrypted password back when you search in the database by the website name.
Here is my script and what it returns:
import tkinter as tk
from tkinter import messagebox
import random
import pyperclip
import sqlite3
from werkzeug.security import generate_password_hash, check_password_hash
import base64
import os
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
# DATABASE.
db = sqlite3.connect('user-data.db')
cursor = db.cursor()
# cursor.execute('CREATE TABLE UserData (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, '
# 'website varchar(250) NOT NULL UNIQUE, '
# 'email varchar(250) NOT NULL, '
# 'password varchar(250) NOT NULL)')
# cursor.execute('INSERT INTO UserData VALUES(1, "amazon.co.uk", "my_email#gmail.com", "wieuiwrhfg4")')
# db.commit()
#
# key = Fernet.generate_key()
# f = Fernet(key)
# PASSWORD GENERATOR.
def generate_password():
letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
symbols = ['!', '#', '$', '%', '&', '(', ')', '*', '+']
password_letters = [random.choice(letters) for _ in range(random.randint(8, 10))]
password_symbols = [random.choice(symbols) for _ in range(random.randint(2, 4))]
password_numbers = [random.choice(numbers) for _ in range(random.randint(2, 4))]
password_list = password_letters + password_symbols + password_numbers
random.shuffle(password_list)
password = "".join(password_list)
password_entry.insert(0, string=password)
pyperclip.copy(password)
return password
def password_enc():
salt = os.urandom(16)
kdf = PBKDF2HMAC(algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=480000
)
key = base64.urlsafe_b64encode(kdf.derive(bytes(generate_password(), 'utf-8')))
# key = Fernet.generate_key().decode()
f = Fernet(key)
token = f.encrypt(bytes(generate_password(), 'utf-8'))
return token, f
# SAVE PASSWORD.
def save():
website = website_entry.get() # .get() fetches the current entry text.
password = password_entry.get()
# hash_salted_password = generate_password_hash(password, method='pbkdf2:sha256', salt_length=8)
# encrypted_password = f.encrypt(str.encode(password))
# encrypted_password = str.encode(password)
# key = base64.urlsafe_b64encode(kdf.derive(str.encode(password)))
# f = Fernet(key)
# token = f.encrypt(str.encode(password))
# print(token)
if len(website) == 0 or len(password) == 0:
messagebox.showinfo(title="Oops", message="Please make sure you haven't left any fields empty.")
else:
try:
cursor.execute("INSERT INTO UserData VALUES(?, ?, ?, ?)",
(None, website_entry.get(), email_entry.get(), password_enc()[0]))
db.commit()
finally:
website_entry.delete(0, tk.END) # .delete() from index 0, first char till the END.
password_entry.delete(0, tk.END)
# FIND PASSWORD.
def find_password():
website = website_entry.get()
try:
cursor.execute("SELECT * FROM UserData WHERE website=?", (website,))
result = cursor.fetchall()
print(result)
except FileNotFoundError:
messagebox.showinfo(title="Error", message="No Data File Found.")
else:
if website in result[0]:
email = result[0][1]
hashed_password = result[0][3]
# password = check_password_hash(pwhash=hashed_password, password=generate_password())
decrypted_password = password_enc()[1].decrypt(hashed_password)
# decrypted_password = save().decode()
# decrypted_password = f.decrypt(hashed_password)
messagebox.showinfo(title=website, message=f"Email: {email}\nPassword: {decrypted_password}")
else:
messagebox.showinfo(title="Error", message=f"No details for {website} exists.")
Exception in Tkinter callback
Traceback (most recent call last):
File "/Users//PycharmProjects/pythonProject/Day-24/venv/lib/python3.10/site-packages/cryptography/fernet.py", line 133, in _verify_signature
h.verify(data[-32:])
File "/Users//PycharmProjects/pythonProject/Day-24/venv/lib/python3.10/site-packages/cryptography/hazmat/primitives/hmac.py", line 72, in verify
ctx.verify(signature)
File "/Users//PycharmProjects/pythonProject/Day-24/venv/lib/python3.10/site-packages/cryptography/hazmat/backends/openssl/hmac.py", line 85, in verify
raise InvalidSignature("Signature did not match digest.")
cryptography.exceptions.InvalidSignature: Signature did not match digest.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/tkinter/__init__.py", line 1921, in __call__
return self.func(*args)
File "/Users//PycharmProjects/pythonProject/password-manager/p_main.py", line 112, in find_password
decrypted_password = password_enc()[1].decrypt(password_enc()[0])
File "/Users//PycharmProjects/pythonProject/Day-24/venv/lib/python3.10/site-packages/cryptography/fernet.py", line 90, in decrypt
return self._decrypt_data(data, timestamp, time_info)
File "/Users//PycharmProjects/pythonProject/Day-24/venv/lib/python3.10/site-packages/cryptography/fernet.py", line 151, in _decrypt_data
self._verify_signature(data)
File "/Users//PycharmProjects/pythonProject/Day-24/venv/lib/python3.10/site-packages/cryptography/fernet.py", line 135, in _verify_signature
raise InvalidToken
cryptography.fernet.InvalidToken
The save() function works as intended, it manages to save and hashed password on the database, but when I try to call find_password() I get the following error cryptography.fernet.InvalidToken. The #commented lines of code in my script are the various ways I have tried to solve this problem.
The closest I've got to solving this issue was to be able to encrypt/save and decrypt/find the password on the same run, after re-running the program the encryption key would change, resulting in errors.
Related
I'm expecting arrayTester to look at each array within the array and if both elements are empty strings for them to be removed from the array. Instead I am getting back the original array.
Expected result = [[], ['string', '']]
Actual result = [['',''], ['string', '']]
Any ideas?
let data = [['',''], ['string', '']]
const emptyString = R.equals('')
const removeEmptyElementsFunc = R.reject(R.isEmpty)
const arrayTester = (data) => {
R.forEach(
R.when(
R.all(emptyString),
R.map(removeEmptyElementsFunc)
)(data))
return data
}
arrayTester(data)
If you need to map an array of empty strings to an empty array, the only thing you need to do is to make sure that it is indeed only made of empty strings. (The "transformation" is rather easy: just return an empty array.)
all(isEmpty) will return true if an array is made of empty stuff. always([]) will always return an empty array.
const arrayTester = map(when(all(isEmpty), always([])));
console.log(
arrayTester([['', ''], ['a', 'b', '']]),
arrayTester([['', '', ''], ['a', 'b', '']]),
arrayTester([['', 'x', ''], ['a', 'b', '']])
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const {map, when, all, isEmpty, always} = R;</script>
ok, I've created custom Auth model, by inhereting from AbstractBaseUser. When i create simple user, everything is Ok, but then i try to create superuser something goes wrong.
here is my User and UserManager:
class PatientUserManager(BaseUserManager):
def create_user(self, snils, name=None, surname=None, telephone=None, password=None, is_superuser=None):
'''Создание пользователя со снилсом, именем, фамилией и паролем'''
if not snils:
raise ValueError('Отсутствует Номер СНИЛС')
user = self.model(snils, name, surname, telephone)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, snils, name, surname, telephone, password):
user=self.create_user(snils, name, surname, telephone)
user.is_superuser = True
user.is_admin = True
user.is_staff = True
user.set_password(password)
user.save(using=self._db)
return user
class PatientUser(AbstractBaseUser, PermissionsMixin):
snils = models.CharField('СНИЛС', max_length= 14, unique=True)
email = models.EmailField('email', max_length= 255, blank=True)
name = models.CharField('Имя', max_length= 50, blank=True)
surname = models.CharField('Фамилия', max_length= 80, blank=True)
patronimic = models.CharField('Отчество', max_length= 80, blank=True)
date_joined = models.DateTimeField('Дата Регистрации', auto_now_add=True)
telephone = models.CharField('Номер телефона', max_length= 18, blank=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
USERNAME_FIELD = 'snils'
EMAIL_FIELD = 'email'
REQUIRED_FIELDS = ['name', 'surname', 'telephone']
objects = PatientUserManager()
def get_full_name(self):
'''
Возвращает first_name и last_name с пробелом между ними.
'''
full_name = '%s %s' % (self.name, self.surname)
return full_name.strip()
def get_short_name(self):
'''
Возвращает сокращенное имя пользователя.
'''
return self.name
when i try to
create superuser, i receive error:
ValueError: invalid literal for int() with base 10: '555-555-555 55'
but if enter integer number in 'СНИЛС' field instead of '555-555-555 55', he starts to complain about surname:
СНИЛС: 47
Имя: Vladimir
Фамилия: Suddenok
Номер телефона: 8800
Password:
Password (again):
...
["'Suddenok' value has an invalid format. It must be in YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format."].
well, i showed perseverance and continued to solve problems as they come. changed Surname:
СНИЛС: 47
Имя: Vladimir
Фамилия: 2018-08-14 12:47
Номер телефона: 8800
Password:
Password (again):
...
django.core.exceptions.ValidationError: ["'8800' value must be either True or False."]
changed Telephone:
СНИЛС: 47
Имя: Vladimir
Фамилия: 2018-08-14 12:47
Номер телефона: True
Password:
Password (again):
...
Traceback (most recent call last):
File "/home/maumba/ProjectPython/VE/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
psycopg2.IntegrityError: null value in column "date_joined" violates not- null constraint
DETAIL: Failing row contains (47, !t0cnBjuTplCtE8vJRGsIgsLN5U0pTDXzg22rWFEF, 2018-08-14 12:47:00+00, t, , , , , , null, , t, f, f).
thanks for your attention
How can I make password hash using RFC 2898 like https://learn.microsoft.com/en-us/previous-versions/aspnet/web-frameworks/gg538287(v=vs.111) in nodejs?
My nodejs app are using a table of SQL server which have password field hashed by Crypto.HashPassword of ASP.NET, so I need create same function in nodejs to compare it.
const crypto = require('crypto');
const hexChar = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
const verifyHashedPassword = (password, hashedPwd) => {
let saltString = '';
let storedSubKeyString = '';
const hashedPasswordBytes = new Buffer(hashedPwd, 'base64');
for (var i = 1; i < hashedPasswordBytes.length; i++) {
if (i > 0 && i <= 16) {
saltString += hexChar[(hashedPasswordBytes[i] >> 4) & 0x0f] + hexChar[hashedPasswordBytes[i] & 0x0f];
}
if (i > 0 && i > 16) {
storedSubKeyString += hexChar[(hashedPasswordBytes[i] >> 4) & 0x0f] + hexChar[hashedPasswordBytes[i] & 0x0f];
}
}
const nodeCrypto = crypto.pbkdf2Sync(new Buffer(password), new Buffer(saltString, 'hex'), 1000, 256, 'sha1');
const derivedKeyOctets = nodeCrypto.toString('hex').toUpperCase();
return derivedKeyOctets.indexOf(storedSubKeyString) === 0;
};
I used that for compare plain password with hashed password. It's working well!
The code below is the answer from my question yesterday that has the ff results:
First run
Updated: 0
Inserted: 4
2nd run
Updated: 4
Inserted: 0
After deleting cid '1' and '3':
Updated: 2
Inserted: 2
DECLARE
ins NUMBER := 0;
upd NUMBER := 0;
CURSOR c1 IS
SELECT cid
FROM tbl_cust
WHERE cid
IN ('1','2','3','4');
BEGIN
FOR rec IN c1 LOOP
begin
INSERT INTO tbl2 (id_tbl2, name_tbl2)
VALUES(rec.cid, DECODE(rec.cid, '1', 'A',
'2', 'B',
'3', 'C',
'4', 'D'));
ins := ins + 1;
EXCEPTION WHEN DUP_VAL_ON_INDEX THEN
UPDATE tbl2 set name_tbl2 = DECODE(rec.cid, '1', 'A',
'2', 'B',
'3', 'C',
'4', 'D'));
WHERE cust_cust_code = rec.cid;
upd := upd + 1;
continue;
end;
END LOOP;
dbms_output.put_line('Updated: ' || upd);
dbms_output.put_line('Inserted: ' || ins);
END;
What I wanted now is to revise this code without using nested block. Maybe something like this:
DECLARE
ins NUMBER := 0;
upd NUMBER := 0;
CURSOR c1 IS
SELECT cid
FROM tbl_cust
WHERE cid
IN ('1','2','3','4');
--maybe declare something as 'holder of values' which are ducplicates and cannot be inserted then will be used on a condition or loop to update.
BEGIN
FOR rec IN c1 LOOP
INSERT INTO tbl2 (id_tbl2, name_tbl2)
VALUES(rec.cid, DECODE(rec.cid, '1', 'A',
'2', 'B',
'3', 'C',
'4', 'D'));
ins := ins + 1;
--maybe put some condition here to pass the values that are not insert to the 'holder of values'
END LOOP;
dbms_output.put_line('Updated: ' || upd);
dbms_output.put_line('Inserted: ' || ins);
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
--maybe put a loop here to update values in the 'holder of values'
UPDATE tbl2 set name_tbl2 = DECODE('holder of values'.VALUE, '1', 'A',
'2', 'B',
'3', 'C',
'4', 'D')
WHERE cust_cust_code = 'holder of values'.VALUE;
upd := upd + 1;
dbms_output.put_line('Updated: ' || upd);
dbms_output.put_line('Inserted: ' || ins);
END;
Actually the best way to do this is merge as was suggested by so many others.
(and first to mention this was #APC)
However if you insist on your logic then you should use some sort of collection. (take a look here Working with Collections).
Nevertheless, you cannot put exception handling outside the loop it still should be inside.
Here how this could look like:
DECLARE
ins NUMBER := 0;
upd NUMBER := 0;
CURSOR c1 IS
SELECT cid
FROM tbl_cust
WHERE cid
IN ('1','2','3','4');
--declare something as 'holder of values'
TYPE list_of_ids IS TABLE OF number;
duplicates list_of_ids:= list_of_ids ();
BEGIN
FOR rec IN c1 LOOP
begin
INSERT INTO tbl2 (id_tbl2, name_tbl2)
VALUES(rec.cid, DECODE(rec.cid, '1', 'A',
'2', 'B',
'3', 'C',
'4', 'D'));
ins := ins + sql%rowcount;
EXCEPTION WHEN DUP_VAL_ON_INDEX THEN
duplicates.EXTEND;
duplicates(duplicates.LAST):=rec.cid;
end;
--condition here to pass the values that are not insert to the 'holder of values'
END LOOP;
dbms_output.put_line('Updated: ' || upd);
dbms_output.put_line('Inserted: ' || ins);
--a loop here to update values in the 'holder of values'
FOR l_row IN 1 .. duplicates.COUNT
LOOP
UPDATE tbl2 set name_tbl2 = DECODE(duplicates (l_row), '1', 'A',
'2', 'B',
'3', 'C',
'4', 'D')
WHERE cust_cust_code := duplicates (l_row);
upd := upd + sql%rowcount;
DBMS_OUTPUT.put_line (duplicates (l_row));
END LOOP;
dbms_output.put_line('Updated: ' || upd);
dbms_output.put_line('Inserted: ' || ins);
END;
I want to know how can I get excel cell name like e.g. if I pass RowNumber and ColumnNumber
then function should return me the excel cell name like "A1".
Is it possible?
I am using ExcelWrapper which I found on codeplex.
This is the link from where I got answer
Translate a column index into an Excel Column Name
And answer from that link is as follows
The answer I came up with is to get a little recursive. This code is in VB.Net:
Function ColumnName(ByVal index As Integer) As String
Static chars() As Char = {"A"c, "B"c, "C"c, "D"c, "E"c, "F"c, "G"c, "H"c, "I"c, "J"c, "K"c, "L"c, "M"c, "N"c, "O"c, "P"c, "Q"c, "R"c, "S"c, "T"c, "U"c, "V"c, "W"c, "X"c, "Y"c, "Z"c}
index -= 1 ''//adjust so it matches 0-indexed array rather than 1-indexed column
Dim quotient As Integer = index \ 26 ''//normal / operator rounds. \ does integer division, which truncates
If quotient > 0 Then
ColumnName = ColumnName(quotient) & chars(index Mod 26)
Else
ColumnName = chars(index Mod 26)
End If
End Function
And in C#:
string ColumnName(int index)
{
index -= 1; //adjust so it matches 0-indexed array rather than 1-indexed column
int quotient = index / 26;
if (quotient > 0)
return ColumnName(quotient) + chars[index % 26].ToString();
else
return chars[index % 26].ToString();
}
private char[] chars = new char[] {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
The only downside it that it uses 1-indexed columns rather than 0-indexed.