mirror of
https://github.com/jrnl-org/jrnl.git
synced 2025-05-10 16:48:31 +02:00
Adds encryption and decryption of existing journals, closes #6
This commit is contained in:
parent
c7f7e2f287
commit
4c7ea456cb
2 changed files with 54 additions and 18 deletions
|
@ -1,6 +1,10 @@
|
||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
### 0.2.2
|
||||||
|
|
||||||
|
* Adds --encrypt and --decrypt to encrypt / descrypt existing journal files
|
||||||
|
|
||||||
### 0.2.1
|
### 0.2.1
|
||||||
|
|
||||||
* Submitted to [PyPi](http://pypi.python.org/pypi/jrnl/0.2.1).
|
* Submitted to [PyPi](http://pypi.python.org/pypi/jrnl/0.2.1).
|
||||||
|
|
66
jrnl.py
66
jrnl.py
|
@ -30,6 +30,8 @@ default_config = {
|
||||||
'tagsymbols': '@'
|
'tagsymbols': '@'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CONFIG_PATH = os.path.expanduser('~/.jrnl_config')
|
||||||
|
|
||||||
class Entry:
|
class Entry:
|
||||||
def __init__(self, journal, date=None, title="", body=""):
|
def __init__(self, journal, date=None, title="", body=""):
|
||||||
self.journal = journal # Reference to journal mainly to access it's config
|
self.journal = journal # Reference to journal mainly to access it's config
|
||||||
|
@ -104,6 +106,11 @@ class Journal:
|
||||||
plain += " " * 16
|
plain += " " * 16
|
||||||
return iv + crypto.encrypt(plain)
|
return iv + crypto.encrypt(plain)
|
||||||
|
|
||||||
|
def make_key(self, prompt="Password: "):
|
||||||
|
"""Creates an encryption key from the default password or prompts for a new password."""
|
||||||
|
password = self.config['password'] or getpass.getpass(prompt)
|
||||||
|
self.key = hashlib.sha256(password).digest()
|
||||||
|
|
||||||
def open(self, filename=None):
|
def open(self, filename=None):
|
||||||
"""Opens the journal file defined in the config and parses it into a list of Entries.
|
"""Opens the journal file defined in the config and parses it into a list of Entries.
|
||||||
Entries have the form (date, title, body)."""
|
Entries have the form (date, title, body)."""
|
||||||
|
@ -115,12 +122,11 @@ class Journal:
|
||||||
decrypted = None
|
decrypted = None
|
||||||
attempts = 0
|
attempts = 0
|
||||||
while decrypted is None:
|
while decrypted is None:
|
||||||
password = self.config['password'] or getpass.getpass()
|
self.make_key()
|
||||||
self.key = hashlib.sha256(password).digest()
|
|
||||||
decrypted = self._decrypt(journal)
|
decrypted = self._decrypt(journal)
|
||||||
if not decrypted:
|
if decrypted is None:
|
||||||
attempts += 1
|
attempts += 1
|
||||||
self.config['password'] = None # This doesn't work.
|
self.config['password'] = None # This password doesn't work.
|
||||||
if attempts < 3:
|
if attempts < 3:
|
||||||
print("Wrong password, try again.")
|
print("Wrong password, try again.")
|
||||||
else:
|
else:
|
||||||
|
@ -203,7 +209,6 @@ class Journal:
|
||||||
search_tags = set([tag.lower() for tag in tags])
|
search_tags = set([tag.lower() for tag in tags])
|
||||||
end_date = self.parse_date(end_date)
|
end_date = self.parse_date(end_date)
|
||||||
start_date = self.parse_date(start_date)
|
start_date = self.parse_date(start_date)
|
||||||
print start_date, end_date
|
|
||||||
# If strict mode is on, all tags have to be present in entry
|
# If strict mode is on, all tags have to be present in entry
|
||||||
tagged = search_tags.issubset if strict else search_tags.intersection
|
tagged = search_tags.issubset if strict else search_tags.intersection
|
||||||
result = [
|
result = [
|
||||||
|
@ -257,7 +262,11 @@ class Journal:
|
||||||
self.entries.append(Entry(self, date, title, body))
|
self.entries.append(Entry(self, date, title, body))
|
||||||
self.sort()
|
self.sort()
|
||||||
|
|
||||||
def setup(config_path):
|
def save_config(self, config_path = CONFIG_PATH):
|
||||||
|
with open(config_path, 'w') as f:
|
||||||
|
json.dump(self.config, f, indent=2)
|
||||||
|
|
||||||
|
def setup():
|
||||||
def autocomplete(text, state):
|
def autocomplete(text, state):
|
||||||
expansions = glob.glob(os.path.expanduser(text)+'*')
|
expansions = glob.glob(os.path.expanduser(text)+'*')
|
||||||
expansions = [e+"/" if os.path.isdir(e) else e for e in expansions]
|
expansions = [e+"/" if os.path.isdir(e) else e for e in expansions]
|
||||||
|
@ -281,7 +290,7 @@ def setup(config_path):
|
||||||
open(default_config['journal'], 'a').close() # Touch to make sure it's there
|
open(default_config['journal'], 'a').close() # Touch to make sure it's there
|
||||||
|
|
||||||
# Write config to ~/.jrnl_conf
|
# Write config to ~/.jrnl_conf
|
||||||
with open(config_path, 'w') as f:
|
with open(CONFIG_PATH, 'w') as f:
|
||||||
json.dump(default_config, f, indent=2)
|
json.dump(default_config, f, indent=2)
|
||||||
config = default_config
|
config = default_config
|
||||||
if password:
|
if password:
|
||||||
|
@ -289,11 +298,11 @@ def setup(config_path):
|
||||||
return config
|
return config
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
config_path = os.path.expanduser('~/.jrnl_config')
|
|
||||||
if not os.path.exists(config_path):
|
if not os.path.exists(CONFIG_PATH):
|
||||||
config = setup(config_path)
|
config = setup()
|
||||||
else:
|
else:
|
||||||
with open(config_path) as f:
|
with open(CONFIG_PATH) as f:
|
||||||
config = json.load(f)
|
config = json.load(f)
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
@ -306,12 +315,20 @@ if __name__ == "__main__":
|
||||||
reading.add_argument('-to', dest='end_date', metavar="DATE", help='View entries before this date')
|
reading.add_argument('-to', dest='end_date', metavar="DATE", help='View entries before this date')
|
||||||
reading.add_argument('-and', dest='strict', action="store_true", help='Filter by tags using AND (default: OR)')
|
reading.add_argument('-and', dest='strict', action="store_true", help='Filter by tags using AND (default: OR)')
|
||||||
reading.add_argument('-n', dest='limit', default=None, metavar="N", help='Shows the last n entries matching the filter', nargs="?", type=int)
|
reading.add_argument('-n', dest='limit', default=None, metavar="N", help='Shows the last n entries matching the filter', nargs="?", type=int)
|
||||||
reading.add_argument('-json', dest='json', action="store_true", help='Returns a JSON-encoded version of the Journal')
|
|
||||||
|
reading = parser.add_argument_group('Export / Import', 'Options for transmogrifying your journal')
|
||||||
|
reading.add_argument('--json', dest='json', action="store_true", help='Returns a JSON-encoded version of the Journal')
|
||||||
|
reading.add_argument('--encrypt', dest='encrypt', action="store_true", help='Encrypts your existing journal with a new password')
|
||||||
|
reading.add_argument('--decrypt', dest='decrypt', action="store_true", help='Decrypts your journal and stores it in plain text')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Guess mode
|
# Guess mode
|
||||||
compose = True
|
compose = True
|
||||||
if args.start_date or args.end_date or args.limit or args.json or args.strict:
|
export = False
|
||||||
|
if args.json or args.decrypt or args.encrypt:
|
||||||
|
compose = False
|
||||||
|
export = True
|
||||||
|
elif args.start_date or args.end_date or args.limit or args.strict:
|
||||||
# Any sign of displaying stuff?
|
# Any sign of displaying stuff?
|
||||||
compose = False
|
compose = False
|
||||||
elif not args.date and args.text and all(word[0] in config['tagsymbols'] for word in args.text):
|
elif not args.date and args.text and all(word[0] in config['tagsymbols'] for word in args.text):
|
||||||
|
@ -344,10 +361,25 @@ if __name__ == "__main__":
|
||||||
print("Entry added.")
|
print("Entry added.")
|
||||||
journal.write()
|
journal.write()
|
||||||
|
|
||||||
else: # read mode
|
elif not export: # read mode
|
||||||
journal.filter(tags=args.text, start_date=args.start_date, end_date=args.end_date, strict=args.strict)
|
journal.filter(tags=args.text, start_date=args.start_date, end_date=args.end_date, strict=args.strict)
|
||||||
journal.limit(args.limit)
|
journal.limit(args.limit)
|
||||||
if args.json:
|
|
||||||
print(journal.to_json())
|
|
||||||
else:
|
|
||||||
print(journal)
|
print(journal)
|
||||||
|
|
||||||
|
elif args.json: # export to json
|
||||||
|
print(journal.to_json())
|
||||||
|
|
||||||
|
elif args.encrypt:
|
||||||
|
journal.config['encrypt'] = True
|
||||||
|
journal.config['password'] = ""
|
||||||
|
journal.make_key(prompt="Enter new password:")
|
||||||
|
journal.write()
|
||||||
|
journal.save_config()
|
||||||
|
print("Journal encrypted to %s." % journal.config['journal'])
|
||||||
|
|
||||||
|
elif args.decrypt:
|
||||||
|
journal.config['encrypt'] = False
|
||||||
|
journal.config['password'] = ""
|
||||||
|
journal.write()
|
||||||
|
journal.save_config()
|
||||||
|
print("Journal decrypted to %s." % journal.config['journal'])
|
||||||
|
|
Loading…
Add table
Reference in a new issue