Skip to content

Commit 5a6c57a

Browse files
committed
Added master passwords check
1 parent c392702 commit 5a6c57a

File tree

2 files changed

+192
-92
lines changed

2 files changed

+192
-92
lines changed

python_password/PyPassword.kv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ Screen:
6262
name: 'passwords'
6363
on_enter:
6464
app.update_passwords()
65+
app.check_alpha()
6566

6667
BoxLayout:
6768
orientation: 'horizontal'

python_password/PyPassword.py

Lines changed: 191 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ def build(self):
100100

101101
def on_start(self):
102102
self.update_passwords()
103+
self.check_alpha()
103104

104105
# ================================
105106
# Context menus and dialogs
@@ -165,31 +166,107 @@ def wip_info(self):
165166
).alert()
166167
info_dialog.open()
167168

169+
# ================================
170+
# Checks
171+
# ================================
172+
173+
def check_alpha(self):
174+
"""Checks if beta password is set. If so, checks if alpha password is set.
175+
That's because beta password is required to save alpha password."""
176+
Logger.debug('Called: check_alpha')
177+
ok_beta = self.check_beta()
178+
if ok_beta is True:
179+
try:
180+
open(appdata(Files.alpha_key))
181+
except FileNotFoundError:
182+
alert_dialog = MDDialog(
183+
title='Missing alpha password',
184+
text='I\'ve noticed, that you have not set alpha password. It\'s needed for safe password storing.'
185+
' Do you want to provide it by yourself, or let program to randomize it?',
186+
auto_dismiss=False,
187+
buttons=[
188+
MDFillRoundFlatIconButton(
189+
text='Set password',
190+
icon='account-key-outline',
191+
on_release=lambda x: self.dismiss_and_back(alert_dialog, 'settings')
192+
),
193+
MDRoundFlatIconButton(
194+
text='Randomize',
195+
icon='dice-multiple-outline',
196+
on_release=lambda x: [
197+
self.change_alpha(rand_password()),
198+
alert_dialog.dismiss()
199+
]
200+
)
201+
]
202+
)
203+
alert_dialog.open()
204+
return False
205+
else:
206+
return True
207+
208+
def check_beta(self):
209+
"""Checks if beta password is set."""
210+
Logger.debug('Called: check_beta')
211+
try:
212+
open(appdata(Files.beta_key))
213+
except FileNotFoundError:
214+
alert_dialog = MDDialog(
215+
title='Missing beta password',
216+
text='I\'ve noticed, that you have not set beta password. It\'s needed for safe password storing.'
217+
' Do you want to provide it by yourself, or let program to randomize it?',
218+
auto_dismiss=False,
219+
buttons=[
220+
MDFillRoundFlatIconButton(
221+
text='Set password',
222+
icon='account-key-outline',
223+
on_release=lambda x: self.dismiss_and_back(alert_dialog, 'settings')
224+
),
225+
MDRoundFlatIconButton(
226+
text='Randomize',
227+
icon='dice-multiple-outline',
228+
on_release=lambda x: [
229+
self.reset_beta(),
230+
alert_dialog.dismiss()
231+
]
232+
)
233+
]
234+
)
235+
alert_dialog.open()
236+
return False
237+
else:
238+
return True
239+
168240
# ================================
169241
# Passwords managing
170242
# ================================
171243

172244
def add_password(self):
173245
"""Adding passwords to database. Invoked by button in ``passwords`` menu."""
174246
Logger.trace('Called: add_password')
175-
alias_box = self.root.ids.password_alias
176-
value_box = self.root.ids.password_value
247+
try:
248+
open(appdata(Files.alpha_key))
249+
except FileNotFoundError:
250+
self.check_alpha()
251+
else:
252+
alias_box = self.root.ids.password_alias
253+
value_box = self.root.ids.password_value
177254

178-
self.validate_input(alias_box, 3)
179-
self.validate_input(value_box, 6)
255+
self.validate_input(alias_box, 3)
256+
self.validate_input(value_box, 6)
180257

181-
ok_alias = self.validate_input(alias_box, 3)
182-
ok_value = self.validate_input(value_box, 6)
258+
ok_alias = self.validate_input(alias_box, 3)
259+
ok_value = self.validate_input(value_box, 6)
183260

184-
password_alias = alias_box.text.capitalize()
185-
password_value = value_box.text
261+
password_alias = alias_box.text.capitalize()
262+
password_value = value_box.text
186263

