Files
wf-module/module.nix
2025-11-12 19:46:51 +03:00

168 lines
4.4 KiB
Nix

{
config,
lib,
pkgs,
...
}:
let
sp = config.selfprivacy;
cfg = sp.modules.writefreely;
oauthClientID = "writefreely";
auth-passthru = config.selfprivacy.passthru.auth;
oauth2-provider-origin = config.services.kanidm.serverSettings.origin;
usersGroup = "sp.writefreely.users";
oauthClientSecretFP = auth-passthru.mkOAuth2ClientSecretFP oauthClientID;
in
{
options.selfprivacy.modules.writefreely = {
enable =
(lib.mkOption {
default = false;
type = lib.types.bool;
description = "Enable WriteFreely";
})
// {
meta = {
type = "enable";
};
};
location =
(lib.mkOption {
type = lib.types.str;
description = "WriteFreely location";
})
// {
meta = {
type = "location";
};
};
subdomain =
(lib.mkOption {
default = "writefreely";
type = lib.types.strMatching "[A-Za-z0-9][A-Za-z0-9\-]{0,61}[A-Za-z0-9]";
description = "Subdomain (changing subdomain after setting up will cause breakage of the federation!)";
})
// {
meta = {
widget = "subdomain";
type = "string";
regex = "[A-Za-z0-9][A-Za-z0-9\-]{0,61}[A-Za-z0-9]";
weight = 0;
};
};
appName =
(lib.mkOption {
default = "WriteFreely";
type = lib.types.str;
description = "Name of the WriteFreely instance.";
})
// {
meta = {
type = "string";
weight = 1;
};
};
enableFederation =
(lib.mkOption {
default = false;
type = lib.types.bool;
description = "Enable the ActivityPub federation.";
})
// {
meta = {
type = "bool";
weight = 2;
};
};
};
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = sp.sso.enable;
message = "WriteFreely cannot be enabled when SSO is disabled.";
}
];
fileSystems = lib.mkIf sp.useBinds {
"/var/lib/writefreely" = {
device = "/volumes/${cfg.location}/writefreely";
options = [ "bind" "uid=writefreely" "gid=writefreely" ];
};
};
services.writefreely = {
enable = true;
database.type = "sqlite3";
host = "${cfg.subdomain}.${sp.domain}";
settings = {
server.port = 8081;
app = {
site_name = cfg.appName;
single_user = false;
federation = cfg.enableFederation;
disable_password_auth = true;
open_registration = false;
};
"oauth.generic" = {
client_id = oauthClientID;
host = oauth2-provider-origin;
display_name = "SSO";
token_endpoint = "/oauth2/token";
inspect_endpoint = "/oauth2/openid/${oauthClientID}/userinfo";
auth_endpoint = "/ui/oauth2";
client_secret = "@replace_oauth_secret@";
};
};
};
systemd = {
services.writefreely = {
requires = [ "writefreely-sqlite-init.service" ];
unitConfig.RequiresMountsFor = lib.mkIf sp.useBinds "/volumes/${cfg.location}/writefreely";
serviceConfig.Slice = "writefreely.slice";
};
services.writefreely-sqlite-init = let
cfgFile = "${config.services.writefreely.stateDir}/config.ini";
in {
postStart = ''
chmod 660 '${cfgFile}'
${lib.getExe pkgs.replace-secret} "@replace_oauth_secret@" "${oauthClientSecretFP}" "${cfgFile}"
chmod 440 '${cfgFile}'
'';
unitConfig.RequiresMountsFor = lib.mkIf sp.useBinds "/volumes/${cfg.location}/writefreely";
serviceConfig.Slice = "writefreely.slice";
};
slices.writefreely = {
description = "WriteFreely service slice";
};
};
services.nginx.virtualHosts."${cfg.subdomain}.${sp.domain}" = {
useACMEHost = sp.domain;
forceSSL = true;
locations = {
"/" = {
proxyPass = "http://127.0.0.1:8081";
};
};
};
selfprivacy.auth.clients.${oauthClientID} = {
inherit usersGroup;
subdomain = cfg.subdomain;
originLanding = "https://${cfg.subdomain}.${sp.domain}/";
originUrl = "https://${cfg.subdomain}.${sp.domain}/auth/oauth2/callback";
clientSystemdUnits = [ "writefreely.service" ];
enablePkce = false;
linuxUserOfClient = "writefreely";
linuxGroupOfClient = "writefreely";
};
};
}