bin/scripts/pd (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
#!/usr/bin/env python3 # # ------------------------------------------------------------- # Journal Keeping Script [aka Personal Diary (pd)] # Author : Prithu Goswami <prithugoswami524@gmail.com> # ------------------------------------------------------------- # Prerequisites : make sure these programs are available on the # machine: # 'rclone' # 'vim' # 'gpg' (v2.X) # # This is a very messy script and is just a quick hack and is not # a very super secure way of keeping a journal but I hope to improve on # it with time. It uses symmetric AES-128 encryption. # # This script opens a temp file in a vim buffer and after wrting # and quiting from vim, it appends the contents to the file # 'pd_path' that is in the 'pd_dir' in the $HOME dir of the machine, # with a date and timestamp. It then encrypts the file using gpg # and uploads it to the cloud storage. # # NOTE : 'rclone' should be configured # with a remote first. run 'rlone config'. # The remote should have directory with the encrypted 'pd' file # Path to remote directory should be stored in 'rclone_dir' # # I use 'rclone' to sync the journal to my dropbox # the script first fetches any changes done to the pd file, # decryptis it using 'gpg' using the passhprase-file as '$HOME/.pdkey' # and then appends the entry, encrypts it and uploads it. # # VARIABLES # # 'key_path' : passphrase for AES encrypted file # default alogrithm used by gpg v2.2 is AES-128 according # to the man page # 'pd_dir' : The directory where the pd file is stored # 'pd_path' : The path to the pd file. This is just "pd_dir+'pd'" # 'rclone_dir' ; The direrctory of the pd file on the 'remote' # in this case the 'remote' is 'drop:' # # NOTE : # Make sure there already exists a symmetrically encrypted AES file # in 'pd_path' and also in 'rclone_dir' # # To symmetrically encrypt an empty file run: # `touch empty ; gpg2 --passphrase <secret> --batch -o pd -c empty` # this should create a symmetrically encrypted AES file named 'pd' with # the passphrase <secret> # Now, save this file ('pd') in the 'pd_dir' and also upload it to the # remote dir using rclone. # This is not the most secure thing in the world I don't even intend it # to be. So anyways, the <secret> has to be saved as .pdkey in your home # directory or elsewhere ( if you're saving it elsewhere, then change # the 'key_path' variable accordingly import os from datetime import datetime as dt import tempfile import subprocess import shlex import sys import hashlib ## VARIABLES ## # Change these accordingly env_home = os.environ['HOME'] tmp_pd_path = '/tmp/pd' key_path = env_home + '/.pdkey' pd_dir = env_home + '/dropbox/pd' pd_path = pd_dir + '/pd' rclone_dir = 'drop:/pd' if os.path.exists(tmp_pd_path): os.remove(tmp_pd_path) ping_cmd = "ping -c 1 8.8.8.8" ping_args = shlex.split(ping_cmd) p = subprocess.Popen(ping_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() if p.returncode: print("Network Unreachable...exiting now\nWrite a better script that can " "cache the entry locally you lazy ass") exit(p.returncode) def save_entry(entry): entry_filename = dt.now().strftime('%s') + ".pdentry" entry_file_path = env_home + "/" + entry_filename print("Saving the entry to {}".format(entry_file_path)) with open(entry_file_path, 'w', encoding='utf8') as entry_file: entry_file.write(entry) def fetch_and_decrypt(): """ Fetches the cloud copy first (sync) and then decrypts it to tmp_pd_path """ print("Fetching changes...") if not os.system('rclone sync {}/ {}/'.format(rclone_dir, pd_dir)): print("Done") decrypt_cmd = ('gpg -o {} -d {}'.format(tmp_pd_path, pd_path)) args = shlex.split(decrypt_cmd) p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) out, err = p.communicate() if p.returncode: # if gpg exits with a non-zero return code print("Error while decrypting :\n" + err) return(p.returncode) else: print("Something went wrong") return(1) def encrypt_and_push(): """ Encrypts the file at tmp_pd_path and then syncs to the cloud. i.e replace the copy in the cloud with the local one. """ if os.path.exists(pd_path): os.remove(pd_path) encrypt_cmd = ('gpg -o {} -c {}'.format( pd_path, tmp_pd_path)) args = shlex.split(encrypt_cmd) p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) out, err = p.communicate() if p.returncode: print("Error while encrypting :\n" + err) return(p.returncode) os.remove(tmp_pd_path) print("Pushing changes...") if not os.system('rclone sync {}/ {}/'.format(pd_dir, rclone_dir)): print("Done") else: print("Something went wrong") return(1) # PD edit argument # with the 'edit' argument passed to the script it will fetch the latest pd # version from the cloud and let you edit and then push it back if len(sys.argv) > 1: if sys.argv[1] == 'edit': if os.path.exists(tmp_pd_path): os.remove(tmp_pd_path) fetch_and_decrypt() with open(tmp_pd_path, 'r') as pdtemp: hash_before_edit = (hashlib.sha1(pdtemp.read().encode('utf-8')) .hexdigest()) os.system("vim {}".format(tmp_pd_path)) with open(tmp_pd_path, 'r') as pdtemp: hash_after_edit = (hashlib.sha1(pdtemp.read().encode('utf-8')) .hexdigest()) if hash_before_edit == hash_after_edit: print("Nothing was changed. Exiting...") exit() encrypt_and_push() exit() entry = None with tempfile.NamedTemporaryFile(suffix='.pdentry') as temp: command = "vim {}".format(temp.name) os.system(command) entry = open(temp.name, 'r').read() if len(entry.strip()) == 0: print("Nothing was entered...") exit() if fetch_and_decrypt(): # if there was any error while fetching and decrypting save_entry(entry) exit(1) with open(tmp_pd_path, 'a', encoding='utf8') as fp: now = dt.now() date_string = now.strftime('%a, %d %b %Y') time_string = now.strftime('%I:%M %p') date_and_time = '[' + date_string + ' | ' + time_string + ']' fp.write('\n\n\n===============================\n' + date_and_time + '\n') fp.write(entry) if encrypt_and_push(): save_entry(entry) exit(1) |