Skip to content

Commit fcf7aaf

Browse files
committed
Merge branch 'release/0.9.10'
2 parents d824741 + d12cfed commit fcf7aaf

20 files changed

Lines changed: 739 additions & 132 deletions

README.rst

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ Copyright 2016 Todd T Knarr <tknarr@silverglass.org>
1818
This program is free software: you can redistribute it and/or modify it under
1919
the terms of the GNU General Public License as published by the Free Software
2020
Foundation, either version 3 of the License, or (at your option) any later
21-
version.
21+
version. The Fernet AES256 implementation (fernet256.py) is dual licensed
22+
under the terms of the Apache License version 2.0 and the BSD License as
23+
noted in the source file.
2224

2325
This program is distributed in the hope that it will be useful, but WITHOUT
2426
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
@@ -36,10 +38,10 @@ and other software and hardware using the standard TOTP algorithm outlined in
3638
`RFC 6238 <https://tools.ietf.org/html/rfc6238>`_ (support for the HOTP algorithm
3739
outlined in `RFC 4226 <https://tools.ietf.org/html/rfc4226>`_ is planned).
3840

39-
Secrets are encrypted in the database using AES encryption in CBC mode. There is
40-
no option for storing unencrypted secrets. If you were using an older beta version
41-
of this program, you will be prompted for a password and upon first save the
42-
secrets will be encrypted using it.
41+
Secrets are encrypted using AES256, there is no option for storing unencrypted
42+
secrets. If you were using an older beta version, you will be prompted for a
43+
password and the stored secrets will be migrated to the current encryption without
44+
requiring any more user intervention.
4345

4446
PyPI page: `https://pypi.python.org/pypi/PyAuth <https://pypi.python.org/pypi/PyAuth>`_
4547

@@ -50,7 +52,9 @@ Prerequisites
5052
* `wxPython <http://www.wxpython.org/>`_ 3.0 or higher, which requires matching
5153
`wxWidgets <http://www.wxwidgets.org/>`_
5254
* `pyotp 2.0.1 <https://pypi.python.org/pypi/pyotp>`_ or higher
53-
* `pycrypto 2.6.1 <https://pypi.python.org/pypi/pycrypto>`_ or higher
55+
* `cryptography 1.3 <https://pypi.python.org/pypi/cryptography>`_ or higher
56+
* `pycrypto 2.6.1 <https://pypi/python.org/pypi/pycrypto>`_ or higher, strictly for
57+
decrypting older databases
5458

5559
wxPython isn't automatically pulled in by ``pip`` because the version at PyPI is
5660
still 2.9. Your distribution probably includes a pre-packaged version, or you can

VERSIONS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# PyAuth version history:
22

3-
* 1.0.0 - Initial release
3+
* 0.9.10 - Implement authenticated 256-bit encryption
44

55
* 0.9.7 - Keyboard accelerators working
66

pyauth/About.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,23 @@
11
# -*- coding: utf-8 -*-
22
"""Metadata about the program."""
33

4+
## PyAuth - Google Authenticator desktop application
5+
## Copyright (C) 2016 Todd T Knarr <tknarr@silverglass.org>
6+
7+
## This program is free software: you can redistribute it and/or modify
8+
## it under the terms of the GNU General Public License as published by
9+
## the Free Software Foundation, either version 3 of the License, or
10+
## (at your option) any later version.
11+
12+
## This program is distributed in the hope that it will be useful,
13+
## but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
## GNU General Public License for more details.
16+
17+
## You should have received a copy of the GNU General Public License
18+
## along with this program. If not, see http://www.gnu.org/licenses/
19+
420
import sysconfig
5-
import base64
621
import io
722
import pkg_resources
823
import wx

pyauth/AuthEntryPanel.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
11
# -*- coding: utf-8 -*-
22
"""Authentication code entry panel."""
33

