parent
a31a917eb9
commit
db846a88a8
@ -0,0 +1,958 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
cfg = config.services.codimd; |
||||
|
||||
prettyJSON = conf: |
||||
pkgs.runCommand "codimd-config.json" { } '' |
||||
echo '${builtins.toJSON conf}' | ${pkgs.jq}/bin/jq \ |
||||
'{production:del(.[]|nulls)|del(.[][]?|nulls)}' > $out |
||||
''; |
||||
in |
||||
{ |
||||
options.services.codimd = { |
||||
enable = mkEnableOption "the CodiMD Markdown Editor"; |
||||
|
||||
groups = mkOption { |
||||
type = types.listOf types.str; |
||||
default = []; |
||||
description = '' |
||||
Groups to which the codimd user should be added. |
||||
''; |
||||
}; |
||||
|
||||
workDir = mkOption { |
||||
type = types.path; |
||||
default = "/var/lib/codimd"; |
||||
description = '' |
||||
Working directory for the CodiMD service. |
||||
''; |
||||
}; |
||||
|
||||
configuration = { |
||||
debug = mkEnableOption "debug mode"; |
||||
domain = mkOption { |
||||
type = types.nullOr types.str; |
||||
default = null; |
||||
example = "codimd.org"; |
||||
description = '' |
||||
Domain name for the CodiMD instance. |
||||
''; |
||||
}; |
||||
urlPath = mkOption { |
||||
type = types.nullOr types.str; |
||||
default = null; |
||||
example = "/url/path/to/codimd"; |
||||
description = '' |
||||
Path under which CodiMD is accessible. |
||||
''; |
||||
}; |
||||
host = mkOption { |
||||
type = types.str; |
||||
default = "localhost"; |
||||
description = '' |
||||
Address to listen on. |
||||
''; |
||||
}; |
||||
port = mkOption { |
||||
type = types.int; |
||||
default = 3000; |
||||
example = "80"; |
||||
description = '' |
||||
Port to listen on. |
||||
''; |
||||
}; |
||||
path = mkOption { |
||||
type = types.nullOr types.str; |
||||
default = null; |
||||
example = "/var/run/codimd.sock"; |
||||
description = '' |
||||
Specify where a UNIX domain socket should be placed. |
||||
''; |
||||
}; |
||||
allowOrigin = mkOption { |
||||
type = types.listOf types.str; |
||||
default = []; |
||||
example = [ "localhost" "codimd.org" ]; |
||||
description = '' |
||||
List of domains to whitelist. |
||||
''; |
||||
}; |
||||
useSSL = mkOption { |
||||
type = types.bool; |
||||
default = false; |
||||
description = '' |
||||
Enable to use SSL server. This will also enable |
||||
<option>protocolUseSSL</option>. |
||||
''; |
||||
}; |
||||
hsts = { |
||||
enable = mkOption { |
||||
type = types.bool; |
||||
default = true; |
||||
description = '' |
||||
Wheter to enable HSTS if HTTPS is also enabled. |
||||
''; |
||||
}; |
||||
maxAgeSeconds = mkOption { |
||||
type = types.int; |
||||
default = 31536000; |
||||
description = '' |
||||
Max duration for clients to keep the HSTS status. |
||||
''; |
||||
}; |
||||
includeSubdomains = mkOption { |
||||
type = types.bool; |
||||
default = true; |
||||
description = '' |
||||
Whether to include subdomains in HSTS. |
||||
''; |
||||
}; |
||||
preload = mkOption { |
||||
type = types.bool; |
||||
default = true; |
||||
description = '' |
||||
Whether to allow preloading of the site's HSTS status. |
||||
''; |
||||
}; |
||||
}; |
||||
csp = mkOption { |
||||
type = types.nullOr types.attrs; |
||||
default = null; |
||||
example = literalExample '' |
||||
{ |
||||
enable = true; |
||||
directives = { |
||||
scriptSrc = "trustworthy.scripts.example.com"; |
||||
}; |
||||
upgradeInsecureRequest = "auto"; |
||||
addDefaults = true; |
||||
} |
||||
''; |
||||
description = '' |
||||
Specify the Content Security Policy which is passed to Helmet. |
||||
For configuration details see <link xlink:href="https://helmetjs.github.io/docs/csp/" |
||||
>https://helmetjs.github.io/docs/csp/</link>. |
||||
''; |
||||
}; |
||||
protocolUseSSL = mkOption { |
||||
type = types.bool; |
||||
default = false; |
||||
description = '' |
||||
Enable to use TLS for resource paths. |
||||
This only applies when <option>domain</option> is set. |
||||
''; |
||||
}; |
||||
urlAddPort = mkOption { |
||||
type = types.bool; |
||||
default = false; |
||||
description = '' |
||||
Enable to add the port to callback URLs. |
||||
This only applies when <option>domain</option> is set |
||||
and only for ports other than 80 and 443. |
||||
''; |
||||
}; |
||||
useCDN = mkOption { |
||||
type = types.bool; |
||||
default = true; |
||||
description = '' |
||||
Whether to use CDN resources or not. |
||||
''; |
||||
}; |
||||
allowAnonymous = mkOption { |
||||
type = types.bool; |
||||
default = true; |
||||
description = '' |
||||
Whether to allow anonymous usage. |
||||
''; |
||||
}; |
||||
allowAnonymousEdits = mkOption { |
||||
type = types.bool; |
||||
default = false; |
||||
description = '' |
||||
Whether to allow guests to edit existing notes with the `freely' permission, |
||||
when <option>allowAnonymous</option> is enabled. |
||||
''; |
||||
}; |
||||
allowFreeURL = mkOption { |
||||
type = types.bool; |
||||
default = false; |
||||
description = '' |
||||
Whether to allow note creation by accessing a nonexistent note URL. |
||||
''; |
||||
}; |
||||
defaultPermission = mkOption { |
||||
type = types.enum [ "freely" "editable" "limited" "locked" "private" ]; |
||||
default = "editable"; |
||||
description = '' |
||||
Default permissions for notes. |
||||
This only applies for signed-in users. |
||||
''; |
||||
}; |
||||
dbURL = mkOption { |
||||
type = types.nullOr types.str; |
||||
default = null; |
||||
example = '' |
||||
postgres://user:pass@host:5432/dbname |
||||
''; |
||||
description = '' |
||||
Specify which database to use. |
||||
CodiMD supports mysql, postgres, sqlite and mssql. |
||||
See <link xlink:href="https://sequelize.readthedocs.io/en/v3/"> |
||||
https://sequelize.readthedocs.io/en/v3/</link> for more information. |
||||
Note: This option overrides <option>db</option>. |
||||
''; |
||||
}; |
||||
db = mkOption { |
||||
type = types.attrs; |
||||
default = {}; |
||||
example = literalExample '' |
||||
{ |
||||
dialect = "sqlite"; |
||||
storage = "/var/lib/codimd/db.codimd.sqlite"; |
||||
} |
||||
''; |
||||
description = '' |
||||
Specify the configuration for sequelize. |
||||
CodiMD supports mysql, postgres, sqlite and mssql. |
||||
See <link xlink:href="https://sequelize.readthedocs.io/en/v3/"> |
||||
https://sequelize.readthedocs.io/en/v3/</link> for more information. |
||||
Note: This option overrides <option>db</option>. |
||||
''; |
||||
}; |
||||
sslKeyPath= mkOption { |
||||
type = types.nullOr types.str; |
||||
default = null; |
||||
example = "/var/lib/codimd/codimd.key"; |
||||
description = '' |
||||
Path to the SSL key. Needed when <option>useSSL</option> is enabled. |
||||
''; |
||||
}; |
||||
sslCertPath = mkOption { |
||||
type = types.nullOr types.str; |
||||
default = null; |
||||
example = "/var/lib/codimd/codimd.crt"; |
||||
description = '' |
||||
Path to the SSL cert. Needed when <option>useSSL</option> is enabled. |
||||
''; |
||||
}; |
||||
sslCAPath = mkOption { |
||||
type = types.listOf types.str; |
||||
default = []; |
||||
example = [ "/var/lib/codimd/ca.crt" ]; |
||||
description = '' |
||||
SSL ca chain. Needed when <option>useSSL</option> is enabled. |
||||
''; |
||||
}; |
||||
dhParamPath = mkOption { |
||||
type = types.nullOr types.str; |
||||
default = null; |
||||
example = "/var/lib/codimd/dhparam.pem"; |
||||
description = '' |
||||
Path to the SSL dh params. Needed when <option>useSSL</option> is enabled. |
||||
''; |
||||
}; |
||||
tmpPath = mkOption { |
||||
type = types.str; |
||||
default = "/tmp"; |
||||
description = '' |
||||
Path to the temp directory CodiMD should use. |
||||
Note that <option>serviceConfig.PrivateTmp</option> is enabled for |
||||
the CodiMD systemd service by default. |
||||
(Non-canonical paths are relative to CodiMD's base directory) |
||||
''; |
||||
}; |
||||
defaultNotePath = mkOption { |
||||
type = types.nullOr types.str; |
||||
default = "./public/default.md"; |
||||
description = '' |
||||
Path to the default Note file. |
||||
(Non-canonical paths are relative to CodiMD's base directory) |
||||
''; |
||||
}; |
||||
docsPath = mkOption { |
||||
type = types.nullOr types.str; |
||||
default = "./public/docs"; |
||||
description = '' |
||||
Path to the docs directory. |
||||
(Non-canonical paths are relative to CodiMD's base directory) |
||||
''; |
||||
}; |
||||
indexPath = mkOption { |
||||
type = types.nullOr types.str; |
||||
default = "./public/views/index.ejs"; |
||||
description = '' |
||||
Path to the index template file. |
||||
(Non-canonical paths are relative to CodiMD's base directory) |
||||
''; |
||||
}; |
||||
hackmdPath = mkOption { |
||||
type = types.nullOr types.str; |
||||
default = "./public/views/hackmd.ejs"; |
||||
description = '' |
||||
Path to the hackmd template file. |
||||
(Non-canonical paths are relative to CodiMD's base directory) |
||||
''; |
||||
}; |
||||
errorPath = mkOption { |
||||
type = types.nullOr types.str; |
||||
default = null; |
||||
defaultText = "./public/views/error.ejs"; |
||||
description = '' |
||||
Path to the error template file. |
||||
(Non-canonical paths are relative to CodiMD's base directory) |
||||
''; |
||||
}; |
||||
prettyPath = mkOption { |
||||
type = types.nullOr types.str; |
||||
default = null; |
||||
defaultText = "./public/views/pretty.ejs"; |
||||
description = '' |
||||
Path to the pretty template file. |
||||
(Non-canonical paths are relative to CodiMD's base directory) |
||||
''; |
||||
}; |
||||
slidePath = mkOption { |
||||
type = types.nullOr types.str; |
||||
default = null; |
||||
defaultText = "./public/views/slide.hbs"; |
||||
description = '' |
||||
Path to the slide template file. |
||||
(Non-canonical paths are relative to CodiMD's base directory) |
||||
''; |
||||
}; |
||||
uploadsPath = mkOption { |
||||
type = types.str; |
||||
default = "${cfg.workDir}/uploads"; |
||||
defaultText = "/var/lib/codimd/uploads"; |
||||
description = '' |
||||
Path under which uploaded files are saved. |
||||
''; |
||||
}; |
||||
sessionName = mkOption { |
||||
type = types.str; |
||||
default = "connect.sid"; |
||||
description = '' |
||||
Specify the name of the session cookie. |
||||
''; |
||||
}; |
||||
sessionSecret = mkOption { |
||||
type = types.nullOr types.str; |
||||
default = null; |
||||
description = '' |
||||
Specify the secret used to sign the session cookie. |
||||
If unset, one will be generated on startup. |
||||
''; |
||||
}; |
||||
sessionLife = mkOption { |
||||
type = types.int; |
||||
default = 1209600000; |
||||
description = '' |
||||
Session life time in milliseconds. |
||||
''; |
||||
}; |
||||
heartbeatInterval = mkOption { |
||||
type = types.int; |
||||
default = 5000; |
||||
description = '' |
||||
Specify the socket.io heartbeat interval. |
||||
''; |
||||
}; |
||||
heartbeatTimeout = mkOption { |
||||
type = types.int; |
||||
default = 10000; |
||||
description = '' |
||||
Specify the socket.io heartbeat timeout. |
||||
''; |
||||
}; |
||||
documentMaxLength = mkOption { |
||||
type = types.int; |
||||
default = 100000; |
||||
description = '' |
||||
Specify the maximum document length. |
||||
''; |
||||
}; |
||||
email = mkOption { |
||||
type = types.bool; |
||||
default = true; |
||||
description = '' |
||||
Whether to enable email sign-in. |
||||
''; |
||||
}; |
||||
allowEmailRegister = mkOption { |
||||
type = types.bool; |
||||
default = true; |
||||
description = '' |
||||
Wether to enable email registration. |
||||
''; |
||||
}; |
||||
allowGravatar = mkOption { |
||||
type = types.bool; |
||||
default = true; |
||||
description = '' |
||||
Whether to use gravatar as profile picture source. |
||||
''; |
||||
}; |
||||
imageUploadType = mkOption { |
||||
type = types.enum [ "imgur" "s3" "minio" "filesystem" ]; |
||||
default = "filesystem"; |
||||
description = '' |
||||
Specify where to upload images. |
||||
''; |
||||
}; |
||||
minio = mkOption { |
||||
type = types.nullOr (types.submodule { |
||||
options = { |
||||
accessKey = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Minio access key. |
||||
''; |
||||
}; |
||||
secretKey = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Minio secret key. |
||||
''; |
||||
}; |
||||
endpoint = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Minio endpoint. |
||||
''; |
||||
}; |
||||
port = mkOption { |
||||
type = types.int; |
||||
default = 9000; |
||||
description = '' |
||||
Minio listen port. |
||||
''; |
||||
}; |
||||
secure = mkOption { |
||||
type = types.bool; |
||||
default = true; |
||||
description = '' |
||||
Whether to use HTTPS for Minio. |
||||
''; |
||||
}; |
||||
}; |
||||
}); |
||||
default = null; |
||||
description = "Configure the minio third-party integration."; |
||||
}; |
||||
s3 = mkOption { |
||||
type = types.nullOr (types.submodule { |
||||
options = { |
||||
accessKeyId = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
AWS access key id. |
||||
''; |
||||
}; |
||||
secretAccessKey = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
AWS access key. |
||||
''; |
||||
}; |
||||
region = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
AWS S3 region. |
||||
''; |
||||
}; |
||||
}; |
||||
}); |
||||
default = null; |
||||
description = "Configure the s3 third-party integration."; |
||||
}; |
||||
s3bucket = mkOption { |
||||
type = types.nullOr types.str; |
||||
default = null; |
||||
description = '' |
||||
Specify the bucket name for upload types <literal>s3</literal> and <literal>minio</literal>. |
||||
''; |
||||
}; |
||||
allowPDFExport = mkOption { |
||||
type = types.bool; |
||||
default = true; |
||||
description = '' |
||||
Whether to enable PDF exports. |
||||
''; |
||||
}; |
||||
imgur.clientId = mkOption { |
||||
type = types.nullOr types.str; |
||||
default = null; |
||||
description = '' |
||||
Imgur API client ID. |
||||
''; |
||||
}; |
||||
azure = mkOption { |
||||
type = types.nullOr (types.submodule { |
||||
options = { |
||||
connectionString = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Azure Blob Storage connection string. |
||||
''; |
||||
}; |
||||
container = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Azure Blob Storage container name. |
||||
It will be created if non-existent. |
||||
''; |
||||
}; |
||||
}; |
||||
}); |
||||
default = null; |
||||
description = "Configure the azure third-party integration."; |
||||
}; |
||||
oauth2 = mkOption { |
||||
type = types.nullOr (types.submodule { |
||||
options = { |
||||
authorizationURL = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Specify the OAuth authorization URL. |
||||
''; |
||||
}; |
||||
tokenURL = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Specify the OAuth token URL. |
||||
''; |
||||
}; |
||||
clientID = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Specify the OAuth client ID. |
||||
''; |
||||
}; |
||||
clientSecret = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Specify the OAuth client secret. |
||||
''; |
||||
}; |
||||
}; |
||||
}); |
||||
default = null; |
||||
description = "Configure the OAuth integration."; |
||||
}; |
||||
facebook = mkOption { |
||||
type = types.nullOr (types.submodule { |
||||
options = { |
||||
clientID = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Facebook API client ID. |
||||
''; |
||||
}; |
||||
clientSecret = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Facebook API client secret. |
||||
''; |
||||
}; |
||||
}; |
||||
}); |
||||
default = null; |
||||
description = "Configure the facebook third-party integration"; |
||||
}; |
||||
twitter = mkOption { |
||||
type = types.nullOr (types.submodule { |
||||
options = { |
||||
consumerKey = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Twitter API consumer key. |
||||
''; |
||||
}; |
||||
consumerSecret = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Twitter API consumer secret. |
||||
''; |
||||
}; |
||||
}; |
||||
}); |
||||
default = null; |
||||
description = "Configure the Twitter third-party integration."; |
||||
}; |
||||
github = mkOption { |
||||
type = types.nullOr (types.submodule { |
||||
options = { |
||||
clientID = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
GitHub API client ID. |
||||
''; |
||||
}; |
||||
clientSecret = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Github API client secret. |
||||
''; |
||||
}; |
||||
}; |
||||
}); |
||||
default = null; |
||||
description = "Configure the GitHub third-party integration."; |
||||
}; |
||||
gitlab = mkOption { |
||||
type = types.nullOr (types.submodule { |
||||
options = { |
||||
baseURL = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
GitLab API authentication endpoint. |
||||
Only needed for other endpoints than gitlab.com. |
||||
''; |
||||
}; |
||||
clientID = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
GitLab API client ID. |
||||
''; |
||||
}; |
||||
clientSecret = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
GitLab API client secret. |
||||
''; |
||||
}; |
||||
scope = mkOption { |
||||
type = types.enum [ "api" "read_user" ]; |
||||
default = "api"; |
||||
description = '' |
||||
GitLab API requested scope. |
||||
GitLab snippet import/export requires api scope. |
||||
''; |
||||
}; |
||||
}; |
||||
}); |
||||
default = null; |
||||
description = "Configure the GitLab third-party integration."; |
||||
}; |
||||
mattermost = mkOption { |
||||
type = types.nullOr (types.submodule { |
||||
options = { |
||||
baseURL = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Mattermost authentication endpoint. |
||||
''; |
||||
}; |
||||
clientID = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Mattermost API client ID. |
||||
''; |
||||
}; |
||||
clientSecret = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Mattermost API client secret. |
||||
''; |
||||
}; |
||||
}; |
||||
}); |
||||
default = null; |
||||
description = "Configure the Mattermost third-party integration."; |
||||
}; |
||||
dropbox = mkOption { |
||||
type = types.nullOr (types.submodule { |
||||
options = { |
||||
clientID = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Dropbox API client ID. |
||||
''; |
||||
}; |
||||
clientSecret = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Dropbox API client secret. |
||||
''; |
||||
}; |
||||
appKey = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Dropbox app key. |
||||
''; |
||||
}; |
||||
}; |
||||
}); |
||||
default = null; |
||||
description = "Configure the Dropbox third-party integration."; |
||||
}; |
||||
google = mkOption { |
||||
type = types.nullOr (types.submodule { |
||||
options = { |
||||
clientID = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Google API client ID. |
||||
''; |
||||
}; |
||||
clientSecret = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Google API client secret. |
||||
''; |
||||
}; |
||||
}; |
||||
}); |
||||
default = null; |
||||
description = "Configure the Google third-party integration."; |
||||
}; |
||||
ldap = mkOption { |
||||
type = types.nullOr (types.submodule { |
||||
options = { |
||||
providerName = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Optional name to be displayed at login form, indicating the LDAP provider. |
||||
''; |
||||
}; |
||||
url = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
example = "ldap://localhost"; |
||||
description = '' |
||||
URL of LDAP server. |
||||
''; |
||||
}; |
||||
bindDn = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Bind DN for LDAP access. |
||||
''; |
||||
}; |
||||
bindCredentials = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Bind credentials for LDAP access. |
||||
''; |
||||
}; |
||||
searchBase = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
example = "o=users,dc=example,dc=com"; |
||||
description = '' |
||||
LDAP directory to begin search from. |
||||
''; |
||||
}; |
||||
searchFilter = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
example = "(uid={{username}})"; |
||||
description = '' |
||||
LDAP filter to search with. |
||||
''; |
||||
}; |
||||
searchAttributes = mkOption { |
||||
type = types.listOf types.str; |
||||
default = []; |
||||
example = [ "displayName" "mail" ]; |
||||
description = '' |
||||
LDAP attributes to search with. |
||||
''; |
||||
}; |
||||
userNameField = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
LDAP field which is used as the username on CodiMD. |
||||
By default <option>useridField</option> is used. |
||||
''; |
||||
}; |
||||
useridField = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
example = "uid"; |
||||
description = '' |
||||
LDAP field which is a unique identifier for users on CodiMD. |
||||
''; |
||||
}; |
||||
tlsca = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
example = "server-cert.pem,root.pem"; |
||||
description = '' |
||||
Root CA for LDAP TLS in PEM format. |
||||
''; |
||||
}; |
||||
}; |
||||
}); |
||||
default = null; |
||||
description = "Configure the LDAP integration."; |
||||
}; |
||||
saml = mkOption { |
||||
type = types.nullOr (types.submodule { |
||||
options = { |
||||
idpSsoUrl = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
example = "https://idp.example.com/sso"; |
||||
description = '' |
||||
IdP authentication endpoint. |
||||
''; |
||||
}; |
||||
idPCert = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
example = "/path/to/cert.pem"; |
||||
description = '' |
||||
Path to IdP certificate file in PEM format. |
||||
''; |
||||
}; |
||||
issuer = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Optional identity of the service provider. |
||||
This defaults to the server URL. |
||||
''; |
||||
}; |
||||
identifierFormat = mkOption { |
||||
type = types.str; |
||||
default = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"; |
||||
description = '' |
||||
Optional name identifier format. |
||||
''; |
||||
}; |
||||
groupAttribute = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
example = "memberOf"; |
||||
description = '' |
||||
Optional attribute name for group list. |
||||
''; |
||||
}; |
||||
externalGroups = mkOption { |
||||
type = types.listOf types.str; |
||||
default = []; |
||||
example = [ "Temporary-staff" "External-users" ]; |
||||
description = '' |
||||
Excluded group names. |
||||
''; |
||||
}; |
||||
requiredGroups = mkOption { |
||||
type = types.listOf types.str; |
||||
default = []; |
||||
example = [ "Hackmd-users" "Codimd-users" ]; |
||||
description = '' |
||||
Required group names. |
||||
''; |
||||
}; |
||||
attribute = { |
||||
id = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Attribute map for `id'. |
||||
Defaults to `NameID' of SAML response. |
||||
''; |
||||
}; |
||||
username = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Attribute map for `username'. |
||||
Defaults to `NameID' of SAML response. |
||||
''; |
||||
}; |
||||
email = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Attribute map for `email'. |
||||
Defaults to `NameID' of SAML response if |
||||
<option>identifierFormat</option> has |
||||
the default value. |
||||
''; |
||||
}; |
||||
}; |
||||
}; |
||||
}); |
||||
default = null; |
||||
description = "Configure the SAML integration."; |
||||
}; |
||||
}; |
||||
}; |
||||
|
||||
config = mkIf cfg.enable { |
||||
assertions = [ |
||||
{ assertion = cfg.configuration.db == {} -> ( |
||||
cfg.configuration.dbURL != "" && cfg.configuration.dbURL != null |
||||
); |
||||
message = "Database configuration for CodiMD missing."; } |
||||
]; |
||||
users.groups.codimd = {}; |
||||
users.users.codimd = { |
||||
description = "CodiMD service user"; |
||||
group = "codimd"; |
||||
extraGroups = cfg.groups; |
||||
home = cfg.workDir; |
||||
createHome = true; |
||||
}; |
||||
|
||||
systemd.services.codimd = { |
||||
description = "CodiMD Service"; |
||||
wantedBy = [ "multi-user.target" ]; |
||||
after = [ "networking.target" ]; |
||||
preStart = '' |
||||
mkdir -p ${cfg.workDir} |
||||
chown -R codimd: ${cfg.workDir} |
||||
''; |
||||
serviceConfig = { |
||||
WorkingDirectory = cfg.workDir; |
||||
ExecStart = "${pkgs.codimd}/bin/codimd"; |
||||
Environment = [ |
||||
"CMD_CONFIG_FILE=${prettyJSON cfg.configuration}" |
||||
"NODE_ENV=production" |
||||
]; |
||||
Restart = "always"; |
||||
User = "codimd"; |
||||
PermissionsStartOnly = true; |
||||
PrivateTmp = true; |
||||
}; |
||||
}; |
||||
}; |
||||
} |
Loading…
Reference in new issue