;; disfluid, implementation of the Solid specification
;; Copyright (C) 2020, 2021 Vivien Kraus
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU Affero General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU Affero General Public License for more details.
;; You should have received a copy of the GNU Affero General Public License
;; along with this program. If not, see .
(define-module (vkraus services disfluid)
#:use-module (gnu services)
#:use-module (gnu services shepherd)
#:use-module (gnu services admin)
#:use-module (gnu services web)
#:use-module (gnu system shadow)
#:use-module (gnu packages admin)
#:use-module (vkraus packages disfluid)
#:use-module (guix gexp)
#:use-module (guix modules)
#:use-module (guix records)
#:use-module (ice-9 match)
#:use-module (ice-9 optargs))
(define-record-type*
disfluid-issuer-configuration
make-disfluid-issuer-configuration
disfluid-issuer-configuration?
(disfluid disfluid-issuer-configuration-disfluid
(default disfluid))
(complete-corresponding-source
disfluid-issuer-configuration-complete-corresponding-source)
(issuer disfluid-issuer-configuration-issuer)
(key-file disfluid-issuer-configuration-key-file)
(subject disfluid-issuer-configuration-subject)
(encrypted-password-file disfluid-issuer-configuration-encrypted-password-file)
(jwks-uri disfluid-issuer-configuration-jwks-uri)
(authorization-endpoint-uri
disfluid-issuer-configuration-authorization-endpoint-uri)
(token-endpoint-uri
disfluid-issuer-configuration-token-endpoint-uri)
(port disfluid-issuer-configuration-port (default 8088))
(extra-options
disfluid-issuer-configuration-extra-options
(default '())))
(define-record-type*
disfluid-reverse-proxy-configuration
make-disfluid-reverse-proxy-configuration
disfluid-reverse-proxy-configuration?
(disfluid disfluid-reverse-proxy-configuration-disfluid
(default disfluid))
(complete-corresponding-source
disfluid-reverse-proxy-configuration-complete-corresponding-source)
(port disfluid-reverse-proxy-port (default 8090))
(inbound-uri disfluid-reverse-proxy-configuration-inbound-uri)
(outbound-uri disfluid-reverse-proxy-configuration-outbound-uri)
(header disfluid-reverse-proxy-configuration-header
(default "XXX-Agent"))
(extra-options
disfluid-reverse-proxy-extra-options
(default '())))
(define-record-type*
disfluid-hello-configuration
make-disfluid-hello-configuration
disfluid-hello-configuration?
(disfluid disfluid-hello-configuration-disfluid
(default disfluid))
(complete-corresponding-source
disfluid-hello-configuration-complete-corresponding-source)
(port disfluid-hello-configuration-port (default 8089))
(extra-options
disfluid-hello-configuration-extra-options
(default '())))
(define-record-type*
disfluid-client-service-configuration
make-disfluid-client-service-configuration
disfluid-client-service-configuration?
(disfluid disfluid-client-service-configuration-disfluid
(default disfluid))
(complete-corresponding-source
disfluid-client-service-configuration-complete-corresponding-source)
(client-id disfluid-client-service-configuration-client-id)
(redirect-uri disfluid-client-service-configuration-redirect-uri)
(client-name disfluid-client-service-configuration-client-name (default "Example Solid App"))
(client-uri disfluid-client-service-configuration-client-uri (default "https://webid-oidc.planete-kraus.eu/Running-a-client.html#Running-a-client"))
(port disfluid-client-service-configuration-port (default 8088))
(extra-options
disfluid-client-service-configuration-extra-options
(default '())))
(define-record-type*
disfluid-server-configuration
make-disfluid-server-configuration
disfluid-server-configuration?
(disfluid disfluid-server-configuration-disfluid
(default disfluid))
(complete-corresponding-source
disfluid-server-configuration-complete-corresponding-source)
(server-name disfluid-server-configuration-server-name)
(key-file disfluid-server-configuration-key-file)
(subject disfluid-server-configuration-subject)
(encrypted-password-file disfluid-server-configuration-encrypted-password-file)
(jwks-uri disfluid-server-configuration-jwks-uri)
(authorization-endpoint-uri
disfluid-server-configuration-authorization-endpoint-uri)
(token-endpoint-uri
disfluid-server-configuration-token-endpoint-uri)
(port disfluid-server-configuration-port (default 8088))
(extra-options
disfluid-issuer-configuration-extra-options
(default '())))
(export
disfluid-issuer-configuration
make-disfluid-issuer-configuration
disfluid-issuer-configuration?
disfluid-issuer-configuration-disfluid
disfluid-issuer-configuration-complete-corresponding-source
disfluid-issuer-configuration-issuer
disfluid-issuer-configuration-key-file
disfluid-issuer-configuration-subject
disfluid-issuer-configuration-encrypted-password-file
disfluid-issuer-configuration-jwks-uri
disfluid-issuer-configuration-authorization-endpoint-uri
disfluid-issuer-configuration-token-endpoint-uri
disfluid-issuer-configuration-port
disfluid-issuer-configuration-extra-options
disfluid-reverse-proxy-configuration
make-disfluid-reverse-proxy-configuration
disfluid-reverse-proxy-configuration?
disfluid-reverse-proxy-configuration-disfluid
disfluid-reverse-proxy-configuration-complete-corresponding-source
disfluid-reverse-proxy-configuration-port
disfluid-reverse-proxy-configuration-inbound-uri
disfluid-reverse-proxy-configuration-outbound-uri
disfluid-reverse-proxy-configuration-header
disfluid-reverse-proxy-configuration-extra-options
disfluid-hello-configuration
make-disfluid-hello-configuration
disfluid-hello-configuration?
disfluid-hello-configuration-disfluid
disfluid-hello-configuration-complete-corresponding-source
disfluid-hello-configuration-port
disfluid-hello-configuration-extra-options
disfluid-client-service-configuration
make-disfluid-client-service-configuration
disfluid-client-service-configuration?
disfluid-client-service-configuration-disfluid
disfluid-client-service-configuration-complete-corresponding-source
disfluid-client-service-configuration-client-id
disfluid-client-service-configuration-redirect-uri
disfluid-client-service-configuration-client-name
disfluid-client-service-configuration-client-uri
disfluid-client-service-configuration-port
disfluid-client-service-configuration-extra-options
disfluid-server-configuration
make-disfluid-server-configuration
disfluid-server-configuration?
disfluid-server-configuration-disfluid
disfluid-server-configuration-complete-corresponding-source
disfluid-server-configuration-server-name
disfluid-server-configuration-key-file
disfluid-server-configuration-subject
disfluid-server-configuration-encrypted-password-file
disfluid-server-configuration-jwks-uri
disfluid-server-configuration-authorization-endpoint-uri
disfluid-server-configuration-token-endpoint-uri
disfluid-server-configuration-port
disfluid-server-configuration-extra-options)
(define configuration->shepherd-service
(match-lambda
((id . ($
disfluid ccs issuer key-file subject encrypted-password-file jwks-uri
authorization-endpoint-uri token-endpoint-uri port extra-options))
`(,(shepherd-service
(provision (list (string->symbol (format #f "disfluid-~a" id))))
(documentation (format #f "Run a Solid identity provider (~a)" id))
(requirement '(user-processes))
(modules '((gnu build shepherd)
(gnu system file-systems)))
(start
(with-imported-modules
(source-module-closure
'((gnu build shepherd)
(gnu system file-systems)))
#~(begin
(let* ((user (getpwnam "disfluid"))
(prepare-directory
(lambda (dir)
(mkdir-p dir)
(chown dir (passwd:uid user) (passwd:gid user))
(chmod dir #o700))))
(prepare-directory "/var/log/disfluid")
(prepare-directory #$(format #f "/var/lib/disfluid/~a" id))
(prepare-directory #$(format #f "/var/cache/disfluid/~a" id)))
(make-forkexec-constructor
(list
(string-append #$disfluid "/bin/disfluid")
"identity-provider"
"--complete-corresponding-source" #$ccs
"--server-name" #$issuer
"--key-file" #$key-file
"--subject" #$subject
"--encrypted-password-from-file" #$encrypted-password-file
"--jwks-uri" #$jwks-uri
"--authorization-endpoint-uri" #$authorization-endpoint-uri
"--token-endpoint-uri" #$token-endpoint-uri
"--port" (with-output-to-string (lambda () (display #$port)))
"--log-file" #$(format #f "issuer-~a.log" id)
"--error-file" #$(format #f "issuer-~a.err" id)
#$@extra-options)
#:user "disfluid"
#:group "disfluid"
#:directory "/var/log/disfluid"
#:environment-variables
'(#$(format #f "XDG_DATA_HOME=/var/lib/disfluid/~a" id)
#$(format #f "XDG_CACHE_HOME=/var/cache/disfluid/~a" id)
"LANG=C")))))
(stop #~(make-kill-destructor)))))
((id . ($
disfluid ccs port inbound-uri outbound-uri header extra-options))
`(,(shepherd-service
(provision (list (string->symbol (format #f "disfluid-~a" id))))
(documentation (format #f "Run a Solid reverse proxy (~a)" id))
(requirement '(user-processes))
(modules '((gnu build shepherd)
(gnu system file-systems)))
(start
(with-imported-modules
(source-module-closure
'((gnu build shepherd)
(gnu system file-systems)))
#~(begin
(let* ((user (getpwnam "disfluid"))
(prepare-directory
(lambda (dir)
(mkdir-p dir)
(chown dir (passwd:uid user) (passwd:gid user))
(chmod dir #o700))))
(prepare-directory "/var/log/disfluid")
(prepare-directory #$(format #f "/var/lib/disfluid/~a" id))
(prepare-directory #$(format #f "/var/cache/disfluid/~a" id)))
(make-forkexec-constructor
(list
(string-append #$disfluid "/bin/disfluid")
"reverse-proxy"
"--complete-corresponding-source" #$ccs
"--port" (with-output-to-string (lambda () (display #$port)))
"--server-name" #$inbound-uri
"--backend-uri" #$outbound-uri
"--header" #$header
"--log-file" #$(format #f "reverse-proxy-~a.log" id)
"--error-file" #$(format #f "reverse-proxy-~a.err" id)
#$@extra-options)
#:user "disfluid"
#:group "disfluid"
#:directory "/var/log/disfluid"
#:environment-variables
'(#$(format #f "XDG_DATA_HOME=/var/lib/disfluid/~a" id)
#$(format #f "XDG_CACHE_HOME=/var/cache/disfluid/~a" id)
"LANG=C")))))
(stop #~(make-kill-destructor)))))
((id . ($
disfluid ccs port extra-options))
`(,(shepherd-service
(provision (list (string->symbol (format #f "disfluid-~a" id))))
(documentation (format #f "Run a demonstration Solid server (~a)" id))
(requirement '(user-processes))
(modules '((gnu build shepherd)
(gnu system file-systems)))
(start
(with-imported-modules
(source-module-closure
'((gnu build shepherd)
(gnu system file-systems)))
#~(begin
(let* ((user (getpwnam "disfluid"))
(prepare-directory
(lambda (dir)
(mkdir-p dir)
(chown dir (passwd:uid user) (passwd:gid user))
(chmod dir #o700))))
(prepare-directory "/var/log/disfluid")
(prepare-directory #$(format #f "/var/lib/disfluid/~a" id))
(prepare-directory #$(format #f "/var/cache/disfluid/~a" id)))
(make-forkexec-constructor
(list
(string-append #$disfluid "/bin/disfluid-hello")
"--complete-corresponding-source" #$ccs
"--port" (with-output-to-string (lambda () (display #$port)))
"--log-file" #$(format #f "hello-~a.log" id)
"--error-file" #$(format #f "hello-~a.err" id)
#$@extra-options)
#:user "disfluid"
#:group "disfluid"
#:directory "/var/log/disfluid"
#:environment-variables
'(#$(format #f "XDG_DATA_HOME=/var/lib/disfluid/~a" id)
#$(format #f "XDG_CACHE_HOME=/var/cache/disfluid/~a" id)
"LANG=C")))))
(stop #~(make-kill-destructor)))))
((id . ($
disfluid ccs client-id redirect-uri client-name client-uri port
extra-options))
`(,(shepherd-service
(provision (list (string->symbol (format #f "disfluid-~a" id))))
(documentation (format #f "Serve the public page for an application (~a)" id))
(requirement '(user-processes))
(modules '((gnu build shepherd)
(gnu system file-systems)))
(start
(with-imported-modules
(source-module-closure
'((gnu build shepherd)
(gnu system file-systems)))
#~(begin
(let* ((user (getpwnam "disfluid"))
(prepare-directory
(lambda (dir)
(mkdir-p dir)
(chown dir (passwd:uid user) (passwd:gid user))
(chmod dir #o700))))
(prepare-directory "/var/log/disfluid")
(prepare-directory #$(format #f "/var/lib/disfluid/~a" id))
(prepare-directory #$(format #f "/var/cache/disfluid/~a" id)))
(make-forkexec-constructor
(list
(string-append #$disfluid "/bin/disfluid")
"client-service"
"--complete-corresponding-source" #$ccs
"--client-id" #$client-id
"--redirect-uri" #$redirect-uri
"--client-name" #$client-name
"--client-uri" #$client-uri
"--port" (with-output-to-string (lambda () (display #$port)))
"--log-file" #$(format #f "client-service-~a.log" id)
"--error-file" #$(format #f "client-service-~a.err" id)
#$@extra-options)
#:user "disfluid"
#:group "disfluid"
#:directory "/var/log/disfluid"
#:environment-variables
'(#$(format #f "XDG_DATA_HOME=/var/lib/disfluid/~a" id)
#$(format #f "XDG_CACHE_HOME=/var/cache/disfluid/~a" id)
"LANG=C")))))
(stop #~(make-kill-destructor)))))
((id . ($
disfluid ccs server-name key-file subject encrypted-password-file jwks-uri
authorization-endpoint-uri token-endpoint-uri port
extra-options))
`(,(shepherd-service
(provision (list (string->symbol (format #f "disfluid-~a" id))))
(documentation (format #f "Run a full server (~a)" id))
(requirement '(user-processes))
(modules '((gnu build shepherd)
(gnu system file-systems)))
(start
(with-imported-modules
(source-module-closure
'((gnu build shepherd)
(gnu system file-systems)))
#~(begin
(let* ((user (getpwnam "disfluid"))
(prepare-directory
(lambda (dir)
(mkdir-p dir)
(chown dir (passwd:uid user) (passwd:gid user))
(chmod dir #o700))))
(prepare-directory "/var/log/disfluid")
(prepare-directory #$(format #f "/var/lib/disfluid/~a" id))
(prepare-directory #$(format #f "/var/cache/disfluid/~a" id)))
(make-forkexec-constructor
(list
(string-append #$disfluid "/bin/disfluid")
"server"
"--complete-corresponding-source" #$ccs
"--server-name" #$server-name
"--key-file" #$key-file
"--subject" #$subject
"--encrypted-password-from-file" #$encrypted-password-file
"--jwks-uri" #$jwks-uri
"--authorization-endpoint-uri" #$authorization-endpoint-uri
"--token-endpoint-uri" #$token-endpoint-uri
"--port" (with-output-to-string (lambda () (display #$port)))
"--log-file" #$(format #f "server-~a.log" id)
"--error-file" #$(format #f "server-~a.err" id)
#$@extra-options)
#:user "disfluid"
#:group "disfluid"
#:directory "/var/log/disfluid"
#:environment-variables
'(#$(format #f "XDG_DATA_HOME=/var/lib/disfluid/~a" id)
#$(format #f "XDG_CACHE_HOME=/var/cache/disfluid/~a" id)
"LANG=C")))))
(stop #~(make-kill-destructor)))))
((items ...)
(apply append (map configuration->shepherd-service items)))))
(define %disfluid-accounts
(list (user-group (name "disfluid")
(system? #t))
(user-account
(name "disfluid")
(group "disfluid")
(system? #t)
(comment "The user that runs the disfluid servers.")
(home-directory "/var/empty")
(shell (file-append shadow "/sbin/nologin")))))
(define configuration->log-rotation
(match-lambda
((id . ($ ))
`(,(log-rotation
(frequency 'daily)
(files
(map (lambda (ext)
(format #f "/var/log/disfluid/issuer-~a.~a" id ext))
'("log err")))
(options '("sharedscripts" "storedir /var/log/disfluid")))))
((id . ($ ))
`(,(log-rotation
(frequency 'daily)
(files
(map (lambda (ext)
(format #f "/var/log/disfluid/reverse-proxy-~a.~a" id ext))
'("log err")))
(options '("sharedscripts" "storedir /var/log/disfluid")))))
((id . ($ ))
`(,(log-rotation
(frequency 'daily)
(files
(map (lambda (ext)
(format #f "/var/log/disfluid/hello-~a.~a" id ext))
'("log err")))
(options '("sharedscripts" "storedir /var/log/disfluid")))))
((id . ($ ))
`(,(log-rotation
(frequency 'daily)
(files
(map (lambda (ext)
(format #f "/var/log/disfluid/client-service-~a.~a" id ext))
'("log err")))
(options '("sharedscripts" "storedir /var/log/disfluid")))))
((id . ($ ))
`(,(log-rotation
(frequency 'daily)
(files
(map (lambda (ext)
(format #f "/var/log/disfluid/server-~a.~a" id ext))
'("log err")))
(options '("sharedscripts" "storedir /var/log/disfluid")))))
((items ...)
(apply append (map configuration->log-rotation items)))))
(define-public disfluid-service-type
(service-type
(name 'disfluid)
(extensions
(list
(service-extension account-service-type
(const %disfluid-accounts))
(service-extension rottlog-service-type
configuration->log-rotation)
(service-extension
shepherd-root-service-type
configuration->shepherd-service)))))
(define-public disfluid-website
(nginx-server-configuration
(server-name '("disfluid.planete-kraus.eu" "webid-oidc.planete-kraus.eu"))
(listen '("443 ssl" "[::]:443 ssl"))
(ssl-certificate "/etc/letsencrypt/live/planete-kraus.eu/fullchain.pem")
(ssl-certificate-key "/etc/letsencrypt/live/planete-kraus.eu/privkey.pem")
(root disfluid:website)
(locations
(list
(nginx-location-configuration
(uri "/project")
(body
(list "default_type text/turtle ;")))))))