engine.lisp 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. (in-package :cl-user)
  2. (defpackage #:assboard.engine
  3. (:use :cl :assboard.utils)
  4. (:export #:not-valid-pgp-error))
  5. (in-package #:assboard.engine)
  6. (defvar *command-valid-for* 600 "Seconds of validity for command timestamp")
  7. (defun sync-keys-with-trustlist ()
  8. (let ((keys (assboard.pgp:list-fingerprints))
  9. (trustlist (assboard.wot:get-trustlist)))
  10. ;; Drop no-longer-trusted keys
  11. (loop for fgp in keys
  12. unless (find fgp trustlist :test #'equal :key #'car)
  13. do (assboard.pgp:delete-key fgp))
  14. ;; Download new trusted keys
  15. (loop for (fgp . username) in trustlist
  16. unless (find fgp keys :test #'equal)
  17. do (assboard.pgp:recv-key fgp))))
  18. (define-condition command-error (error) ())
  19. (define-condition not-valid-pgp-error (command-error) ())
  20. (define-condition not-valid-command-error (command-error) ())
  21. (define-condition not-valid-signature-error (command-error) ())
  22. (define-condition not-valid-timestamp-error (command-error) ())
  23. (defun cmd/new-post (cmd raw)
  24. (let* ((fgp (assboard.data::raw-fingerprint raw))
  25. (author (or (cdr (assoc fgp
  26. assboard.wot:*trustlist-cache*
  27. :test #'equal))
  28. fgp))
  29. (title-end (position #\Newline cmd))
  30. (title (subseq cmd 10 title-end))
  31. (body (subseq cmd (+ title-end 2)))
  32. (posting
  33. (pomo:make-dao 'assboard.data::posting
  34. :author author
  35. :title title
  36. :body body))
  37. (posting-edition
  38. (pomo:make-dao 'assboard.data::posting-edition
  39. :posting-id (assboard.data::posting-id posting)
  40. :title title
  41. :body body
  42. :raw-id (assboard.data::raw-id raw))))
  43. (values posting posting-edition)))
  44. (defun cmd/close-post (cmd raw))
  45. (defun cmd/update-post (cmd raw))
  46. (defparameter +commands+
  47. (list (cons "NEW POST: " #'cmd/new-post)
  48. (cons "CLOSE POST: " #'cmd/close-post)
  49. (cons "UPDATE POST: " #'cmd/update-post)))
  50. (defun get-command-handler (command)
  51. (cdr (find command +commands+ :key #'car
  52. :test #'(lambda (s w) (starts-with w s)))))
  53. (defun process-command (clearsigned)
  54. ;; Simple vanity check
  55. (unless (starts-with "-----BEGIN PGP SIGNED MESSAGE-----" clearsigned)
  56. (error 'not-valid-pgp-error))
  57. (handler-case
  58. (let* ((start (+ 2 (search '(#\Newline #\Newline) clearsigned)))
  59. (end (1- (search "-----BEGIN PGP SIGNATURE-----" clearsigned)))
  60. (command (subseq clearsigned start end))
  61. (handler (get-command-handler command)))
  62. ;; Command check
  63. (unless handler
  64. (error 'not-valid-command-error))
  65. ;; Signature validation
  66. (multiple-value-bind (fgp unixtime)
  67. (assboard.pgp:verify clearsigned)
  68. (unless fgp
  69. (error 'not-valid-signature-error))
  70. (let ((timestamp (local-time:unix-to-timestamp unixtime)))
  71. ;; Timestamp check
  72. (unless (< (abs (local-time:timestamp-difference
  73. (local-time:now)
  74. timestamp))
  75. *command-valid-for*)
  76. (error 'not-valid-timestamp-error))
  77. ;; All checks performed, store raw command text and process it
  78. (let ((raw (pomo:make-dao 'assboard.data::raw
  79. :clearsigned clearsigned
  80. :fingerprint fgp
  81. :timestamp timestamp)))
  82. (funcall handler command raw)))))
  83. (type-error (e)
  84. (princ e)
  85. (error 'not-valid-command-error))))