gnu: services: Add mollysocket service.

* gnu/services/messaging.scm (ms-format,ms-serialize-string,
ms-serialize-integer, ms-serialize-boolean,
ms-serialize-list-of-strings, mollysocket-shepherd-service,
mollysocket-account-service, mollysocket-activation-service): New
procedures.
(mollysocket-configuration): New configuration.
(mollysocket-service-type): New variable.
* doc/guix.texi (Messaging Services)[Mollysocket Service]: New section.

Change-Id: I87d57b69a6d8fa8841a95add084aa383385de4c7
This commit is contained in:
Lilah Tascheter 2025-10-21 14:13:59 -05:00 committed by Efraim Flashner
parent 368d2d9e0f
commit 7fb7d071cf
No known key found for this signature in database
GPG key ID: 41AAE7DCCA3D8351
2 changed files with 148 additions and 1 deletions

View file

@ -31777,6 +31777,50 @@ Owner's group of the broker process.
@end table
@end deftp
@subsubheading Mollysocket Service
@url{https://github.com/mollyim/mollysocket,Mollysocket} is a UnifiedPush
provider for the messaging app @url{https://molly.im,Molly}, a fork of Signal.
@defvar mollysocket-service-type
The Mollysocket service. Takes @code{mollysocket-configuration} as its value.
By default, this service listens on port 8020 for any Molly client.
@end defvar
@deftp {Data Type} mollysocket-configuration
The configuration for Mollysocket, with the following fields:
@table @asis
@item @code{package} (default: @code{mollysocket})
The Mollysocket package to use.
@item @code{host} (default: @code{"0.0.0.0"})
Address for the webserver to listen on. It is recommended that this be set to
localhost, and instead configure a TLS-supporting reverse proxy in front of it.
@item @code{port} (default: @code{8020})
Port for the webserver to listen on.
@item @code{webserver} (default: @code{#t})
Whether the webserver sould be enabled. If disabled, the server is considered to
be in airgapped mode, and clients must be configured likewise.
@item @code{allowed-endpoints} (default: @code{'("*")})
Allowlist of UnifiedPush distributor endpoints, represented as IP addresses or
domain names. Addresses on the local network must be specified explicitly.
@item @code{allowed-uuids} (default: @code{'("*")})
Allowlist of Signal account UUIDs.
@item @code{db} (default: @code{"/var/lib/mollysocket/db.sqlite"})
Path to the Mollysocket database. Will be created if it doesn't exist.
@item @code{vapid-key-file} (default: @code{"/var/lib/mollysocket/vapid.key"})
Path to the VAPID key used to authorize requests to the UnifiedPush distributor.
Will be created if it doesn't exist.
@end table
@end deftp
@node Telephony Services
@subsection Telephony Services

View file

@ -27,6 +27,7 @@
#:use-module (gnu packages base)
#:use-module (gnu packages irc)
#:use-module (gnu packages messaging)
#:autoload (gnu packages rust-apps) (mollysocket)
#:use-module (gnu packages tls)
#:use-module (gnu services)
#:use-module (gnu services shepherd)
@ -196,7 +197,18 @@
mosquitto-configuration-config-file
mosquitto-configuration-user
mosquitto-configuration-group
mosquitto-service-type))
mosquitto-service-type
mollysocket-configuration
mollysocket-configuration?
mollysocket-configuration-host
mollysocket-configuration-port
mollysocket-configuration-webserver
mollysocket-configuration-allowed-endpoints
mollysocket-configuration-allowed-uuids
mollysocket-configuration-db
mollysocket-configuration-vapid-key-file
mollysocket-service-type))
;;; Commentary:
;;;
@ -2283,3 +2295,94 @@ multiple machines simultaneously.")))
(const %snuik-accounts))
(service-extension shepherd-root-service-type
snuik-services)))))
;;;
;;; Mollysocket.
;;;
(define (ms-format label str)
(format #f "~a = ~a~%" label (string-map (match-lambda (#\- #\_) (x x)) str)))
(define (ms-serialize-string label val)
(ms-format label (string-append "'" val "'")))
(define (ms-serialize-integer label val)
(ms-format label (number->string val)))
(define (ms-serialize-boolean label val)
(ms-format label (if val "true" "false")))
(define (ms-serialize-list-of-strings label val)
(ms-format label (format #f "[ ~{'~a'~^, ~} ]" val)))
(define-configuration mollysocket-configuration
(package (file-like mollysocket) "Mollysocket package to use."
(serializer empty-serializer))
(host (string "127.0.0.1") "Listening address. It is recommended to connect
to Mollysocket through a TLS-supporting reverse proxy.")
(port (integer 8020) "Listening port.")
(webserver (boolean #t) "Enable webserver. If disabled, clients must use
airgapped mode.")
(allowed-endpoints (list-of-strings '("*")) "Allowlist of UnifiedPush
distributor endpoints, represented as IP addresses or domain names. Addresses
on the local network must be specified explicitly.")
(allowed-uuids (list-of-strings '("*")) "Allowlist of Signal account UUIDs.")
(db (string "/var/lib/mollysocket/db.sqlite") "Path to the database. Will be
created if it does not exist.")
(vapid-key-file (string "/var/lib/mollysocket/vapid.key") "Path to the VAPID
key used to authorize requests to the UnifiedPush distributor. Will be created
if it does not exist.")
(prefix ms-))
(define (mollysocket-shepherd-service config)
(list (shepherd-service
(documentation "UnifiedPush provider for the Signal client Molly.")
(provision '(mollysocket))
(requirement '(networking syslogd user-processes))
(start #~(make-forkexec-constructor
(list #$(file-append mollysocket "/bin/mollysocket")
"-c" #$(mixed-text-file "mollysocket.toml"
(serialize-configuration config
mollysocket-configuration-fields))
"server")
#:user "mollysocket" #:group "mollysocket"
#:log-file "/var/log/mollysocket.log"))
(stop #~(make-kill-destructor SIGINT)))))
(define (mollysocket-account-service config)
(list (user-group (name "mollysocket") (system? #t))
(user-account
(name "mollysocket")
(group "mollysocket")
(system? #t)
(comment "Mollysocket daemon user")
(home-directory "/var/empty")
(shell (file-append shadow "/sbin/nologin")))))
(define (mollysocket-activation-service config)
#~(let* ((mollysocket #$(file-append
(mollysocket-configuration-package config)
"/bin/mollysocket"))
(user (getpwnam "mollysocket"))
(key #$(mollysocket-configuration-vapid-key-file config))
(dbdir (dirname #$(mollysocket-configuration-db config)))
(keydir (dirname key)))
(define (create file proc mode)
(let ((ret (proc file)))
(chmod file mode)
(chown file (passwd:uid user) (passwd:gid user))
ret))
(unless (file-exists? dbdir) (create dbdir mkdir-p #o700))
(unless (file-exists? keydir) (create keydir mkdir-p #o700))
(unless (file-exists? key)
(let ((p (create key open-output-file #o600))) ; restrict then write
(with-output-to-port p (lambda () (invoke mollysocket "vapid" "gen")))
(close-port p)))))
(define mollysocket-service-type
(service-type
(name 'mollysocket)
(extensions (list (service-extension shepherd-root-service-type
mollysocket-shepherd-service)
(service-extension account-service-type
mollysocket-account-service)
(service-extension activation-service-type
mollysocket-activation-service)))
(default-value (mollysocket-configuration))
(description "UnifiedPush provider for the Signal client Molly.")))