4+
## PyAuth - Google Authenticator desktop application
5+
## Copyright (C) 2016 Todd T Knarr <tknarr@silverglass.org>
6+
7+
## This program is free software: you can redistribute it and/or modify
8+
## it under the terms of the GNU General Public License as published by
9+
## the Free Software Foundation, either version 3 of the License, or
10+
## (at your option) any later version.
11+
12+
## This program is distributed in the hope that it will be useful,
13+
## but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
## GNU General Public License for more details.
16+
17+
## You should have received a copy of the GNU General Public License
18+
## along with this program. If not, see http://www.gnu.org/licenses/
19+
420
import wx
521
from AuthenticationStore import AuthenticationEntry
622
from Logging import GetLogger

pyauth/AuthFrame.py

Lines changed: 73 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
11
# -*- coding: utf-8 -*-
22
"""Frame for the main window."""
33

4+
## PyAuth - Google Authenticator desktop application
5+
## Copyright (C) 2016 Todd T Knarr <tknarr@silverglass.org>
6+
7+
## This program is free software: you can redistribute it and/or modify
8+
## it under the terms of the GNU General Public License as published by
9+
## the Free Software Foundation, either version 3 of the License, or
10+
## (at your option) any later version.
11+
12+
## This program is distributed in the hope that it will be useful,
13+
## but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
## GNU General Public License for more details.
16+
17+
## You should have received a copy of the GNU General Public License
18+
## along with this program. If not, see http://www.gnu.org/licenses/
19+
420
import math
521
import sysconfig
622
import pkg_resources
@@ -16,6 +32,7 @@
1632
from ChangeDatabasePasswordDialog import ChangeDatabasePasswordDialog
1733
from HTMLTextDialog import HTMLTextDialog
1834
from Logging import GetLogger
35+
from Errors import DecryptionError, PasswordError
1936

2037
class AuthTaskbarIcon( wx.TaskBarIcon ):
2138
"""Notification tray icon."""
@@ -205,13 +222,22 @@ def OnCreate( self, event ):
205222
break
206223
try:
207224
self.auth_store = AuthenticationStore( Configuration.GetDatabaseFilename(), password )
208-
except ValueError:
225+
except DecryptionError as e:
226+
GetLogger().error( str( e ) )
227+
GetLogger().error( "Failure decrypting database." )
209228
retry = True
210-
else:
229+
except PasswordError as e:
230+
GetLogger().error( str( e ) )
231+
GetLogger().error( "Password problem decrypting database." )
232+
retry = True
233+
except Exception as e:
234+
GetLogger().error( str( e ) )
235+
GetLogger().critical( "Unexpected exception decrypting database." )
211236
retry = False
212237
finally:
213238
if self.auth_store != None:
214239
authentication_store_ok = True
240+
retry = False
215241
if not authentication_store_ok:
216242
GetLogger().critical( "Database could not be opened" )
217243
self.do_not_save = True
@@ -427,7 +453,14 @@ def OnCloseWindow( self, event ):
427453
self.timer = None
428454
if not self.do_not_save:
429455
if self.auth_store != None:
430-
self.auth_store.Save()
456+
try:
457+
self.auth_store.Save()
458+
except PasswordError:
459+
dlg = wx.MessageDialog( self, "A database password is required.", "Error",
460+
style = wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP | wx.CENTRE )
461+
dlg.SetExtendedMessage( "The database could not be properly saved." )
462+
dlg.ShowModal()
463+
dlg.Destroy()
431464
wp = self.GetPosition()
432465
Configuration.SetLastWindowPosition( wp )
433466
if self.displayed:
@@ -503,7 +536,12 @@ def OnMenuNewEntry( self, event ):
503536
GetLogger().debug( "AF NE account %s", account )
504537
GetLogger().debug( "AF NE digits %d", digits )
505538
GetLogger().debug( "AF NE orig lbl %s", original_label )
506-
entry = self.auth_store.Add( provider, account, secret, digits, original_label )
539+
try:
540+
entry = self.auth_store.Add( provider, account, secret, digits, original_label )
541+
sts = ''
542+
except PasswordError:
543+
entry = None
544+
sts = 'password'
507545
if entry != None:
508546
GetLogger().debug( "AF NE new panel: %d", entry.GetGroup() )
509547
# If all we have is the dummy entry then replace it, otherwise add the new entry at the end
@@ -524,10 +562,15 @@ def OnMenuNewEntry( self, event ):
524562
## unicode( panel.GetMinSize() ) )
525563
self.UpdatePanelSize()
526564
else:
527-
GetLogger().debug( "AF NE duplicate item" )
528-
dlg = wx.MessageDialog( self, "That entry already exists.", "Error",
529-
style = wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP | wx.CENTRE )
530-
dlg.SetExtendedMessage( "Provider: {0}\nAccount: {1}".format( provider, account ) )
565+
if sts == 'password':
566+
GetLogger().debug( "AF NE password error" )
567+
dlg = wx.MessageDialog( self, "A database password is required.", "Error",
568+
style = wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP | wx.CENTRE )
569+
else:
570+
GetLogger().debug( "AF NE duplicate item" )
571+
dlg = wx.MessageDialog( self, "That entry already exists.", "Error",
572+
style = wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP | wx.CENTRE )
573+
dlg.SetExtendedMessage( "Provider: {0}\nAccount: {1}".format( provider, account ) )
531574
dlg.ShowModal()
532575
dlg.Destroy()
533576