187-
if ok_alias is True and ok_value is True:
188-
try:
189-
query(
190-
'INSERT INTO passwords (`name`, `password`) VALUES (?, ?);',
191-
[password_alias, encrypt(password_value)]
192-
)
264+
if ok_alias is True and ok_value is True:
265+
try:
266+
query(
267+
'INSERT INTO passwords (`name`, `password`) VALUES (?, ?);',
268+
[password_alias, encrypt(password_value)]
269+
)
193270

194271
except sqlite3.IntegrityError:
195272
Logger.info(f'Passwords: Tried to save "{password_alias}" but already exists.')
@@ -206,22 +283,15 @@ def add_password(self):
206283
).alert()
207284

208285
else:
209-
Logger.info(f'Passwords: Password "{password_alias}" saved.')
210286
result_dialog = CustomDialog(
211287
title='Whoops!',
212288
text='The entered values are too short or invalid.'
213289
).alert()
214290

215-
else:
216-
result_dialog = CustomDialog(
217-
title='Whoops!',
218-
text='The entered data is invalid.'
219-
).alert()
220-
221-
result_dialog.open()
222-
alias_box.text = ''
223-
value_box.text = ''
224-
self.update_passwords()
291+
result_dialog.open()
292+
alias_box.text = ''
293+
value_box.text = ''
294+
self.update_passwords()
225295

