457 lines
14 KiB
Nix
457 lines
14 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
shb,
|
|
...
|
|
}:
|
|
|
|
let
|
|
cfg = config.shb.firefly-iii;
|
|
in
|
|
{
|
|
imports = [
|
|
../blocks/nginx.nix
|
|
../blocks/lldap.nix
|
|
|
|
../../lib/module.nix
|
|
];
|
|
|
|
options.shb.firefly-iii = {
|
|
enable = lib.mkEnableOption "SHB's firefly-iii module";
|
|
|
|
subdomain = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = ''
|
|
Subdomain under which firefly-iii will be served.
|
|
|
|
```
|
|
<subdomain>.<domain>
|
|
```
|
|
'';
|
|
example = "firefly-iii";
|
|
};
|
|
|
|
domain = lib.mkOption {
|
|
description = ''
|
|
Domain under which firefly-iii is served.
|
|
|
|
```
|
|
<subdomain>.<domain>[:<port>]
|
|
```
|
|
'';
|
|
type = lib.types.str;
|
|
example = "domain.com";
|
|
};
|
|
|
|
ssl = lib.mkOption {
|
|
description = "Path to SSL files";
|
|
type = lib.types.nullOr shb.contracts.ssl.certs;
|
|
default = null;
|
|
};
|
|
|
|
siteOwnerEmail = lib.mkOption {
|
|
description = "Email of the site owner.";
|
|
type = lib.types.str;
|
|
example = "mail@example.com";
|
|
};
|
|
|
|
impermanence = lib.mkOption {
|
|
description = ''
|
|
Path to save when using impermanence setup.
|
|
'';
|
|
type = lib.types.str;
|
|
default = config.services.firefly-iii.dataDir;
|
|
defaultText = "services.firefly-iii.dataDir";
|
|
};
|
|
|
|
backup = lib.mkOption {
|
|
description = ''
|
|
Backup configuration.
|
|
'';
|
|
default = { };
|
|
type = lib.types.submodule {
|
|
options = shb.contracts.backup.mkRequester {
|
|
user = config.services.firefly-iii.user;
|
|
userText = "services.firefly-iii.user";
|
|
sourceDirectories = [
|
|
config.services.firefly-iii.dataDir
|
|
];
|
|
sourceDirectoriesText = ''
|
|
[
|
|
config.services.firefly-iii.dataDir
|
|
]
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
|
|
appKey = lib.mkOption {
|
|
description = "Encryption key used for sessions. Must be 32 characters long exactly.";
|
|
type = lib.types.submodule {
|
|
options = shb.contracts.secret.mkRequester {
|
|
mode = "0400";
|
|
owner = config.services.firefly-iii.user;
|
|
ownerText = "services.firefly-iii.user";
|
|
restartUnits = [ "firefly-iii-setup.service" ];
|
|
};
|
|
};
|
|
};
|
|
|
|
dbPassword = lib.mkOption {
|
|
description = "DB password.";
|
|
type = lib.types.submodule {
|
|
options = shb.contracts.secret.mkRequester {
|
|
mode = "0440";
|
|
owner = config.services.firefly-iii.user;
|
|
ownerText = "services.firefly-iii.user";
|
|
group = "postgres";
|
|
restartUnits = [
|
|
"postgresql.service"
|
|
"firefly-iii-setup.service"
|
|
];
|
|
};
|
|
};
|
|
};
|
|
|
|
ldap = lib.mkOption {
|
|
description = ''
|
|
LDAP Integration
|
|
'';
|
|
default = { };
|
|
type = lib.types.submodule {
|
|
options = {
|
|
userGroup = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "Group users must belong to to be able to login to Firefly-iii.";
|
|
default = "firefly-iii_user";
|
|
};
|
|
adminGroup = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "Group users must belong to to be able to import data user the Firefly-iii data importer.";
|
|
default = "firefly-iii_admin";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
sso = lib.mkOption {
|
|
description = ''
|
|
SSO Integration
|
|
'';
|
|
default = { };
|
|
type = lib.types.submodule {
|
|
options = {
|
|
enable = lib.mkEnableOption "SSO integration.";
|
|
|
|
authEndpoint = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "OIDC endpoint for SSO.";
|
|
example = "https://authelia.example.com";
|
|
};
|
|
|
|
port = lib.mkOption {
|
|
description = "If given, adds a port to the endpoint.";
|
|
type = lib.types.nullOr lib.types.port;
|
|
default = null;
|
|
};
|
|
|
|
provider = lib.mkOption {
|
|
type = lib.types.enum [ "Authelia" ];
|
|
description = "OIDC provider name, used for display.";
|
|
default = "Authelia";
|
|
};
|
|
|
|
clientID = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "Client ID for the OIDC endpoint.";
|
|
default = "firefly-iii";
|
|
};
|
|
|
|
authorization_policy = lib.mkOption {
|
|
type = lib.types.enum [
|
|
"one_factor"
|
|
"two_factor"
|
|
];
|
|
description = "Require one factor (password) or two factor (device) authentication.";
|
|
default = "one_factor";
|
|
};
|
|
|
|
adminGroup = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "Group admins must belong to to be able to login to Firefly-iii.";
|
|
default = "firefly-iii_admin";
|
|
};
|
|
|
|
secret = lib.mkOption {
|
|
description = "OIDC shared secret.";
|
|
type = lib.types.submodule {
|
|
options = shb.contracts.secret.mkRequester {
|
|
mode = "0400";
|
|
owner = "firefly-iii";
|
|
restartUnits = [ "firefly-iii-setup.service" ];
|
|
};
|
|
};
|
|
};
|
|
|
|
secretForAuthelia = lib.mkOption {
|
|
description = "OIDC shared secret. Content must be the same as `secretFile` option.";
|
|
type = lib.types.submodule {
|
|
options = shb.contracts.secret.mkRequester {
|
|
mode = "0400";
|
|
owner = "authelia";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
smtp = lib.mkOption {
|
|
description = ''
|
|
If set, send notifications through smtp.
|
|
|
|
https://docs.firefly-iii.org/how-to/firefly-iii/advanced/notifications/
|
|
'';
|
|
default = null;
|
|
type = lib.types.nullOr (
|
|
lib.types.submodule {
|
|
options = {
|
|
from_address = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "SMTP address from which the emails originate.";
|
|
example = "authelia@mydomain.com";
|
|
};
|
|
host = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "SMTP host to send the emails to.";
|
|
};
|
|
port = lib.mkOption {
|
|
type = lib.types.port;
|
|
description = "SMTP port to send the emails to.";
|
|
default = 25;
|
|
};
|
|
username = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "Username to connect to the SMTP host.";
|
|
};
|
|
password = lib.mkOption {
|
|
description = "File containing the password to connect to the SMTP host.";
|
|
type = lib.types.submodule {
|
|
options = shb.contracts.secret.mkRequester {
|
|
mode = "0400";
|
|
owner = config.services.firefly-iii.user;
|
|
ownerText = "services.firefly-iii.user";
|
|
restartUnits = [ "firefly-iii-setup.service" ];
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|
|
);
|
|
};
|
|
|
|
debug = lib.mkOption {
|
|
type = lib.types.bool;
|
|
description = "Enable more verbose logging.";
|
|
default = false;
|
|
example = true;
|
|
};
|
|
|
|
importer = lib.mkOption {
|
|
description = ''
|
|
Configuration for Firefly-iii data importer.
|
|
'';
|
|
default = { };
|
|
type = lib.types.submodule {
|
|
options = {
|
|
enable = lib.mkEnableOption "Firefly-iii Data Importer." // {
|
|
default = true;
|
|
};
|
|
|
|
subdomain = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = ''
|
|
Subdomain under which the firefly-iii data importer will be served.
|
|
'';
|
|
default = "${cfg.subdomain}-importer";
|
|
defaultText = lib.literalExpression "\${shb.firefly-iii.subdomain}-importer";
|
|
};
|
|
|
|
firefly-iii-accessToken = lib.mkOption {
|
|
type = lib.types.nullOr (
|
|
lib.types.submodule {
|
|
options = shb.contracts.secret.mkRequester {
|
|
mode = "0400";
|
|
owner = config.services.firefly-iii-data-importer.user;
|
|
ownerText = "services.firefly-iii-data-importer.user";
|
|
restartUnits = [ "firefly-iii-data-importer-setup.service" ];
|
|
};
|
|
}
|
|
);
|
|
description = ''
|
|
Create a Personal Access Token then set then token in this option.
|
|
'';
|
|
default = null;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
dashboard = lib.mkOption {
|
|
description = ''
|
|
Dashboard contract consumer
|
|
'';
|
|
default = { };
|
|
type = lib.types.submodule {
|
|
options = shb.contracts.dashboard.mkRequester {
|
|
externalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
|
externalUrlText = "https://\${config.shb.firefly-iii.subdomain}.\${config.shb.firefly-iii.domain}";
|
|
# This works thanks to the Personal Access Token.
|
|
internalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
|
internalUrlText = "https://\${config.shb.firefly-iii.subdomain}.\${config.shb.firefly-iii.domain}";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable (
|
|
lib.mkMerge [
|
|
{
|
|
services.firefly-iii = {
|
|
enable = true;
|
|
group = "nginx";
|
|
|
|
virtualHost = "${cfg.subdomain}.${cfg.domain}";
|
|
|
|
# https://github.com/firefly-iii/firefly-iii/blob/main/.env.example
|
|
settings = {
|
|
APP_ENV = "production";
|
|
APP_URL = "https://${cfg.subdomain}.${cfg.domain}";
|
|
|
|
APP_DEBUG = cfg.debug;
|
|
APP_LOG_LEVEL = if cfg.debug then "debug" else "notice";
|
|
LOG_CHANNEL = "stdout";
|
|
|
|
APP_KEY_FILE = cfg.appKey.result.path;
|
|
SITE_OWNER = cfg.siteOwnerEmail;
|
|
DB_CONNECTION = "pgsql";
|
|
DB_HOST = "localhost";
|
|
DB_PORT = config.services.postgresql.settings.port;
|
|
DB_DATABASE = "firefly-iii";
|
|
DB_USERNAME = "firefly-iii";
|
|
DB_PASSWORD_FILE = cfg.dbPassword.result.path;
|
|
|
|
# MAP_DEFAULT_LAT = "51.983333";
|
|
# MAP_DEFAULT_LONG = "5.916667";
|
|
# MAP_DEFAULT_ZOOM = "6";
|
|
};
|
|
};
|
|
shb.postgresql.enableTCPIP = true;
|
|
shb.postgresql.ensures = [
|
|
{
|
|
username = "firefly-iii";
|
|
database = "firefly-iii";
|
|
passwordFile = cfg.dbPassword.result.path;
|
|
}
|
|
];
|
|
|
|
# This should be using a contract instead of setting the option directly.
|
|
shb.lldap = lib.mkIf config.shb.lldap.enable {
|
|
ensureGroups = {
|
|
${cfg.ldap.userGroup} = { };
|
|
${cfg.ldap.adminGroup} = { };
|
|
};
|
|
};
|
|
|
|
# We enable the firefly-iii nginx integration and merge it with SHB's nginx configuration.
|
|
services.firefly-iii.enableNginx = true;
|
|
shb.nginx.vhosts = [
|
|
{
|
|
inherit (cfg) subdomain domain ssl;
|
|
}
|
|
];
|
|
}
|
|
(lib.mkIf cfg.importer.enable {
|
|
services.firefly-iii-data-importer = {
|
|
enable = true;
|
|
|
|
virtualHost = "${cfg.importer.subdomain}.${cfg.domain}";
|
|
|
|
settings = {
|
|
FIREFLY_III_URL = "https://${config.services.firefly-iii.virtualHost}";
|
|
}
|
|
// lib.optionalAttrs (cfg.importer.firefly-iii-accessToken != null) {
|
|
FIREFLY_III_ACCESS_TOKEN_FILE = cfg.importer.firefly-iii-accessToken.result.path;
|
|
};
|
|
};
|
|
|
|
# We enable the firefly-iii-data-importer nginx integration and merge it with SHB's nginx configuration.
|
|
services.firefly-iii-data-importer.enableNginx = true;
|
|
shb.nginx.vhosts = [
|
|
{
|
|
inherit (cfg) domain ssl;
|
|
subdomain = cfg.importer.subdomain;
|
|
}
|
|
];
|
|
})
|
|
(lib.mkIf (cfg.smtp != null) {
|
|
services.firefly-iii.settings = {
|
|
MAIL_MAILER = "smtp";
|
|
MAIL_HOST = cfg.smtp.host;
|
|
MAIL_PORT = cfg.smtp.port;
|
|
MAIL_FROM = cfg.smtp.from_address;
|
|
MAIL_USERNAME = cfg.smtp.username;
|
|
MAIL_PASSWORD_FILE = cfg.smtp.password.result.path;
|
|
MAIL_ENCRYPTION = "tls";
|
|
};
|
|
})
|
|
(lib.mkIf cfg.sso.enable {
|
|
services.firefly-iii.settings = {
|
|
AUTHENTICATION_GUARD = "remote_user_guard";
|
|
AUTHENTICATION_GUARD_HEADER = "HTTP_X_FORWARDED_USER";
|
|
};
|
|
|
|
shb.nginx.vhosts = [
|
|
{
|
|
inherit (cfg) subdomain domain ssl;
|
|
inherit (cfg.sso) authEndpoint;
|
|
|
|
phpForwardAuth = true;
|
|
autheliaRules = [
|
|
{
|
|
domain = "${cfg.subdomain}.${cfg.domain}";
|
|
policy = "bypass";
|
|
resources = [ "^/api" ];
|
|
}
|
|
{
|
|
domain = "${cfg.subdomain}.${cfg.domain}";
|
|
policy = cfg.sso.authorization_policy;
|
|
subject = [
|
|
"group:${cfg.ldap.userGroup}"
|
|
"group:${cfg.ldap.adminGroup}"
|
|
];
|
|
}
|
|
];
|
|
}
|
|
];
|
|
})
|
|
(lib.mkIf (cfg.sso.enable && cfg.importer.enable) {
|
|
shb.nginx.vhosts = [
|
|
{
|
|
inherit (cfg.importer) subdomain;
|
|
inherit (cfg) domain ssl;
|
|
inherit (cfg.sso) authEndpoint;
|
|
|
|
autheliaRules = [
|
|
{
|
|
domain = "${cfg.importer.subdomain}.${cfg.domain}";
|
|
policy = cfg.sso.authorization_policy;
|
|
subject = [ "group:${cfg.ldap.adminGroup}" ];
|
|
}
|
|
];
|
|
}
|
|
];
|
|
})
|
|
]
|
|
);
|
|
}
|