basic notification system for atproto stuff using ntfy
1# copied from here https://github.com/NixOS/nixpkgs/blob/nixos-unstable/nixos/modules/services/web-apps/bluesky-pds.nix
2{
3 lib,
4 pkgs,
5 config,
6 ...
7}: let
8 cfg = config.services.atproto-basic-notifications;
9
10 inherit
11 (lib)
12 getExe
13 mkEnableOption
14 mkIf
15 mkOption
16 mkPackageOption
17 types
18 ;
19in {
20 options.services.atproto-basic-notifications = {
21 enable = mkEnableOption "basic notification system for atproto stuff";
22
23 package = mkPackageOption pkgs "atproto-basic-notifications" {};
24
25 settings = mkOption {
26 type = types.submodule {
27 freeformType = types.attrsOf (
28 types.oneOf [
29 (types.nullOr types.str)
30 types.port
31 ]
32 );
33 options = {
34 TARGET_DID = mkOption {
35 type = types.nullOr types.str;
36 default = null;
37 description = "The DID of the user to monitor, put yours otherwise you'll be getting all my notifs lol.";
38 example = "did:plc:3c6vkaq7xf5kz3va3muptjh5";
39 };
40
41 JETSTREAM_URL = mkOption {
42 type = types.nullOr types.str;
43 default = null;
44 description = "The URL of the jetstream to connect to.";
45 example = "wss://jetstream2.us-east.bsky.network/subscribe";
46 };
47
48 NTFY_URL = mkOption {
49 type = types.nullOr types.str;
50 default = null;
51 description = "The URL of the ntfy.sh server for sending notifications, you should definitely change this. If you have a login put this on the environment file thing not here!!!";
52 example = "http://ntfy.sh";
53 };
54
55 BSKY_URL = mkOption {
56 type = types.nullOr types.str;
57 default = null;
58 description = "The URL of the Bluesky web client, probably doesn't make sense editing.";
59 example = "https://bsky.app";
60 };
61
62 PDSLS_URL = mkOption {
63 type = types.nullOr types.str;
64 default = null;
65 description = "The URL for pdsls.dev, probably doesn't make sense editing.";
66 example = "https://pdsls.dev";
67 };
68
69 TANGLED_URL = mkOption {
70 type = types.nullOr types.str;
71 default = null;
72 description = "The URL for tangled.sh, probably doesn't make sense editing.";
73 example = "https://tangled.sh";
74 };
75 };
76 };
77
78 description = ''
79 Environment variables to set for the service. Secrets should be
80 specified using {option}`environmentFile`.
81
82 Refer to <https://github.com/ayla6/atproto-basic-notifications/blob/main/index.ts> for available environment variables.
83 '';
84 };
85
86 environmentFiles = mkOption {
87 type = types.listOf types.path;
88 default = [];
89 description = "this is where you should put the ntfy url if there's a login or token";
90 };
91 };
92
93 config = mkIf cfg.enable {
94 systemd.services.atproto-basic-notifications = {
95 description = "basic notification system for atproto stuff";
96
97 after = ["network-online.target"];
98 wants = ["network-online.target"];
99 wantedBy = ["multi-user.target"];
100
101 serviceConfig = {
102 ExecStart = getExe cfg.package;
103 Environment =
104 lib.mapAttrsToList (k: v: "${k}=${
105 if builtins.isInt v
106 then toString v
107 else v
108 }") (
109 lib.filterAttrs (_: v: v != null) cfg.settings
110 );
111
112 EnvironmentFile = cfg.environmentFiles;
113 User = "atp-notif";
114 Group = "atp-notif";
115 StateDirectory = "atproto-basic-notifications";
116 StateDirectoryMode = "0755";
117 Restart = "always";
118
119 # Hardening
120 RemoveIPC = true;
121 CapabilityBoundingSet = ["CAP_NET_BIND_SERVICE"];
122 NoNewPrivileges = true;
123 PrivateDevices = true;
124 ProtectClock = true;
125 ProtectKernelLogs = true;
126 ProtectControlGroups = true;
127 ProtectKernelModules = true;
128 PrivateMounts = true;
129 SystemCallArchitectures = ["native"];
130 MemoryDenyWriteExecute = false; # required by V8 JIT
131 RestrictNamespaces = true;
132 RestrictSUIDSGID = true;
133 ProtectHostname = true;
134 LockPersonality = true;
135 ProtectKernelTunables = true;
136 RestrictAddressFamilies = [
137 "AF_UNIX"
138 "AF_INET"
139 "AF_INET6"
140 ];
141 RestrictRealtime = true;
142 DeviceAllow = [""];
143 ProtectSystem = "strict";
144 ProtectProc = "invisible";
145 ProcSubset = "pid";
146 ProtectHome = true;
147 PrivateUsers = true;
148 PrivateTmp = true;
149 UMask = "0077";
150 };
151 };
152
153 users = {
154 users.atp-notif = {
155 group = "atp-notif";
156 isSystemUser = true;
157 };
158 groups.atp-notif = {};
159 };
160 };
161}