@@ -568,10 +611,14 @@ def OnMenuEditEntry( self, event ):
568611
GetLogger().debug( "AF UE updating entry" )
569612
status = self.auth_store.Update( entry.GetGroup(), provider, account, secret, digits )
570613
if status < 0:
571-
dlg = wx.MessageDialog( self, "Database is corrupted.", "Error",
572-
style = wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP | wx.CENTRE )
573-
dlg.SetExtendedMessage( "Multiple copies of the entry were found.\n" +
574-
"The database is likely corrupted and needs repaired." )
614+
if status == -100:
615+
dlg = wx.MessageDialog( self, "A database password is required.", "Error",
616+
style = wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP | wx.CENTRE )
617+
else:
618+
dlg = wx.MessageDialog( self, "Database is corrupted.", "Error",
619+
style = wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP | wx.CENTRE )
620+
dlg.SetExtendedMessage( "Multiple copies of the entry were found.\n" +
621+
"The database is likely corrupted and needs repaired." )
575622
dlg.ShowModal()
576623
dlg.Destroy()
577624
elif status == 0:
@@ -779,7 +826,13 @@ def OnMenuReindex( self, event ):
779826
"""Handle a request to reindex the database from the menu."""
780827
GetLogger().debug( "AF menu Reindex command" )
781828
GetLogger().info( "Database reindex ordered" )
782-
self.auth_store.Reindex()
829+
try:
830+
self.auth_store.Reindex()
831+
except PasswordError:
832+
dlg = wx.MessageDialog( self, "A database password is required.", "Error",
833+
style = wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP | wx.CENTRE )
834+
dlg.ShowModal()
835+
dlg.Destroy()
783836
self.depopulate_entries_window()
784837
self.populate_entries_window()
785838
self.UpdatePanelSize()
@@ -788,7 +841,13 @@ def OnMenuRegroup( self, event ):
788841
"""Handle a request to re-group the database from the menu."""
789842
GetLogger().debug( "AF menu Regroup command" )
790843
GetLogger().info( "Database regroup and reindex ordered" )
791-
self.auth_store.Regroup()
844+
try:
845+
self.auth_store.Regroup()
846+
except PasswordError:
847+
dlg = wx.MessageDialog( self, "A database password is required.", "Error",
848+
style = wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP | wx.CENTRE )
849+
dlg.ShowModal()
850+
dlg.Destroy()
792851
self.depopulate_entries_window()
793852
self.populate_entries_window()
794853
self.UpdatePanelSize()

0 commit comments

Comments
 (0)