187 lines
5.1 KiB
Nix
187 lines
5.1 KiB
Nix
![]() |
latestPkgs: {
|
||
|
config,
|
||
|
lib,
|
||
|
...
|
||
|
}: let
|
||
|
sp = config.selfprivacy;
|
||
|
cfg = sp.modules.vikunja;
|
||
|
oauthClientID = "vikunja";
|
||
|
auth-passthru = config.selfprivacy.passthru.auth;
|
||
|
oauth2-provider-name = auth-passthru.oauth2-provider-name;
|
||
|
oauthDiscoveryURL = auth-passthru.oauth2-discovery-url oauthClientID;
|
||
|
|
||
|
# SelfPrivacy uses SP Module ID to identify the group!
|
||
|
usersGroup = "sp.vikunja.users";
|
||
|
|
||
|
oauthClientSecretFP =
|
||
|
auth-passthru.mkOAuth2ClientSecretFP oauthClientID;
|
||
|
|
||
|
vikunjaPackage = latestPkgs.vikunja.overrideAttrs (old: {
|
||
|
doCheck = false; # Tests are slow.
|
||
|
patches =
|
||
|
(old.patches or [])
|
||
|
++ [
|
||
|
./load-client-secret-from-env.patch
|
||
|
];
|
||
|
});
|
||
|
in {
|
||
|
options.selfprivacy.modules.vikunja = {
|
||
|
enable =
|
||
|
(lib.mkOption {
|
||
|
default = false;
|
||
|
type = lib.types.bool;
|
||
|
description = "Enable Vikunja";
|
||
|
})
|
||
|
// {
|
||
|
meta = {
|
||
|
type = "enable";
|
||
|
};
|
||
|
};
|
||
|
location =
|
||
|
(lib.mkOption {
|
||
|
type = lib.types.str;
|
||
|
description = "Vikunja location";
|
||
|
})
|
||
|
// {
|
||
|
meta = {
|
||
|
type = "location";
|
||
|
};
|
||
|
};
|
||
|
subdomain =
|
||
|
(lib.mkOption {
|
||
|
default = "vikunja";
|
||
|
type = lib.types.strMatching "[A-Za-z0-9][A-Za-z0-9\-]{0,61}[A-Za-z0-9]";
|
||
|
description = "Subdomain";
|
||
|
})
|
||
|
// {
|
||
|
meta = {
|
||
|
widget = "subdomain";
|
||
|
type = "string";
|
||
|
regex = "[A-Za-z0-9][A-Za-z0-9\-]{0,61}[A-Za-z0-9]";
|
||
|
weight = 0;
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
config =
|
||
|
lib.mkIf cfg.enable
|
||
|
{
|
||
|
assertions = [
|
||
|
{
|
||
|
assertion = sp.sso.enable;
|
||
|
message = "Vikunja cannot be enabled when SSO is disabled.";
|
||
|
}
|
||
|
];
|
||
|
|
||
|
fileSystems = lib.mkIf sp.useBinds {
|
||
|
"/var/lib/vikunja" = {
|
||
|
device = "/volumes/${cfg.location}/vikunja";
|
||
|
options = ["bind"];
|
||
|
};
|
||
|
};
|
||
|
|
||
|
users = {
|
||
|
users.vikunja = {
|
||
|
isSystemUser = true;
|
||
|
group = "vikunja";
|
||
|
};
|
||
|
groups.vikunja = {};
|
||
|
};
|
||
|
|
||
|
services.postgresql = {
|
||
|
ensureDatabases = ["vikunja"];
|
||
|
ensureUsers = [
|
||
|
{
|
||
|
name = "vikunja";
|
||
|
ensureDBOwnership = true;
|
||
|
}
|
||
|
];
|
||
|
};
|
||
|
|
||
|
services.vikunja = {
|
||
|
enable = true;
|
||
|
package = vikunjaPackage;
|
||
|
frontendScheme = "https";
|
||
|
frontendHostname = "${cfg.subdomain}.${sp.domain}";
|
||
|
port = 4835;
|
||
|
|
||
|
database = {
|
||
|
type = "postgres";
|
||
|
host = "/run/postgresql";
|
||
|
};
|
||
|
|
||
|
settings = {
|
||
|
service = {
|
||
|
enableregistration = false;
|
||
|
enabletotp = false;
|
||
|
enableuserdeletion = true;
|
||
|
};
|
||
|
|
||
|
auth = {
|
||
|
local.enabled = false;
|
||
|
openid = {
|
||
|
enabled = true;
|
||
|
providers = [
|
||
|
{
|
||
|
name = oauth2-provider-name;
|
||
|
authurl = lib.strings.removeSuffix "/.well-known/openid-configuration" oauthDiscoveryURL;
|
||
|
clientid = oauthClientID;
|
||
|
clientsecret = ""; # There's patch for our Vikunja to make it load client secret from environment variable.
|
||
|
scope = "openid profile email";
|
||
|
}
|
||
|
];
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
services.nginx.virtualHosts."${cfg.subdomain}.${sp.domain}" = {
|
||
|
useACMEHost = sp.domain;
|
||
|
forceSSL = true;
|
||
|
extraConfig = ''
|
||
|
add_header Strict-Transport-Security $hsts_header;
|
||
|
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
|
||
|
add_header 'Referrer-Policy' 'origin-when-cross-origin';
|
||
|
add_header X-Frame-Options DENY;
|
||
|
add_header X-Content-Type-Options nosniff;
|
||
|
add_header X-XSS-Protection "1; mode=block";
|
||
|
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
|
||
|
'';
|
||
|
locations = {
|
||
|
"/" = {
|
||
|
proxyPass = "http://127.0.0.1:4835";
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
systemd = {
|
||
|
services.vikunja = {
|
||
|
unitConfig.RequiresMountsFor = lib.mkIf sp.useBinds "/volumes/${cfg.location}/vikunja";
|
||
|
serviceConfig = {
|
||
|
Slice = "vikunja.slice";
|
||
|
LoadCredential = "oauth2-secret:${oauthClientSecretFP}";
|
||
|
DynamicUser = lib.mkForce false;
|
||
|
User = "vikunja";
|
||
|
Group = "vikunja";
|
||
|
};
|
||
|
environment.SP_VIKUNJA_CLIENT_SECRET_PATH = "%d/oauth2-secret";
|
||
|
};
|
||
|
slices.vikunja = {
|
||
|
description = "Vikunja service slice";
|
||
|
};
|
||
|
};
|
||
|
|
||
|
selfprivacy.auth.clients.${oauthClientID} = {
|
||
|
inherit usersGroup;
|
||
|
subdomain = cfg.subdomain;
|
||
|
isTokenNeeded = true;
|
||
|
originLanding = "https://${cfg.subdomain}.${sp.domain}/";
|
||
|
originUrl = "https://${cfg.subdomain}.${sp.domain}/auth/openid/${lib.strings.toLower oauth2-provider-name}";
|
||
|
clientSystemdUnits = ["vikunja.service"];
|
||
|
enablePkce = false;
|
||
|
linuxUserOfClient = "vikunja";
|
||
|
linuxGroupOfClient = "vikunja";
|
||
|
};
|
||
|
};
|
||
|
}
|