|
@@ -1,6 +1,8 @@
|
|
|
-(ql:quickload "cl-store")
|
|
|
+;;;(ql:quickload "cl-store")
|
|
|
+(ql:quickload "yason")
|
|
|
(ql:quickload "cl-ppcre")
|
|
|
(ql:quickload "unix-opts")
|
|
|
+(ql:quickload "ironclad")
|
|
|
|
|
|
;;; Features
|
|
|
;;; - Import records from old .txt format
|
|
@@ -57,8 +59,47 @@
|
|
|
(defun reload ()
|
|
|
(load "~/Repos/fin-lisp/fin-lisp.lisp"))
|
|
|
|
|
|
+(defun wfile (file-content file-path)
|
|
|
+ (alexandria:write-string-into-file
|
|
|
+ (concatenate 'string file-content) file-path :if-exists :overwrite
|
|
|
+ :if-does-not-exist :create))
|
|
|
+
|
|
|
+;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
+;;; Encryption stuff ;;;
|
|
|
+;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
+;;; See: https://www.cliki.net/Ironclad
|
|
|
+
|
|
|
+;;; Return cipher when provided key
|
|
|
+(defun get-cipher (key)
|
|
|
+ (ironclad:make-cipher
|
|
|
+ :blowfish
|
|
|
+ :mode :ecb
|
|
|
+ :key (ironclad:ascii-string-to-byte-array key)))
|
|
|
+
|
|
|
+;;; First serialize the file,
|
|
|
+;;; then encrypt it from disk
|
|
|
+(defun encrypt-records (key filename)
|
|
|
+ (let ((cipher (get-cipher key))
|
|
|
+ (file-content (uiop:read-file-string filename)))
|
|
|
+ (let ((content (ironclad:ascii-string-to-byte-array file-content)))
|
|
|
+ (ironclad:encrypt-in-place cipher content)
|
|
|
+ (wfile
|
|
|
+ (write-to-string (ironclad:octets-to-integer content))
|
|
|
+ (concatenate 'string filename ".enc")))))
|
|
|
+
|
|
|
+(defun decrypt-records (key filename)
|
|
|
+ (let ((cipher (get-cipher key))
|
|
|
+ (file-content (uiop:read-file-string filename)))
|
|
|
+ (let ((content (ironclad:integer-to-octets (parse-integer file-content))))
|
|
|
+ (ironclad:decrypt-in-place cipher content)
|
|
|
+ (coerce (mapcar #'code-char (coerce content 'list)) 'string))))
|
|
|
+
|
|
|
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
+;;; End Encryption Stuff ;;;
|
|
|
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
+
|
|
|
(defun reset-records ()
|
|
|
- (setf *records* (make-hash-table :test 'equalp)))
|
|
|
+ (setf *records* (make-hash-table :test 'equal)))
|
|
|
|
|
|
;; Called like: (add-month '202107)
|
|
|
(defun add-month (month-key)
|
|
@@ -97,17 +138,20 @@
|
|
|
(format t "~a : ~a~C" exp-key (gethash exp-key month-hash) #\linefeed))))
|
|
|
|
|
|
;;; Dump all records.
|
|
|
-;;; This will also be used for data serialization at some point
|
|
|
(defun dump-records ()
|
|
|
(let ((record-key-list (loop for key being the hash-keys of *records* collect key)))
|
|
|
(dolist (month-key record-key-list) (dump-month month-key))))
|
|
|
|
|
|
-(defun serialize-records (filename)
|
|
|
- (cl-store:store *records* filename))
|
|
|
+(defun serialize-records (key filename)
|
|
|
+ (with-open-file (stream filename
|
|
|
+ :direction :output
|
|
|
+ :if-exists :overwrite
|
|
|
+ :if-does-not-exist :create)
|
|
|
+ (yason:encode *records* stream))
|
|
|
+ (encrypt-records key filename))
|
|
|
|
|
|
-(defun deserialize-records (filename)
|
|
|
- ;(setf *records* (cl-store:restore (pathname filename))))
|
|
|
- (setf *records* (cl-store:restore filename)))
|
|
|
+(defun deserialize-records (key filename)
|
|
|
+
|
|
|
|
|
|
;; Import records from old perl version (plaintext file)
|
|
|
(defun import-records (filename)
|
|
@@ -168,7 +212,8 @@
|
|
|
"Invalid month"))
|
|
|
(if (string= answer "3")
|
|
|
(generic-handler
|
|
|
- (serialize-records (prompt-read "Enter filename"))
|
|
|
+ (serialize-records (prompt-read "Enter encryption key")
|
|
|
+ (prompt-read "Enter filename"))
|
|
|
"Serialization error or invalid filename"))
|
|
|
(if (string= answer "4")
|
|
|
(generic-handler
|
|
@@ -202,5 +247,5 @@
|
|
|
(when-option (matches :interactive-mode)
|
|
|
(progn
|
|
|
(interactive-mode)
|
|
|
- (quit)))))
|
|
|
+ (quit))))))
|
|
|
|