Miguel Moreno: 2 system: Add synapse-service-type and mautrix-whatsapp-service-type. rde: Add feature-synapse. Miguel Ángel Moreno: 1 system: Add synapse-service-type and mautrix-whatsapp-service-type. 3 files changed, 1014 insertions(+), 0 deletions(-)
Thank you for working on this, appreciate it.
Hi Andrew, Amended the case name transforms as mentioned in the YAML serializer thread. This <https://issues.guix.gnu.org/62495> patch has been recently merged upstream, so the only withstanding patches needed for this patch series are <https://issues.guix.gnu.org/62284> and <https://issues.guix.gnu.org/62389>. Would you mind having a look at them, please? Over the last months, I've come across many people in the help-guix/IRC channels that are interested in the YAML serializer and the Synapse system service, so we should get the ball rolling on these.
Hi Andrew, Friendly ping on this :)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~abcdw/rde-devel/patches/40029/mbox | git am -3Learn more about email & git
--- src/rde/system/services/matrix.scm | 462 +++++++++++++++++++++++++++++ 1 file changed, 462 insertions(+) create mode 100644 src/rde/system/services/matrix.scm diff --git a/src/rde/system/services/matrix.scm b/src/rde/system/services/matrix.scm new file mode 100644 index 00000000..d153b1a7 --- /dev/null +++ b/src/rde/system/services/matrix.scm @@ -0,0 +1,462 @@ +(define-module (rde system services matrix) + #:use-module (rde features predicates) + #:use-module (rde serializers yaml) + #:use-module (gnu services) + #:use-module (gnu services shepherd) + #:use-module (gnu services configuration) + #:use-module (gnu services databases) + #:use-module (gnu packages admin) + #:use-module (gnu packages matrix) + #:use-module (gnu system accounts) + #:use-module (gnu system shadow) + #:use-module (guix gexp) + #:use-module (srfi srfi-1) + #:use-module (ice-9 match) + #:export (synapse-configuration + synapse-configuration? + synapse-service-type + synapse-extension + mautrix-whatsapp-configuration + mautrix-whatsapp-configuration? + mautrix-whatsapp-service-type)) + +(define-maybe/no-serialization string) + +(define-configuration/no-serialization synapse-configuration + (synapse + (file-like synapse) + "The @code{synapse} package to use.") + (server-name + (string "localhost") + "The public-facing domain of the server. This is used by remote servers to +look up the server address and will appear at the end of usernames and room +addresses created on this server. The @code{server_name} cannot be changed +later so it's important to configure this before you start Synapse. It +should be all lowercase and may contain an explicit port.") + (public-base-url + (string "") + "The public-facing base URL that clients use to access this homeserver.") + (enable-registration? + (boolean #f) + "Whether to enable registration for new users.") + (shared-secret + (string "") + "If set, it allows registration of standard or admin accounts by anyone +who has the shared secret, even if registration is otherwise disabled.") + (secret-key + maybe-string + "A secret which is used to sign access tokens. If none is specified, the +@code{registration_shared_secret} is used, if one is given; otherwise, a +secret key is derived from the signing key.") + (postgresql-db? + (boolean #f) + "Whether to use a PostgreSQL database for storage.") + (postgresql-db-password + maybe-string + "The password for the PostgreSQL database user. Do note this will be +exposed under @file{/gnu/store} in plain sight.") + (max-upload-size + (string "50M") + "The largest allowed upload size in bytes.") + (data-directory + (string "/var/lib/matrix-synapse") + "Indicates the path where data such as the media store and database files +should be stored.") + (config-directory + (string "/var/lib/matrix-synapse") + "Specifies where additional configuration files such as signing keys and +log configuration should be stored.") + (trusted-key-servers + (yaml-config '()) + "The trusted servers to download signing keys from.") + (report-stats? + (boolean #f) + "Indicates whether or not to report anonymized homeserver usage +statistics.") + (extra-config + (yaml-config '()) + "Alist, vector, gexp, or file-like objects to write to a Synapse homeserver +configuration to be placed under @file{homeserver.yaml}. See more settings in +@uref{https://matrix-org.github.io/synapse/latest/usage/configuration/homeserver_sample_config.html}.")) + +(define (synapse-shepherd-service config) + "Returns a Shepherd service for Synapse." + (list + (shepherd-service + (provision '(synapse)) + (requirement (if (synapse-configuration-postgresql-db? config) + '(postgres) + '())) + (start #~(make-forkexec-constructor + (list (string-append #$(synapse-configuration-synapse config) + "/bin/synapse_homeserver") + "-c" + #$(synapse-file config) + "--config-directory" + #$(synapse-configuration-config-directory config) + "--data-directory" + #$(synapse-configuration-data-directory config)) + #:log-file "/var/log/matrix-synapse.log" + #:environment-variables + (list "SSL_CERT_DIR=/etc/ssl/certs" + "SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt"))) + (stop #~(make-kill-destructor))))) + +(define add-synapse-configuration + (match-lambda + (($ <synapse-configuration> _ server-name public-base-url + enable-registration? shared-secret + secret-key postgresql-db? + postgresql-db-password max-upload-size + data-directory config-directory + trusted-key-servers report-stats? + extra-config) + (serialize-yaml-config + `((pid-file . ,(string-append data-directory "/homeserver.pid")) + (server-name . ,server-name) + (public-base-url . ,public-base-url) + (media-store-path . ,(string-append data-directory "/media_store")) + (max-upload-size . ,max-upload-size) + (registration-shared-secret . ,shared-secret) + (macaroon-secret-key . ,(or secret-key shared-secret)) + (signing-key-path . ,(string-append config-directory + "/homeserver.signing.key")) + (enable-registration . ,enable-registration?) + (report-stats . ,report-stats?) + (database . ,(if postgresql-db? + `((name . psycopg2) + (allow-unsafe-locale . #t) + (args . ((user . "matrix-synapse") + (database . "matrix-synapse") + (host . localhost) + (password . ,postgresql-db-password) + (port . 5432) + (cp-min . 5) + (cp-max . 10)))) + `((name . sqlite3) + (args . ((database . ,(string-append + data-directory + "/homeserver.db"))))))) + (listeners . #(((port . 8008) + (tls . #f) + (type . http) + (x-forwarded . true) + (bind-addresses . #("::1" "127.0.0.1")) + (resources . #(((names . (client federation)) + (compress . #f))))))) + (trusted-key-servers . ,(if (null? trusted-key-servers) + #(((server-name . "matrix.org"))) + trusted-key-servers)) + ,@extra-config))))) + +(define %synapse-accounts + (list + (user-group + (name "matrix-synapse") + (system? #t)) + (user-account + (name "matrix-synapse") + (group "matrix-synapse") + (system? #t) + (home-directory "/var/empty") + (shell (file-append shadow "/sbin/nologin"))))) + +(define (synapse-file config) + (mixed-text-file + "homeserver.yaml" + (add-synapse-configuration config))) + +(define (add-synapse-configuration config) + `(("matrix-synapse/homeserver.yaml" + ,(synapse-file config)))) + +(define (synapse-postgresql-service config) + (if (synapse-configuration-postgresql-db? config) + (list + (postgresql-role + (name "matrix-synapse") + (create-database? #t) + (collation "C") + (ctype "C") + (template "template0"))) + '())) + +(define (synapse-activation-service config) + #~(begin + (use-modules (guix build utils)) + + (define %user (getpw "matrix-synapse")) + (define data-dir #$(synapse-configuration-data-directory config)) + (define config-dir #$(synapse-configuration-config-directory config)) + (define signing-key-path + #$(string-append (synapse-configuration-config-directory config) + "/homeserver.signing.key")) + (define (generate-signing-key) + (unless (stat signing-key-path #f) + (system* #$(file-append (synapse-configuration-synapse config) + "/bin/generate_signing_key") + "-o" + signing-key-path))) + + (mkdir-p data-dir) + (chown data-dir (passwd:uid %user) (passwd:gid %user)) + (chmod data-dir #o700) + (mkdir-p config-dir) + (chown config-dir (passwd:uid %user) (passwd:gid %user)) + (chmod config-dir #o700) + (generate-signing-key) + (chown signing-key-path (passwd:uid %user) (passwd:gid %user)) + (chmod signing-key-path #o600))) + +(define-configuration/no-serialization synapse-extension + (extra-config + (yaml-config '()) + "See @code{synapse-service-type} for more information.")) + +(define (synapse-extension-service original-config extension-configs) + (synapse-configuration + (inherit original-config) + (extra-config + (append (synapse-configuration-extra-config original-config) + (append-map synapse-extension-extra-config extension-configs))))) + +(define (generate-synapse-documentation) + (generate-documentation + `((synapse-configuration + ,synapse-configuration-fields)) + 'synapse-configuration)) + +(define synapse-service-type + (service-type + (name 'synapse) + (extensions + (list + (service-extension postgresql-role-service-type + synapse-postgresql-service) + (service-extension etc-service-type + add-synapse-configuration) + (service-extension account-service-type + (const %synapse-accounts)) + (service-extension activation-service-type + synapse-activation-service) + (service-extension shepherd-root-service-type + synapse-shepherd-service))) + (compose identity) + (extend synapse-extension-service) + (default-value (synapse-configuration)) + (description "Configure and run the Synapse Matrix flagship homeserver."))) + +(define-configuration/no-serialization mautrix-whatsapp-configuration + (mautrix-whatsapp + (file-like mautrix-whatsapp) + "The @code{mautrix-whatsapp} package to use.") + (address + (string "http://localhost:8008") + "The address this appservice can use to connect to the homeserver.") + (domain + (string "") + "The domain of the homeserver (for MXIDs, etc).") + (postgresql-db? + (boolean #f) + "Whether to use PostgreSQL as the database type.") + (postgresql-db-password + maybe-string + "The password for the PostgreSQL database user. Note this will be +exposed under @file{/gnu/store} in plain sight.") + (encryption? + (boolean #f) + "Whether to add end-to-bridge encryption support.") + (data-directory + (string "/var/lib/mautrix-whatsapp") + "The path where data such as the registration and database files should +be stored.") + (log-directory + (string "/var/log/mautrix-whatsapp") + "The directory for @code{mautrix-whatsapp} log files.") + (permissions + (alist '()) + "The permissions for using the bridge. Permitted values include: +@itemize +@item relay - Talk through the relaybot (if enabled), no access otherwise +@item user - Access to use the bridge to chat with a WhatsApp account +@item admin - User level and some additional administration tools +@end itemize +Permitted keys include: +@itemize +@item * - All Matrix users +@item domain - All users on that homeserver +@item mxid - Specific user +@end itemize") + (extra-config + (yaml-config '()) + "Alist, vector, gexp, or file-like objects to write to a +@code{mautrix-whatsapp} bridge configuration to be placed under +@file{config.yaml}. See more settings in +@uref{https://github.com/mautrix/whatsapp/blob/master/example-config.yaml}.")) + +(define %mautrix-whatsapp-accounts + (list + (user-group + (name "mautrix-whatsapp") + (system? #t)) + (user-account + (name "mautrix-whatsapp") + (group "mautrix-whatsapp") + (system? #t) + (home-directory "/var/empty") + (shell (file-append shadow "/sbin/nologin"))))) + +(define (mautrix-whatsapp-postgresql-service config) + (if (mautrix-whatsapp-configuration-postgresql-db? config) + (list + (postgresql-role + (name "mautrix-whatsapp") + (create-database? #t) + (collation "C") + (ctype "C") + (template "template0"))) + '())) + +(define add-mautrix-whatsapp-configuration + (match-lambda + (($ <mautrix-whatsapp-configuration> _ address domain postgresql-db? + postgresql-db-password + encryption? data-directory + log-directory permissions + extra-config) + (serialize-yaml-config + `((homeserver . ((address . ,address) + (domain . ,domain))) + ,(cons 'appservice + `((address . "http://localhost:29318") + (hostname . "0.0.0.0") + (port . 29318) + ,(cons + 'database + (if postgresql-db? + `((type . postgres) + ,(cons + 'uri + (string-append + "postgres://mautrix-whatsapp:" + postgresql-db-password + "@localhost/mautrix-whatsapp?sslmode=disable"))) + `((type . sqlite3) + (uri . ,(string-append + data-directory + "/mautrix-whatsapp.db"))))) + (id . whatsapp) + (bot . ((username . whatsappbot) + (displayname . "WhatsApp bridge bot"))) + (as-token . "") + (hs-token . ""))) + ,(cons 'bridge + `((username-template . "whatsapp_{{.}}") + ,(cons + 'displayname-template + (string-append + "{{if .BusinessName}}{{.BusinessName}}" + "{{else if .PushName}}{{.PushName}}" + "{{else}}{{.JID}}{{end}} (WA)")) + (command-prefix . "!wa") + (permissions . (("*" . relay) + ,@permissions)) + (relay . ((enabled . #t) + (admin-only . #t))) + (encryption . ((allow . ,encryption?) + (default . ,encryption?))))) + (logging . ((directory . ,(string-append log-directory "/logs")) + (file-name-format . "{{.Date}}-{{.Index}}.log") + (file-date-format . "2006-01-02") + (file-mode . 0384) + (timestamp-format . "Jan _2, 2006 15:04:05") + (print-level . debug))) + ,@extra-config))))) + +(define (mautrix-whatsapp-synapse-service config) + (synapse-extension + (extra-config + `((app-service-config-files + . #(,(string-append + (mautrix-whatsapp-configuration-data-directory config) + "/registration.yaml"))))))) + +(define (mautrix-whatsapp-activation-service config) + (define mautrix-whatsapp-file + (mixed-text-file + "config.yaml" + #~(add-mautrix-whatsapp-configuration config))) + + #~(begin + (use-modules (guix build utils)) + + (define %user (getpw "mautrix-whatsapp")) + (define data-dir + #$(mautrix-whatsapp-configuration-data-directory config)) + (define log-dir #$(mautrix-whatsapp-configuration-log-directory config)) + (define registration-file (string-append data-dir "/registration.yaml")) + (define config-file (string-append data-dir "/config.yaml")) + (define (generate-registration-file) + (unless (stat registration-file #f) + (copy-file #$mautrix-whatsapp-file config-file) + (system* #$(file-append + (mautrix-whatsapp-configuration-mautrix-whatsapp config) + "/bin/mautrix-whatsapp") + "--generate-registration" + "--config=" config-file + "--registration=" registration-file))) + + (mkdir-p data-dir) + (chown data-dir (passwd:uid %user) (passwd:gid %user)) + (chmod data-dir #o700) + (mkdir-p log-dir) + (chown log-dir (passwd:uid %user) (passwd:gid %user)) + (chmod log-dir #o700) + (generate-registration-file) + (chmod registration-file #o640) + (chown config-file (passwd:uid %user) (passwd:gid %user)))) + +(define (mautrix-whatsapp-shepherd-service config) + (list + (shepherd-service + (provision '(mautrix-whatsapp)) + (requirement '(synapse)) + (start #~(make-forkexec-constructor + (list + (string-append + #$(mautrix-whatsapp-configuration-mautrix-whatsapp config) + "/bin/mautrix-whatsapp") + (string-append + "--config=" + #$(mautrix-whatsapp-configuration-data-directory config) + "/config.yaml") + (string-append + "--registration=" + #$(mautrix-whatsapp-configuration-data-directory config) + "/registration.yaml")) + #:user "mautrix-whatsapp" + #:group "mautrix-whatsapp" + #:log-file "/var/log/mautrix-whatsapp/mautrix-whatsapp.log")) + (stop #~(make-kill-destructor))))) + +(define mautrix-whatsapp-service-type + (service-type + (name 'mautrix-whatsapp) + (extensions + (list + (service-extension account-service-type + (const %mautrix-whatsapp-accounts)) + (service-extension postgresql-role-service-type + mautrix-whatsapp-postgresql-service) + (service-extension synapse-service-type + mautrix-whatsapp-synapse-service) + (service-extension activation-service-type + mautrix-whatsapp-activation-service) + (service-extension shepherd-root-service-type + mautrix-whatsapp-shepherd-service))) + (default-value (mautrix-whatsapp-configuration)) + (description "Configure the Matrix-WhatsApp puppetting bridge. Note that +changing any of the values in @code{mautrix-whatsapp-configuration} requires +regeneration of the registration settings, which you may do by removing +@file{/var/lib/mautrix-whatsapp/registration.yaml} and restarting the +service."))) -- 2.39.2
Miguel Ángel Moreno <contact@conses.eu>Hey Andrew, Please disregard the second patch in this series, since as per <https://lists.sr.ht/~abcdw/rde-devel/patches/39616>, I've decided not to go forward with the nginx+certbot integration, and I feel that a feature is not needed for these services. If you could, would you be able to review <https://issues.guix.gnu.org/62284> and <https://issues.guix.gnu.org/62389>?
-- Best regards, Miguel Moreno
--- * Use original casing for property names src/rde/system/services/matrix.scm | 462 +++++++++++++++++++++++++++++ 1 file changed, 462 insertions(+) create mode 100644 src/rde/system/services/matrix.scm diff --git a/src/rde/system/services/matrix.scm b/src/rde/system/services/matrix.scm new file mode 100644 index 00000000..5556ec9a --- /dev/null +++ b/src/rde/system/services/matrix.scm @@ -0,0 +1,462 @@ +(define-module (rde system services matrix) + #:use-module (rde features predicates) + #:use-module (rde serializers yaml) + #:use-module (gnu services) + #:use-module (gnu services shepherd) + #:use-module (gnu services configuration) + #:use-module (gnu services databases) + #:use-module (gnu packages admin) + #:use-module (gnu packages matrix) + #:use-module (gnu system accounts) + #:use-module (gnu system shadow) + #:use-module (guix gexp) + #:use-module (srfi srfi-1) + #:use-module (ice-9 match) + #:export (synapse-configuration + synapse-configuration? + synapse-service-type + synapse-extension + mautrix-whatsapp-configuration + mautrix-whatsapp-configuration? + mautrix-whatsapp-service-type)) + +(define-maybe/no-serialization string) + +(define-configuration/no-serialization synapse-configuration + (synapse + (file-like synapse) + "The @code{synapse} package to use.") + (server-name + (string "localhost") + "The public-facing domain of the server. This is used by remote servers to +look up the server address and will appear at the end of usernames and room +addresses created on this server. The @code{server_name} cannot be changed +later so it's important to configure this before you start Synapse. It +should be all lowercase and may contain an explicit port.") + (public-base-url + (string "") + "The public-facing base URL that clients use to access this homeserver.") + (enable-registration? + (boolean #f) + "Whether to enable registration for new users.") + (shared-secret + (string "") + "If set, it allows registration of standard or admin accounts by anyone +who has the shared secret, even if registration is otherwise disabled.") + (secret-key + maybe-string + "A secret which is used to sign access tokens. If none is specified, the +@code{registration_shared_secret} is used, if one is given; otherwise, a +secret key is derived from the signing key.") + (postgresql-db? + (boolean #f) + "Whether to use a PostgreSQL database for storage.") + (postgresql-db-password + maybe-string + "The password for the PostgreSQL database user. Do note this will be +exposed under @file{/gnu/store} in plain sight.") + (max-upload-size + (string "50M") + "The largest allowed upload size in bytes.") + (data-directory + (string "/var/lib/matrix-synapse") + "Indicates the path where data such as the media store and database files +should be stored.") + (config-directory
Make all values containing paths to accept file-like too. It will be important after state-management facilities are introduced.
+ (string "/var/lib/matrix-synapse") + "Specifies where additional configuration files such as signing keys and +log configuration should be stored.") + (trusted-key-servers + (yaml-config '()) + "The trusted servers to download signing keys from.") + (report-stats? + (boolean #f) + "Indicates whether or not to report anonymized homeserver usage +statistics.") + (extra-config
Better to name it homeserver-yaml.
+ (yaml-config '()) + "Alist, vector, gexp, or file-like objects to write to a Synapse homeserver +configuration to be placed under @file{homeserver.yaml}. See more settings in +@uref{https://matrix-org.github.io/synapse/latest/usage/configuration/homeserver_sample_config.html}.")) + +(define (synapse-shepherd-service config) + "Returns a Shepherd service for Synapse." + (list + (shepherd-service + (provision '(synapse)) + (requirement (if (synapse-configuration-postgresql-db? config) + '(postgres) + '())) + (start #~(make-forkexec-constructor + (list (string-append #$(synapse-configuration-synapse config) + "/bin/synapse_homeserver") + "-c" + #$(synapse-file config) + "--config-directory" + #$(synapse-configuration-config-directory config) + "--data-directory" + #$(synapse-configuration-data-directory config)) + #:log-file "/var/log/matrix-synapse.log" + #:environment-variables + (list "SSL_CERT_DIR=/etc/ssl/certs" + "SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt"))) + (stop #~(make-kill-destructor))))) + +(define add-synapse-configuration + (match-lambda + (($ <synapse-configuration> _ server-name public-base-url + enable-registration? shared-secret + secret-key postgresql-db? + postgresql-db-password max-upload-size + data-directory config-directory + trusted-key-servers report-stats? + extra-config) + (yaml-serialize + `((pid_file . ,(string-append data-directory "/homeserver.pid")) + (server_name . ,server-name) + (public_base_url . ,public-base-url) + (media_store_path . ,(string-append data-directory "/media_store")) + (max_upload_size . ,max-upload-size) + (registration_shared_secret . ,shared-secret) + (macaroon_secret_key . ,(if (maybe-value-set? secret-key) + secret-key + shared-secret)) + (signing_key_path . ,(string-append config-directory + "/homeserver.signing.key")) + (enable_registration . ,enable-registration?) + (report_stats . ,report-stats?) + (database . ,(if postgresql-db? + `((name . psycopg2) + (allow_unsafe_locale . #t) + (args . ((user . "matrix-synapse") + (database . "matrix-synapse") + (host . localhost) + (password . ,postgresql-db-password) + (port . 5432) + (cp_min . 5) + (cp_max . 10)))) + `((name . sqlite3) + (args . ((database . ,(string-append + data-directory + "/homeserver.db"))))))) + (listeners . #(((port . 8008)
Not a big deal at the moment, but maybe someone would like to adjust those values and it doesn't seem to be possible. https://git.sr.ht/~abcdw/rde/tree/fe90ee80b7a90da3d5d72cc988198eb0f9b44e3e/doc/decision-log/0004-rde-flavor-guix-services.org#L39
+ (tls . #f) + (type . http) + (x_forwarded . true) + (bind_addresses . #("::1" "127.0.0.1")) + (resources . #(((names . (client federation)) + (compress . #f))))))) + (trusted_key_servers . ,(if (null? trusted-key-servers) + #(((server_name . "matrix.org")))
It maybe better to make it a default value for this field. This way people know the format for the field out of example and default value too.
+ trusted-key-servers)) + ,@extra-config))))) + +(define %synapse-accounts + (list + (user-group + (name "matrix-synapse") + (system? #t)) + (user-account + (name "matrix-synapse") + (group "matrix-synapse") + (system? #t) + (home-directory "/var/empty") + (shell (file-append shadow "/sbin/nologin"))))) + +(define (synapse-file config) + (mixed-text-file "homeserver.yaml" + (add-synapse-configuration config))) + +(define (synapse-etc-service config) + `(("matrix-synapse/homeserver.yaml" + ,(synapse-file config)))) + +(define (synapse-postgresql-service config) + (if (synapse-configuration-postgresql-db? config) + (list + (postgresql-role + (name "matrix-synapse") + (create-database? #t) + (collation "C") + (ctype "C") + (template "template0"))) + '())) + +(define (synapse-activation-service config) + #~(begin + (use-modules (guix build utils)) + + (define %user (getpw "matrix-synapse")) + (define data-dir #$(synapse-configuration-data-directory config)) + (define config-dir #$(synapse-configuration-config-directory config)) + (define signing-key-path + #$(string-append (synapse-configuration-config-directory config) + "/homeserver.signing.key")) + (define (generate-signing-key) + (unless (stat signing-key-path #f) + (system* #$(file-append (synapse-configuration-synapse config) + "/bin/generate_signing_key") + "-o" + signing-key-path))) + + (mkdir-p data-dir) + (chown data-dir (passwd:uid %user) (passwd:gid %user)) + (chmod data-dir #o700) + (mkdir-p config-dir) + (chown config-dir (passwd:uid %user) (passwd:gid %user)) + (chmod config-dir #o700) + (generate-signing-key) + (chown signing-key-path (passwd:uid %user) (passwd:gid %user)) + (chmod signing-key-path #o600))) + +(define-configuration/no-serialization synapse-extension + (extra-config
homeserver-yaml
+ (yaml-config '()) + "See @code{synapse-service-type} for more information.")) + +(define (synapse-extension-service original-config extension-configs) + (synapse-configuration + (inherit original-config) + (extra-config + (append (synapse-configuration-extra-config original-config) + (append-map synapse-extension-extra-config extension-configs))))) + +(define (generate-synapse-documentation)
This function can be removed.
+ (generate-documentation + `((synapse-configuration + ,synapse-configuration-fields)) + 'synapse-configuration)) + +(define synapse-service-type + (service-type + (name 'synapse) + (extensions + (list + (service-extension postgresql-role-service-type + synapse-postgresql-service) + (service-extension etc-service-type + synapse-etc-service) + (service-extension account-service-type + (const %synapse-accounts)) + (service-extension activation-service-type + synapse-activation-service) + (service-extension shepherd-root-service-type + synapse-shepherd-service))) + (compose identity) + (extend synapse-extension-service) + (default-value (synapse-configuration)) + (description "Configure and run the Synapse Matrix flagship homeserver."))) +
Better to split it out into a separate patch. The bigger the patch - the harder it to review -> either almost no review done or review becomes very exhaustive and thus always delayed.
+(define-configuration/no-serialization mautrix-whatsapp-configuration + (mautrix-whatsapp + (file-like mautrix-whatsapp) + "The @code{mautrix-whatsapp} package to use.") + (address + (string "http://localhost:8008") + "The address this appservice can use to connect to the homeserver.") + (domain + (string "") + "The domain of the homeserver (for MXIDs, etc).") + (postgresql-db? + (boolean #f) + "Whether to use PostgreSQL as the database type.") + (postgresql-db-password + maybe-string + "The password for the PostgreSQL database user. Note this will be +exposed under @file{/gnu/store} in plain sight.") + (encryption? + (boolean #f) + "Whether to add end-to-bridge encryption support.") + (data-directory
+file-like
+ (string "/var/lib/mautrix-whatsapp") + "The path where data such as the registration and database files should +be stored.") + (log-directory + (string "/var/log/mautrix-whatsapp") + "The directory for @code{mautrix-whatsapp} log files.") + (permissions + (alist '()) + "The permissions for using the bridge. Permitted values include: +@itemize +@item relay - Talk through the relaybot (if enabled), no access otherwise +@item user - Access to use the bridge to chat with a WhatsApp account +@item admin - User level and some additional administration tools +@end itemize +Permitted keys include: +@itemize +@item * - All Matrix users +@item domain - All users on that homeserver +@item mxid - Specific user +@end itemize") + (extra-config
config-yaml
+ (yaml-config '()) + "Alist, vector, gexp, or file-like objects to write to a +@code{mautrix-whatsapp} bridge configuration to be placed under +@file{config.yaml}. See more settings in +@uref{https://github.com/mautrix/whatsapp/blob/master/example-config.yaml}.")) + +(define %mautrix-whatsapp-accounts + (list + (user-group + (name "mautrix-whatsapp") + (system? #t)) + (user-account + (name "mautrix-whatsapp") + (group "mautrix-whatsapp") + (system? #t) + (home-directory "/var/empty") + (shell (file-append shadow "/sbin/nologin"))))) + +(define (mautrix-whatsapp-postgresql-service config) + (if (mautrix-whatsapp-configuration-postgresql-db? config) + (list + (postgresql-role + (name "mautrix-whatsapp") + (create-database? #t) + (collation "C") + (ctype "C") + (template "template0"))) + '())) + +(define add-mautrix-whatsapp-configuration + (match-lambda + (($ <mautrix-whatsapp-configuration> _ address domain postgresql-db? + postgresql-db-password + encryption? data-directory + log-directory permissions + extra-config) + (yaml-serialize + `((homeserver . ((address . ,address) + (domain . ,domain))) + ,(cons 'appservice
The hardcoded things should be overridable.
+ `((address . "http://localhost:29318") + (hostname . "0.0.0.0") + (port . 29318) + ,(cons + 'database + (if postgresql-db? + `((type . postgres) + ,(cons + 'uri + (string-append + "postgres://mautrix-whatsapp:" + postgresql-db-password + "@localhost/mautrix-whatsapp?sslmode=disable"))) + `((type . sqlite3) + (uri . ,(string-append + data-directory + "/mautrix-whatsapp.db"))))) + (id . whatsapp) + (bot . ((username . whatsappbot) + (displayname . "WhatsApp bridge bot"))) + (as_token . "") + (hs_token . ""))) + ,(cons 'bridge + `((username_template . "whatsapp_{{.}}") + ,(cons + 'displayname_template + (string-append + "{{if .BusinessName}}{{.BusinessName}}" + "{{else if .PushName}}{{.PushName}}" + "{{else}}{{.JID}}{{end}} (WA)")) + (command_prefix . "!wa") + (permissions . (("*" . relay) + ,@permissions)) + (relay . ((enabled . #t) + (admin_only . #t))) + (encryption . ((allow . ,encryption?) + (default . ,encryption?))))) + (logging . ((directory . ,(string-append log-directory "/logs")) + (file_name_format . "{{.Date}}-{{.Index}}.log") + (file_date_format . "2006-01-02") + (file_mode . 0384) + (timestamp_format . "Jan _2, 2006 15:04:05") + (print_level . debug))) + ,@extra-config))))) + +(define (mautrix-whatsapp-synapse-service config) + (synapse-extension + (extra-config + `((app_service_config_files + . #(,(string-append + (mautrix-whatsapp-configuration-data-directory config) + "/registration.yaml"))))))) + +(define (mautrix-whatsapp-activation-service config) + (define mautrix-whatsapp-file + (mixed-text-file "config.yaml" + (add-mautrix-whatsapp-configuration config))) + + #~(begin + (use-modules (guix build utils)) + + (define %user (getpw "mautrix-whatsapp")) + (define data-dir + #$(mautrix-whatsapp-configuration-data-directory config)) + (define log-dir #$(mautrix-whatsapp-configuration-log-directory config)) + (define registration-file (string-append data-dir "/registration.yaml")) + (define config-file (string-append data-dir "/config.yaml")) + (define (generate-registration-file) + (unless (stat registration-file #f) + (copy-file #$mautrix-whatsapp-file config-file) + (system* #$(file-append + (mautrix-whatsapp-configuration-mautrix-whatsapp config) + "/bin/mautrix-whatsapp") + "--generate-registration" + "--config=" config-file + "--registration=" registration-file))) + + (mkdir-p data-dir) + (chown data-dir (passwd:uid %user) (passwd:gid %user)) + (chmod data-dir #o700) + (mkdir-p log-dir) + (chown log-dir (passwd:uid %user) (passwd:gid %user)) + (chmod log-dir #o700) + (generate-registration-file) + (chmod registration-file #o640) + (chown config-file (passwd:uid %user) (passwd:gid %user)))) + +(define (mautrix-whatsapp-shepherd-service config) + (list + (shepherd-service + (provision '(mautrix-whatsapp)) + (requirement '(synapse)) + (start #~(make-forkexec-constructor + (list + (string-append + #$(mautrix-whatsapp-configuration-mautrix-whatsapp config) + "/bin/mautrix-whatsapp") + (string-append + "--config=" + #$(mautrix-whatsapp-configuration-data-directory config) + "/config.yaml") + (string-append + "--registration=" + #$(mautrix-whatsapp-configuration-data-directory config) + "/registration.yaml")) + #:user "mautrix-whatsapp" + #:group "mautrix-whatsapp" + #:log-file "/var/log/mautrix-whatsapp/mautrix-whatsapp.log")) + (stop #~(make-kill-destructor))))) + +(define mautrix-whatsapp-service-type + (service-type + (name 'mautrix-whatsapp) + (extensions + (list + (service-extension account-service-type + (const %mautrix-whatsapp-accounts)) + (service-extension postgresql-role-service-type + mautrix-whatsapp-postgresql-service) + (service-extension synapse-service-type + mautrix-whatsapp-synapse-service) + (service-extension activation-service-type + mautrix-whatsapp-activation-service) + (service-extension shepherd-root-service-type + mautrix-whatsapp-shepherd-service))) + (default-value (mautrix-whatsapp-configuration)) + (description "Configure the Matrix-WhatsApp puppetting bridge. Note that +changing any of the values in @code{mautrix-whatsapp-configuration} requires +regeneration of the registration settings, which you may do by removing +@file{/var/lib/mautrix-whatsapp/registration.yaml} and restarting the +service."))) -- 2.41.0 -- Best regards, Miguel Ángel Moreno
Thank you for working on this, appreciate it.
Hi Andrew, Amended the case name transforms as mentioned in the YAML serializer thread. This <https://issues.guix.gnu.org/62495> patch has been recently merged upstream, so the only withstanding patches needed for this patch series are <https://issues.guix.gnu.org/62284> and <https://issues.guix.gnu.org/62389>. Would you mind having a look at them, please? Over the last months, I've come across many people in the help-guix/IRC channels that are interested in the YAML serializer and the Synapse system service, so we should get the ball rolling on these.
--- src/rde/features/matrix.scm | 90 +++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/rde/features/matrix.scm diff --git a/src/rde/features/matrix.scm b/src/rde/features/matrix.scm new file mode 100644 index 00000000..9200d9cb --- /dev/null +++ b/src/rde/features/matrix.scm @@ -0,0 +1,90 @@ +(define-module (rde features matrix) + #:use-module (rde features) + #:use-module (rde features emacs) + #:use-module (rde features predicates) + #:use-module (rde features web) + #:use-module (rde home services matrix) + #:use-module (rde system services matrix) + #:use-module (gnu home services) + #:use-module (gnu services) + #:use-module (gnu services certbot) + #:use-module (gnu services configuration) + #:use-module (gnu services web) + #:use-module (gnu packages emacs-xyz) + #:use-module (gnu packages matrix) + #:use-module (guix gexp) + #:use-module (srfi srfi-1) + #:export (feature-synapse)) + +(define* (feature-synapse + #:key + (whatsapp-bridge? #f)) + "Set up a live instance of the Synapse Matrix flagship home server. +If WHATSAPP-BRIDGE?, configure the @code{mautrix-whatsapp} puppetting +bridge to relay messages to/from WhatsApp." + (ensure-pred boolean? whatsapp-bridge?) + + (define (get-system-services config) + "Return system services related to Synapse." + (require-value 'matrix-settings config) + (define homeserver (get-value 'matrix-homeserver config)) + (define server-name + (string-drop homeserver (+ 1 (string-index-right homeserver #\/)))) + (define domain + (string-drop server-name (+ 1 (string-index server-name #\.)))) + (define letsencrypt-dir + (and domain (string-append "/etc/letsencrypt/live/matrix." domain))) + + (append + (list + (service synapse-service-type + (get-value 'synapse-configuration config))) + (if whatsapp-bridge? + (list + (service mautrix-whatsapp-service-type + (get-value 'mautrix-whatsapp-configuration config))) + '()) + (if (get-value 'nginx config) + (list + (simple-service + 'add-synapse-nginx-configuration + nginx-service-type + (list + (nginx-server-configuration + (listen '("443 ssl http2" + "[::]:443 ssl http2" + "8448 ssl http2 default_server" + "[::]:8448 ssl http2 default_server")) + (server-name (list server-name)) + (ssl-certificate + (string-append letsencrypt-dir "/fullchain.pem")) + (ssl-certificate-key + (string-append letsencrypt-dir "/privkey.pem")) + (locations + (list + (nginx-location-configuration + (uri "~ ^(/_matrix|/_synapse/client)") + (body + (list "proxy_pass http://localhost:8008;" + "proxy_set_header X-Forwarded-For $remote_addr;" + "proxy_set_header X-Forwarded-Proto $scheme;" + "proxy_set_header Host $host;" + "client_max_body_size 50M;"))) + %letsencrypt-acme-challenge)))))) + '()) + (if (get-value 'certbot config) + (list + (simple-service + 'add-synapse-ssl + certbot-service-type + (list + (certificate-configuration + (domains (list server-name)) + (deploy-hook %nginx-deploy-hook))))) + '()))) + + (feature + (name 'synapse) + (values `((synapse . #t) + (matrix-whatsapp-bridge? . ,whatsapp-bridge?))) + (system-services-getter get-system-services))) -- 2.39.2 -- Best regards, Miguel Moreno