226296
def copy_password(self, password=None):
227297
"""
@@ -279,45 +349,56 @@ def del_password(self, password=None):
279349

280350
self.root.ids.del_password_alias.text = ''
281351

282-
to_del = query(
283-
'SELECT `password` FROM `passwords` WHERE `name` LIKE ?;',
284-
[password]
285-
)
286-
if to_del is not None:
287-
to_del = to_del[0][0]
288-
if type(to_del) is bytes:
289-
result_dialog = MDDialog(
290-
title='Attention',
291-
text=f'Do you really want to delete "{password}" password?',
292-
auto_dismiss=False,
293-
buttons=[
294-
MDFillRoundFlatIconButton(
295-
text='Yes',
296-
icon='check-circle-outline',
297-
on_release=lambda x: [
298-
self.del_password_confirm(password=password),
299-
result_dialog.dismiss()
300-
]
301-
),
302-
MDRoundFlatIconButton(
303-
text='No',
304-
icon='close-circle-outline',
305-
on_release=lambda x: self.dismiss_and_back(result_dialog)
306-
)
307-
]
308-
)
352+
if len(password) == 0:
353+
result_dialog = CustomDialog(
354+
title='Whoops',
355+
text='Please provide password alias at first.'
356+
).alert()
357+
elif len(password) < 3:
358+
result_dialog = CustomDialog(
359+
title='Whoops',
360+
text='Password alias has to be at least 3 characters long.'
361+
).alert()
362+
else:
363+
to_del = query(
364+
'SELECT `password` FROM `passwords` WHERE `name` LIKE ?;',
365+
[password]
366+
)
367+
if len(to_del) > 0:
368+
to_del = to_del[0][0]
369+
if type(to_del) is bytes:
370+
result_dialog = MDDialog(
371+
title='Attention',
372+
text=f'Do you really want to delete "{password}" password?',
373+
auto_dismiss=False,
374+
buttons=[
375+
MDFillRoundFlatIconButton(
376+
text='Yes',
377+
icon='check-circle-outline',
378+
on_release=lambda x: [
379+
self.del_password_confirm(password=password),
380+
result_dialog.dismiss()
381+
]
382+
),
383+
MDRoundFlatIconButton(
384+
text='No',
385+
icon='close-circle-outline',
386+
on_release=lambda x: self.dismiss_and_back(result_dialog)
387+
)
388+
]
389+
)
390+
else:
391+
Logger.critical(
392+
f'Database: Password "{password}" is stored as "{type(to_del)}" type instead of "byte" type')
393+
result_dialog = CustomDialog(
394+
title='Warning!',
395+
text='An critical error has occurred. Passwords are saved to local database in wrong way.'
396+
).alert()
309397
else:
310-
Logger.critical(
311-
f'Database: Password "{password}" is stored as "{type(to_del)}" type instead of "byte" type')
312398
result_dialog = CustomDialog(
313399
title='Warning!',
314-
text='An critical error has occurred. Passwords are saved to local database in wrong way.'
400+
text='That password do not exists in database'
315401
).alert()
316-
else:
317-
result_dialog = CustomDialog(
318-
title='Warning!',
319-
text='That password do not exists in database'
320-
).alert()
321402
result_dialog.open()
322403

323404
def del_password_confirm(self, password):
@@ -347,12 +428,14 @@ def del_password_confirm(self, password):
347428
def change_alpha(self, preset=None):
348429
"""Changing alpha password based on text input or random value from ``reset_alpha`` method."""
349430
Logger.trace('Called: change_alpha')
431+
ok_beta = self.check_beta()
350432
password_box = self.root.ids.alpha_change
433+
if ok_beta is True:
351434

352-
if preset is None:
353-
password = password_box.text
354-
else:
355-
password = preset
435+
if preset is None:
436+
password = password_box.text
437+
else:
438+
password = preset
356439

357440
if len(password) < 6:
358441
result_dialog = CustomDialog(
@@ -361,38 +444,38 @@ def change_alpha(self, preset=None):
361444
).alert()
362445
password_box.error = True
363446

364-
else:
365-
password_box.error = False
366-
try:
367-
open(appdata(Files.beta_key))
368-
except FileNotFoundError:
369-
generate_salt()
370-
finally:
447+
else:
448+
password_box.error = False
371449
try:
372-
open(appdata(Files.alpha_key))
450+
open(appdata(Files.beta_key))
373451
except FileNotFoundError:
374-
open(appdata(Files.alpha_key), 'x')
375-
finally:
376-
with open(appdata(Files.beta_key), 'rb') as f:
377-
kdf = PBKDF2HMAC(
378-
algorithm=hashes.SHA256(),
379-
length=32,
380-
salt=f.read(),
381-
iterations=100000,
382-
backend=default_backend()
383-
)
384-
with open(appdata(Files.alpha_key), 'wb') as f:
385-
key = base64.urlsafe_b64encode(kdf.derive(password.encode()))
386-
f.write(key)
387-
Logger.info('Passwords: Alpha password has changed')
388-
389-
result_dialog = CustomDialog(
390-
title='Success!',
391-
text='New alpha password successfully saved.'
392-
).alert()
452+
self.check_beta()
453+
return
454+
else:
455+
try:
456+
open(appdata(Files.alpha_key))
457+
except FileNotFoundError:
458+
open(appdata(Files.alpha_key), 'x')
459+
finally:
460+
with open(appdata(Files.beta_key), 'rb') as f:
461+
kdf = PBKDF2HMAC(
462+
algorithm=hashes.SHA256(),
463+
length=32,
464+
salt=f.read(),
465+
iterations=100000,
466+
backend=default_backend()
467+
)
468+
with open(appdata(Files.alpha_key), 'wb') as f:
469+
key = base64.urlsafe_b64encode(kdf.derive(password.encode()))
470+
f.write(key)
471+
Logger.info('Passwords: Alpha password has changed')
472+
result_dialog = CustomDialog(
473+
title='Success!',
474+
text='New alpha password successfully saved.'
475+
).alert()
393476

477+
result_dialog.open()
394478
password_box.text = ''
395-
result_dialog.open()
396479

397480
def reset_alpha(self):
398481
"""Changing alpha password to ``random_password`` function value."""
@@ -526,8 +609,24 @@ def update_passwords(self):
526609
count = len(self.passwords)
527610
if count == 0:
528611
text = 'There are no passwords in database.'
612+
self.root.ids.passwords_list.add_widget(
613+
NewbieTip(
614+
text='Welcome to Python Password',
615+
secondary_text='Save your first password, by entering',
616+
tertiary_text='it\'s data on the right',
617+
icon='arrow-right-bold-circle'
618+
)
619+
)
529620
elif count == 1:
530621
text = 'There\'s only 1 password in database.'
622+
self.root.ids.passwords_list.add_widget(
623+
NewbieTip(
624+
text='Congratulations!',
625+
secondary_text='You have saved your\'s 1st password.',
626+
tertiary_text='Preview it just by clicking it.',
627+
icon='arrow-up-bold-circle'
628+
)
629+
)
531630
else:
532631
text = f'There are {count} passwords in database.'
533632
self.root.ids.passwords_count.text = text

0 commit comments

Comments
 (0)