I've been working on a home service for the pantalaimon matrix reverse
proxy (https://github.com/matrix-org/pantalaimon/).  I have been
successfully using successfully for a while now, so I believe it could
be useful to others.  I've attached the service definition, and would
welcome comments from people with more experience in this area of Guix.

Also if there is interest in this service should it go into a new file
in gnu/home/services or into one of the existing files?

(define-module (kjartan home services pantalaimon)
  #:use-module (srfi srfi-26)
  #:use-module (srfi srfi-1)
  #:use-module (guix gexp)
  #:use-module (guix records)
  #:use-module (guix packages)
  #:use-module (gnu services)
  #:use-module (gnu home services)
  #:use-module (gnu services configuration)
  #:use-module (gnu home services shepherd)
  #:use-module (gnu packages matrix)
  #:export (pantalaimon-configuration
            pantalaimon-homeserver-configuration
            pantalaimon-service-type))

(define (uglify-field-name field-name)
  (string-trim-right
   (if (eq? field-name 'ssl?)
       "SSL"
       (fold-right string-append ""
                   (map (cut string-upcase <> 0 1)
                        (string-split (symbol->string field-name) #\-))))
   (lambda (c) (eqv? c #\?))))

(define (port-number? val)
  (and (exact-integer? val) (not (negative? val))))

(define (serialize-string field-name value)
  (format #f "~a = ~a\n" (uglify-field-name field-name) value))

(define (serialize-port-number field-name value)
  (format #f "~a = ~a\n" (uglify-field-name field-name) value))

(define (serialize-boolean field-name value)
  (format #f "~a = ~a\n" (uglify-field-name field-name) (if value "True" 
"False")))

(define (serialize-boolean-yn field-name value)
  (if (maybe-value-set? value)
      (format #f "~a = ~a\n" (uglify-field-name field-name) (if value "Yes" 
"No"))
      ""))

(define (serialize-boolean-on-off field-name value)
  (if (maybe-value-set? value)
      (format #f "~a = ~a\n" (uglify-field-name field-name) (if value "On" 
"Off"))
      ""))

(define (serialize-symbol field-name value)
  (if (maybe-value-set? value)
      (format #f "~a = ~a\n" (uglify-field-name field-name) (symbol->string 
value))
      ""))

(define (serialize-name field-name value)
  (format #f "\n[~a]\n" value))

(define-maybe port-number)
(define-maybe string)
(define-maybe boolean)
(define-maybe symbol)

(define-configuration pantalaimon-homeserver-configuration
  (name
   string
   "The name of the proxy instance"
   serialize-name)
  (homeserver
   string
   "The URI of the homeserver that the pantalaimon proxy should forward 
requests to, without the matrix API path but including the http(s) schema.")
  (listen-address
   maybe-string
   "The address where the daemon will listen to client connections for this 
homeserver. Defaults to localhost")
  (listen-port
   maybe-port-number
   "The port where the daemon will listen to client connections for this 
homeserver. Note that the listen address/port combination needs to be unique 
between different homeservers. Defaults to 8009.")
  (proxy
   maybe-string
   "An URI of a HTTP proxy that the daemon should use when making requests to 
the homeserver. pantalaimon only supports HTTP proxies. The default is to make 
a direct connection to the homeserver.")
  (ssl?
   maybe-boolean
   "A boolean that decides if SSL verification should be enabled for outgoing 
connections to the homeserver. Defaults to True.")
  (ignore-verification?
   maybe-boolean
   "A boolean that decides if device verification should be enabled. If this is 
True devices will be marked as ignored automatically and encryption keys will 
be shared with them, if this is False the user needs to verify, blacklist or 
ignore devices manually before messages can be sent to a room. Defaults to 
False.")
  (use-keyring?
   maybe-boolean
   "This option configures if a proxy instance should use the OS keyring to 
store its own access tokens. The access tokens are required for the daemon to 
resume operation. If this is set to No, access tokens are stored in the 
pantalaimon database in plaintext. Defaults to Yes."
   serialize-boolean-yn)
  (drop-old-keys?
   maybe-boolean
   "This option configures if a proxy instance should only keep the latest 
version of a room key from a certain user around. This effectively means that 
only newly incoming messages will be decryptable, the proxy will be unable to 
decrypt the room history. Defaults to No."
   serialize-boolean-yn))

(define (list-of-pantalaimon-homeserver-configurations? lst)
  (every pantalaimon-homeserver-configuration? lst))

(define (serialize-list-of-pantalaimon-homeserver-configurations field-name 
value)
  #~(string-append #$@(map (cut serialize-configuration <>
                                pantalaimon-homeserver-configuration-fields)
                           value)))

(define-configuration pantalaimon-configuration
  (pantalaimon
   (package pantalaimon)
   "The pantalaimon package to use")
  (listen-address
   maybe-string
   "The address where the daemon will listen to client connections for this 
homeserver. Defaults to localhost")
  (listen-port
   maybe-port-number
   "The port where the daemon will listen to client connections for this 
homeserver. Note that the listen address/port combination needs to be unique 
between different homeservers. Defaults to 8009.")
  (proxy
   maybe-string
   "An URI of a HTTP proxy that the daemon should use when making requests to 
the homeserver. pantalaimon only supports HTTP proxies. The default is to make 
a direct connection to the homeserver.")
  (ssl?
   maybe-boolean
   "A boolean that decides if SSL verification should be enabled for outgoing 
connections to the homeserver. Defaults to True.")
  (ignore-verification?
   maybe-boolean
   "A boolean that decides if device verification should be enabled. If this is 
True devices will be marked as ignored automatically and encryption keys will 
be shared with them, if this is False the user needs to verify, blacklist or 
ignore devices manually before messages can be sent to a room. Defaults to 
False.")
  (use-keyring?
   maybe-boolean
   "This option configures if a proxy instance should use the OS keyring to 
store its own access tokens. The access tokens are required for the daemon to 
resume operation. If this is set to No, access tokens are stored in the 
pantalaimon database in plaintext. Defaults to Yes."
   serialize-boolean-yn)
  (notifications?
   maybe-boolean
   "The daemon sends out notifications for some actions that require users to 
interfere (unverified devices are in a room, interactive key verification 
events), this option enables or disables OS notifications. Can be one of On, 
Off. Defaults to On."
   serialize-boolean-on-off)
  (log-level
   maybe-symbol
   "Set the log level of the daemon, can be one of error, warning, info, debug. 
Defaults to warning.")
  (homeservers
   (list-of-pantalaimon-homeserver-configurations '())
   "A list of homeserver configurations."))

(define (pantalaimon-configuration-default-section? configuration)
  (any (lambda (b) b)
       (map maybe-value-set?
            (map (lambda (f) (f configuration))
                 (list pantalaimon-configuration-listen-address
                  pantalaimon-configuration-listen-port
                  pantalaimon-configuration-proxy
                  pantalaimon-configuration-ssl?
                  pantalaimon-configuration-ignore-verification?
                  pantalaimon-configuration-use-keyring?
                  pantalaimon-configuration-notifications?)))))

(define (serialize-pantalaimon-configuration configuration)
  (mixed-text-file
   "pantalaimon.conf"
   #~(string-append #$(if (pantalaimon-configuration-default-section? 
configuration)
                        "[Default]\n"
                        "")
                    #$(serialize-configuration
                       configuration pantalaimon-configuration-fields))))

(define (pantalaimon-shepherd-service config)
  (let ((pantalaimon-bin (file-append
                          (pantalaimon-configuration-pantalaimon config) 
"/bin/pantalaimon")))
    (list (shepherd-service
           (documentation "End-to-End Encryption aware Matrix reverse proxy 
daemon")
           (provision '(pantalaimon))
           (start #~(make-forkexec-constructor `(#$pantalaimon-bin)))
           (stop #~(make-kill-destructor))))))

(define (pantalaimon-xdg-configuration-files config)
  `(("pantalaimon/pantalaimon.conf" ,(serialize-pantalaimon-configuration 
config))))

(define pantalaimon-service-type
  (service-type
   (name 'pantalaimon)
   (extensions
    (list
     (service-extension home-shepherd-service-type
                        pantalaimon-shepherd-service)
     (service-extension home-xdg-configuration-files-service-type
                        pantalaimon-xdg-configuration-files)))
   (description "Pantalaimon is an end-to-end encryption aware Matrix reverse 
proxy daemon. Pantalaimon acts as a good man in the middle that handles the 
encryption for you.

Messages are transparently encrypted and decrypted for clients inside of 
pantalaimon.")))
  

-- 
Kjartan Oli Agustsson
GPG Key fingerprint: 4801 0D71 49C0 1DD6 E5FD  6AC9 D757 2FE3 605E E6B0

Attachment: signature.asc
Description: PGP signature

Reply via email to