parent
6eff44f9fb
commit
25503db8e8
@ -0,0 +1,83 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
cfg = config.services.spacecookie; |
||||
configFile = pkgs.writeText "spacecookie.json" (lib.generators.toJSON {} { |
||||
inherit (cfg) hostname port root; |
||||
}); |
||||
in { |
||||
|
||||
options = { |
||||
|
||||
services.spacecookie = { |
||||
|
||||
enable = mkEnableOption "spacecookie"; |
||||
|
||||
hostname = mkOption { |
||||
type = types.str; |
||||
default = "localhost"; |
||||
description = "The hostname the service is reachable via. Clients will use this hostname for further requests after loading the initial gopher menu."; |
||||
}; |
||||
|
||||
port = mkOption { |
||||
type = types.port; |
||||
default = 70; |
||||
description = "Port the gopher service should be exposed on."; |
||||
}; |
||||
|
||||
root = mkOption { |
||||
type = types.path; |
||||
default = "/srv/gopher"; |
||||
description = "The root directory spacecookie serves via gopher."; |
||||
}; |
||||
}; |
||||
}; |
||||
|
||||
config = mkIf cfg.enable { |
||||
|
||||
systemd.sockets.spacecookie = { |
||||
description = "Socket for the Spacecookie Gopher Server"; |
||||
wantedBy = [ "sockets.target" ]; |
||||
listenStreams = [ "[::]:${toString cfg.port}" ]; |
||||
socketConfig = { |
||||
BindIPv6Only = "both"; |
||||
}; |
||||
}; |
||||
|
||||
systemd.services.spacecookie = { |
||||
description = "Spacecookie Gopher Server"; |
||||
wantedBy = [ "multi-user.target" ]; |
||||
requires = [ "spacecookie.socket" ]; |
||||
|
||||
serviceConfig = { |
||||
Type = "notify"; |
||||
ExecStart = "${pkgs.haskellPackages.spacecookie}/bin/spacecookie ${configFile}"; |
||||
FileDescriptorStoreMax = 1; |
||||
|
||||
DynamicUser = true; |
||||
|
||||
ProtectSystem = "strict"; |
||||
ProtectHome = true; |
||||
PrivateTmp = true; |
||||
PrivateDevices = true; |
||||
PrivateMounts = true; |
||||
PrivateUsers = true; |
||||
|
||||
ProtectKernelTunables = true; |
||||
ProtectKernelModules = true; |
||||
ProtectControlGroups = true; |
||||
|
||||
CapabilityBoundingSet = ""; |
||||
NoNewPrivileges = true; |
||||
LockPersonality = true; |
||||
RestrictRealtime = true; |
||||
|
||||
# AF_UNIX for communication with systemd |
||||
# AF_INET replaced by BindIPv6Only=both |
||||
RestrictAddressFamilies = "AF_UNIX AF_INET6"; |
||||
}; |
||||
}; |
||||
}; |
||||
} |
@ -0,0 +1,51 @@ |
||||
let |
||||
gopherRoot = "/tmp/gopher"; |
||||
gopherHost = "gopherd"; |
||||
fileContent = "Hello Gopher!"; |
||||
fileName = "file.txt"; |
||||
in |
||||
import ./make-test-python.nix ({...}: { |
||||
name = "spacecookie"; |
||||
nodes = { |
||||
${gopherHost} = { |
||||
networking.firewall.allowedTCPPorts = [ 70 ]; |
||||
systemd.services.spacecookie = { |
||||
preStart = '' |
||||
mkdir -p ${gopherRoot}/directory |
||||
echo "${fileContent}" > ${gopherRoot}/${fileName} |
||||
''; |
||||
}; |
||||
|
||||
services.spacecookie = { |
||||
enable = true; |
||||
root = gopherRoot; |
||||
hostname = gopherHost; |
||||
}; |
||||
}; |
||||
|
||||
client = {}; |
||||
}; |
||||
|
||||
testScript = '' |
||||
start_all() |
||||
${gopherHost}.wait_for_open_port(70) |
||||
${gopherHost}.wait_for_unit("spacecookie.service") |
||||
client.wait_for_unit("network.target") |
||||
|
||||
fileResponse = client.succeed("curl -s gopher://${gopherHost}//${fileName}") |
||||
|
||||
# the file response should return our created file exactly |
||||
if not (fileResponse == "${fileContent}\n"): |
||||
raise Exception("Unexpected file response") |
||||
|
||||
# sanity check on the directory listing: we serve a directory and a file |
||||
# via gopher, so the directory listing should have exactly two entries, |
||||
# one with gopher file type 0 (file) and one with file type 1 (directory). |
||||
dirResponse = client.succeed("curl -s gopher://${gopherHost}") |
||||
dirEntries = [l[0] for l in dirResponse.split("\n") if len(l) > 0] |
||||
dirEntries.sort() |
||||
|
||||
if not (["0", "1"] == dirEntries): |
||||
raise Exception("Unexpected directory response") |
||||
''; |
||||
}) |
Loading…
Reference in new issue