- # python modules
- import sys
- import pickle
- import base64
- import getpass
- import gzip
- # own modules
- from notebook import Notebook
- # cryptography module
- from cryptography.fernet import Fernet, InvalidToken
- from cryptography.hazmat.primitives import hashes
- from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
- from cryptography.hazmat.backends import default_backend
-
-
- class Menu:
- """Display a menu and respond to choices when run."""
-
- def __init__(self):
- self.salt = "a683c64de226677703f56e6b6ead94bbc3690ec5293c3de3ffdc"
- self.savefile = 'notebook.safe'
- self.notebook = Notebook()
- self.choices = {
- "1": self.show_notes,
- "2": self.search_notes,
- "3": self.add_note,
- "4": self.modify_note,
- "5": self.remove_note,
- "6": self.load_notes,
- "7": self.save_notes,
- "8": self.__init__,
- "9": self.quit
- }
-
- def display_menu(self):
- print("""
- Notebook Menu
- 1. Show all Notes
- 2. Search Notes
- 3. Add Note
- 4. Modify Note
- 5. Remove Note
- 6. Load Notes
- 7. Save Notes
- 8. Reset Notes
- 9. Quit """)
-
- def run(self):
- """Display the menu and respond to choices."""
- while True:
- self.display_menu()
- choice = input("Enter an option: ")
- action = self.choices.get(choice)
- try:
- action()
- except TypeError:
- print("{0} is not a valid choice".format(choice))
-
- def show_notes(self, notes=None):
- """Display all notes stored in notebook object"""
- if not notes:
- notes = self.notebook.notes
- for note in notes:
- print("{0}: {1}\n{2}".format(note.id, note.tags, note.memo))
-
- def search_notes(self):
- """Search for a note containing given string"""
- filter = input("Search for: ")
- notes = self.notebook.search(filter)
- self.show_notes(notes)
-
- def add_note(self):
- """Add a given not to notebook object"""
- memo = input("Enter a memo: ")
- self.notebook.new_note(memo)
- print("Your note has been added.")
-
- def modify_note(self):
- """Modify tag and memo of note with given id"""
- id = input("Enter a note id: ")
- memo = input("Enter a memo: ")
- tags = input("Enter tags: ")
- if memo:
- if not self.notebook.modify_memo(id, memo):
- print("Note with id {0} doesn't exist.".format(id))
- return
- if tags:
- if not self.notebook.modify_tags(id, tags):
- print("Note with id {0} doesn't exist.".format(id))
-
- def remove_note(self):
- """Remove note with given id from note list"""
- id = input("Enter a note id: ")
- if self.notebook.remove_note(id):
- print("Note with id {0} removed.".format(id))
- else:
- print("Note with id {0} doesn't exist.".format(id))
-
- def load_notes(self):
- """Decrypt notebook safe file and load it into notebook object"""
- try:
- f = open(self.savefile, 'rb')
- except IOError:
- print("Could not open file")
- else:
- cipher = f.read()
- f.close()
- notebook = self._decode_notefile(cipher)
- if notebook:
- self.notebook = notebook
- self.notebook._set_id()
-
- def save_notes(self):
- """Encrypt notebook object and store it into notebook safe file"""
- cipher = self._encode_notefile()
- try:
- f = open(self.savefile, 'wb')
- except IOError:
- print("Could not open file")
- else:
- f.write(cipher)
- f.close()
-
- def _decode_notefile(self, cipher):
- crypt = Fernet(self._get_password())
- try:
- plain = crypt.decrypt(cipher)
- except InvalidToken:
- print("Wrong password")
- else:
- try:
- plain = gzip.decompress(plain)
- except OSError:
- print("File not valid")
- else:
- return pickle.loads(plain)
-
- def _encode_notefile(self):
- plain = pickle.dumps(self.notebook, pickle.HIGHEST_PROTOCOL)
- crypt = Fernet(self._get_password())
- plain = gzip.compress(plain)
- return crypt.encrypt(plain)
-
- def _get_password(self):
- """Request passphrase and derive key from it"""
- passphrase = getpass.getpass()
- kdf = PBKDF2HMAC(
- algorithm=hashes.SHA256(),
- length=32,
- salt=self.salt.encode('utf-8'),
- iterations=10000,
- backend=default_backend()
- )
- return base64.urlsafe_b64encode(kdf.derive(passphrase.encode('utf-8')))
-
- def quit(self):
- """Quit application"""
- print("Thank you for using your notebook today.")
- sys.exit(0)
-
-
- if __name__ == "__main__":
- Menu().run()
|