mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-09-30 03:39:59 +00:00
gophernicus: init at 3.1.1 with nixos module (#443747)
This commit is contained in:
@@ -98,6 +98,8 @@
|
||||
|
||||
- [gocron](https://github.com/flohoss/gocron), a task scheduler with web interface. Available as [services.gocron](#opt-services.gocron.enable).
|
||||
|
||||
- [gophernicus](https://github.com/gophernicus/gophernicus), a modern gopher daemon. Available at [services.gophernicus](#opt-services.gophernicus.enable).
|
||||
|
||||
- [Unpackerr](https://unpackerr.zip), extracts downloads for Radarr, Sonarr, Lidarr, Readarr, and/or a Watch folder. Available as [services.unpackerr](#opt-services.unpackerr.enable).
|
||||
|
||||
- [ioquake3](https://ioquake3.org), a open-source port of the 3D action shooter Quake 3 Arena. Available as [programs.ioquake3](#opt-programs.ioquake3.enable).
|
||||
|
||||
@@ -912,6 +912,7 @@
|
||||
./services/misc/gitolite.nix
|
||||
./services/misc/gitweb.nix
|
||||
./services/misc/gollum.nix
|
||||
./services/misc/gophernicus.nix
|
||||
./services/misc/gotenberg.nix
|
||||
./services/misc/gpsd.nix
|
||||
./services/misc/graphical-desktop.nix
|
||||
|
||||
229
nixos/modules/services/misc/gophernicus.nix
Normal file
229
nixos/modules/services/misc/gophernicus.nix
Normal file
@@ -0,0 +1,229 @@
|
||||
{
|
||||
config,
|
||||
options,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.gophernicus;
|
||||
opt = options.services.gophernicus;
|
||||
in
|
||||
{
|
||||
options.services.gophernicus = {
|
||||
enable = lib.mkEnableOption "gophernicus, a modern gopher daemon";
|
||||
package = lib.mkPackageOption pkgs "gophernicus" { };
|
||||
|
||||
domain = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "A DNS-resolvable domain pointing to this machine or a reverse proxy redirecting here.";
|
||||
example = "gopher.example.com";
|
||||
};
|
||||
|
||||
path = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.package;
|
||||
description = ''
|
||||
Packages with content in {file}`/bin` that should be available to gophernicus.
|
||||
|
||||
This will be provided as {env}`PATH` to both gophermaps, cgi scripts and filters.
|
||||
'';
|
||||
default = with pkgs; [
|
||||
coreutils
|
||||
gnused
|
||||
whoami
|
||||
bash
|
||||
php
|
||||
perl
|
||||
];
|
||||
defaultText = lib.literalExpression ''
|
||||
with pkgs; [
|
||||
coreutils
|
||||
gnused
|
||||
whoami
|
||||
bash
|
||||
php
|
||||
perl
|
||||
]
|
||||
'';
|
||||
};
|
||||
|
||||
filters = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.pathInStore;
|
||||
description = "Executables that should be registered as preprocessing filters.";
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
# Files with the `.txt` extension should be preprocessed with `my-filter`
|
||||
txt = pkgs.writeShellScript "my-filter" '''
|
||||
echo "To whom it may concern..."
|
||||
# First argument is the path of the file being filtered
|
||||
cat "$1"
|
||||
echo "Best regards, server owner"
|
||||
''';
|
||||
# Files with the `.php` extension should automatically be rendered by php
|
||||
php = "''${pkgs.php}/bin/php";
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
rootDir = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
description = ''
|
||||
The directory which contains the root of your gopher content.
|
||||
|
||||
Note that you might want to disable {option}`services.gophernicus.enableDefaultRootIndex` if you are
|
||||
modifying the contents of your root directory.
|
||||
'';
|
||||
default = "/var/lib/gophernicus/gopher";
|
||||
example = lib.literalExpression ''
|
||||
pkgs.symlinkJoin {
|
||||
name = "gophernicus-root-dir";
|
||||
paths = [
|
||||
(pkgs.writeTextDir "gophermap" '''
|
||||
iHello!
|
||||
|
||||
1Misc\tmisc
|
||||
''')
|
||||
(pkgs.writeTextDir "misc/info.txt" '''
|
||||
World
|
||||
''')
|
||||
];
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
enableDefaultRootIndex = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
description = "Whether to enable the example gophermap shipped with gophernicus as the default root index.";
|
||||
default = true;
|
||||
example = false;
|
||||
};
|
||||
|
||||
enableUserDirs = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
description = "Whether to host content from {file}`~/public_gopher` in user home directories.";
|
||||
default = true;
|
||||
example = false;
|
||||
};
|
||||
|
||||
listenStreams = lib.mkOption {
|
||||
description = ''
|
||||
Which sockets to bind to.
|
||||
|
||||
See {option}`systemd.sockets.«name».listenStreams`.
|
||||
'';
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ "127.0.0.1:70" ];
|
||||
example = [ "/run/gophernicus/gophernicus.sock" ];
|
||||
};
|
||||
|
||||
extraArgs = lib.mkOption {
|
||||
description = ''
|
||||
Extra commandline arguments to pass to {command}`gophernicus`.
|
||||
|
||||
See {manpage}`gophernicus(8)` for available arguments.
|
||||
'';
|
||||
type = lib.types.attrsOf lib.types.anything;
|
||||
default = { };
|
||||
example = {
|
||||
u = "gopher_stuff";
|
||||
w = 80;
|
||||
np = true;
|
||||
nx = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.gophernicus.path = opt.path.default;
|
||||
|
||||
systemd.packages = [ cfg.package ];
|
||||
|
||||
systemd.sockets."gophernicus" = {
|
||||
wantedBy = [ "sockets.target" ];
|
||||
listenStreams = [ "" ] ++ cfg.listenStreams;
|
||||
};
|
||||
|
||||
systemd.services."gophernicus@" = {
|
||||
documentation = [ "man:gophernicus(8)" ];
|
||||
serviceConfig = {
|
||||
DynamicUser = true;
|
||||
User = "gophernicus";
|
||||
Group = "gophernicus";
|
||||
|
||||
StateDirectory = [ "gophernicus/gopher" ];
|
||||
|
||||
RuntimeDirectory = [ "gophernicus/bin" ];
|
||||
BindReadOnlyPaths =
|
||||
let
|
||||
binDir = pkgs.symlinkJoin {
|
||||
name = "gophernicus-bin";
|
||||
paths = cfg.path;
|
||||
stripPrefix = "/bin";
|
||||
};
|
||||
in
|
||||
[
|
||||
"${binDir}:/run/gophernicus/bin"
|
||||
]
|
||||
++ lib.optionals (cfg.rootDir != opt.rootDir.default) [
|
||||
"${cfg.rootDir}:/var/lib/gophernicus/gopher"
|
||||
]
|
||||
++ lib.optionals cfg.enableDefaultRootIndex [
|
||||
"${cfg.package}/share/gophernicus/gopher/gophermap:/var/lib/gophernicus/gopher/gophermap"
|
||||
];
|
||||
|
||||
ExecStart =
|
||||
let
|
||||
args = lib.cli.toCommandLineShellGNU { } (
|
||||
{
|
||||
r = "/var/lib/gophernicus/gopher";
|
||||
h = cfg.domain;
|
||||
f = if cfg.filters != { } then pkgs.linkFarm "gophernicus-filters" cfg.filters else null;
|
||||
nu = !cfg.enableUserDirs;
|
||||
}
|
||||
// cfg.extraArgs
|
||||
);
|
||||
in
|
||||
[
|
||||
""
|
||||
"${lib.getExe cfg.package} ${args}"
|
||||
];
|
||||
|
||||
PrivateUsers = !cfg.enableUserDirs;
|
||||
ProtectHome = if cfg.enableUserDirs then "read-only" else true;
|
||||
|
||||
ProcSubset = "pid";
|
||||
ProtectProc = "invisible";
|
||||
UMask = "0077";
|
||||
CapabilityBoundingSet = "";
|
||||
NoNewPrivileges = true;
|
||||
ProtectSystem = "strict";
|
||||
PrivateTmp = true;
|
||||
PrivateDevices = true;
|
||||
ProtectHostname = true;
|
||||
ProtectClock = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectControlGroups = true;
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
"AF_UNIX"
|
||||
];
|
||||
RestrictNamespaces = true;
|
||||
LockPersonality = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
RemoveIPC = true;
|
||||
PrivateMounts = true;
|
||||
SystemCallArchitectures = "native";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
felixalbrigtsen
|
||||
h7x4
|
||||
];
|
||||
}
|
||||
@@ -793,6 +793,7 @@ in
|
||||
gollum = runTest ./gollum.nix;
|
||||
gonic = runTest ./gonic.nix;
|
||||
google-oslogin = runTest ./google-oslogin;
|
||||
gophernicus = runTest ./gophernicus.nix;
|
||||
gopro-tool = runTest ./gopro-tool.nix;
|
||||
goss = runTest ./goss.nix;
|
||||
gotenberg = runTest ./gotenberg.nix;
|
||||
|
||||
117
nixos/tests/gophernicus.nix
Normal file
117
nixos/tests/gophernicus.nix
Normal file
@@ -0,0 +1,117 @@
|
||||
{ pkgs, lib, ... }:
|
||||
{
|
||||
name = "gophernicus";
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
felixalbrigtsen
|
||||
h7x4
|
||||
];
|
||||
|
||||
containers.machine =
|
||||
{ options, ... }:
|
||||
{
|
||||
imports = [ ./common/user-account.nix ];
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
phetch
|
||||
];
|
||||
|
||||
users.users = {
|
||||
alice.homeMode = "755";
|
||||
bob.homeMode = "755";
|
||||
};
|
||||
|
||||
services.gophernicus = {
|
||||
enable = true;
|
||||
domain = "localhost";
|
||||
|
||||
path = options.services.gophernicus.path.default ++ [
|
||||
(pkgs.writeScriptBin "hello" ''printf "aaaaaaa\n"'')
|
||||
];
|
||||
|
||||
filters = {
|
||||
txt = pkgs.writeShellScript "gophernicus-test-filter-script" ''
|
||||
cat "$1"
|
||||
echo "world"
|
||||
'';
|
||||
php = "${pkgs.php}/bin/php";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testScript =
|
||||
let
|
||||
alice-hello = pkgs.writeText "gophernicus-test-alice-hello" ''
|
||||
Hi!
|
||||
'';
|
||||
bob-hello = pkgs.writeText "gophernicus-test-bob-hello" ''
|
||||
Hello!
|
||||
'';
|
||||
bob-custom-command = pkgs.writeText "gophernicus-test-bob-custom-command" ''
|
||||
=hello
|
||||
'';
|
||||
bob-php-cgi = pkgs.writeText "gophernicus-test-bob-php-cgi" ''
|
||||
#!${lib.getExe pkgs.php}
|
||||
<?php echo "Result: " . (1 + 1); ?>
|
||||
'';
|
||||
bob-filtered = pkgs.writeText "gophernicus-test-bob-filtered" ''
|
||||
hello
|
||||
'';
|
||||
bob-php-non-cgi = pkgs.writeText "gophernicus-test-bob-php-non-cgi" ''
|
||||
<?php echo "Result: " . (1 + 1); ?>
|
||||
'';
|
||||
in
|
||||
''
|
||||
machine.wait_for_unit("sockets.target")
|
||||
|
||||
def phetch_or_fail(path: str) -> str:
|
||||
result = machine.succeed(f"phetch -r gopher://localhost/{path}")
|
||||
|
||||
print("--- RESPONSE ---")
|
||||
print(result)
|
||||
print("----------------")
|
||||
|
||||
assert "Error:" not in result, "Found error in fetched content"
|
||||
assert "command not found" not in result, "Found missing command error in fetched content"
|
||||
|
||||
return result
|
||||
|
||||
with subtest("Fetch root pages"):
|
||||
content = phetch_or_fail("")
|
||||
assert "Welcome to Gophernicus!" in content, "Content not rendered properly"
|
||||
|
||||
content = phetch_or_fail("/server-status")
|
||||
assert "Total Accesses" in content, "Content not rendered properly"
|
||||
|
||||
content = phetch_or_fail("/caps.txt")
|
||||
assert "This is an automatically generated caps file." in content, "Content not rendered properly"
|
||||
|
||||
machine.succeed("runuser -u alice -- install -Dm755 -d /home/alice/public_gopher")
|
||||
machine.succeed("runuser -u bob -- install -Dm755 -d /home/bob/public_gopher")
|
||||
|
||||
with subtest("Fetch user pages"):
|
||||
machine.succeed("runuser -u alice -- install -Dm644 '${alice-hello}' /home/alice/public_gopher/hello")
|
||||
machine.succeed("runuser -u bob -- install -Dm644 '${bob-hello}' /home/bob/public_gopher/world")
|
||||
phetch_or_fail("1~alice/hello")
|
||||
phetch_or_fail("1~bob/world")
|
||||
|
||||
with subtest("Render gophermap with custom command"):
|
||||
machine.succeed("runuser -u bob -- install -Dm644 '${bob-custom-command}' /home/bob/public_gopher/custom/gophermap")
|
||||
content = phetch_or_fail("1~bob/custom")
|
||||
assert "aaaaaaa" in content, "Content not rendered properly"
|
||||
|
||||
with subtest("Render php as cgi"):
|
||||
machine.succeed("runuser -u bob -- install -Dm755 '${bob-php-cgi}' /home/bob/public_gopher/cgi-bin/php-cgi.php")
|
||||
content = phetch_or_fail("1~bob/cgi-bin/php-cgi.php")
|
||||
assert "Result: 2" in content, "Content not rendered properly"
|
||||
|
||||
with subtest("Render filters"):
|
||||
machine.succeed("runuser -u bob -- install -Dm644 '${bob-filtered}' /home/bob/public_gopher/filtered.txt")
|
||||
content = phetch_or_fail("1~bob/filtered.txt")
|
||||
assert "hello" in content, "Content not rendered properly"
|
||||
assert "world" in content, "Content not rendered properly"
|
||||
|
||||
machine.succeed("runuser -u bob -- install -Dm644 '${bob-php-non-cgi}' /home/bob/public_gopher/filtered.php")
|
||||
content = phetch_or_fail("1~bob/filtered.php")
|
||||
assert "Result: 2" in content, "Content not rendered properly"
|
||||
'';
|
||||
}
|
||||
124
pkgs/by-name/go/gophernicus/package.nix
Normal file
124
pkgs/by-name/go/gophernicus/package.nix
Normal file
@@ -0,0 +1,124 @@
|
||||
{
|
||||
lib,
|
||||
stdenv,
|
||||
buildPackages,
|
||||
fetchFromGitHub,
|
||||
gnused,
|
||||
systemdMinimal,
|
||||
systemdSupport ? lib.meta.availableOn stdenv.hostPlatform systemdMinimal,
|
||||
xinetd,
|
||||
xinetdSupport ? lib.meta.availableOn stdenv.hostPlatform xinetd,
|
||||
versionCheckHook,
|
||||
nix-update-script,
|
||||
nixosTests,
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "gophernicus";
|
||||
version = "3.1.1";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "gophernicus";
|
||||
repo = "gophernicus";
|
||||
tag = finalAttrs.version;
|
||||
hash = "sha256-pweiUiMmLXiyF9NMxvcWfJPH6JiGRlpT4chJiRGh9vg=";
|
||||
};
|
||||
|
||||
postPatch = ''
|
||||
substituteInPlace README.md \
|
||||
--replace-warn 'DEVEL' '${finalAttrs.version}'
|
||||
|
||||
substituteInPlace src/gophernicus.h \
|
||||
--replace-fail 'SAFE_PATH "/usr/bin:/bin"' 'SAFE_PATH "/usr/bin:/bin:/run/gophernicus/bin"'
|
||||
|
||||
substituteInPlace init/gophernicus.xinetd.in \
|
||||
--replace-fail ' -h@HOSTNAME@' '''
|
||||
|
||||
substituteInPlace init/gophernicus.env.in \
|
||||
--replace-fail '-h @HOSTNAME@ ' '''
|
||||
|
||||
substituteInPlace init/org.gophernicus.server.plist.in \
|
||||
--replace-fail '${"\t\t"}<string>-h@HOSTNAME@</string>${"\n"}' ''' \
|
||||
--replace-fail '/usr/local/sbin' '${placeholder "out"}/sbin'
|
||||
|
||||
substituteInPlace init/gophernicus@.service.in \
|
||||
--replace-fail 'User=nobody' '''
|
||||
|
||||
substituteInPlace Makefile.in \
|
||||
--replace-fail \
|
||||
'$(INSTALL) -s' \
|
||||
'$(INSTALL) -s --strip-program=${stdenv.cc.targetPrefix}strip' \
|
||||
--replace-fail \
|
||||
'$(INSTALL) -m 644 init/$(PLIST) $(DESTDIR)$(LAUNCHD)' \
|
||||
'$(INSTALL) -Dm 644 -t $(DESTDIR)$(LAUNCHD) init/$(PLIST)'
|
||||
|
||||
sed -E -i '/^\s+(chown|chmod)/d' Makefile.in
|
||||
'';
|
||||
|
||||
configurePlatforms = [ ];
|
||||
dontAddStaticConfigureFlags = true;
|
||||
configureFlags = [
|
||||
"--prefix=/"
|
||||
"--gopherroot=/share/gophernicus/gopher"
|
||||
"--os=${
|
||||
if stdenv.hostPlatform.isDarwin then
|
||||
"mac"
|
||||
else if stdenv.hostPlatform.isLinux then
|
||||
"linux"
|
||||
else if stdenv.hostPlatform.isBSD then
|
||||
"freebsd"
|
||||
else
|
||||
"autodetected"
|
||||
}"
|
||||
]
|
||||
++ lib.optionals systemdSupport [
|
||||
"--listener=systemd"
|
||||
]
|
||||
++ lib.optionals xinetdSupport [
|
||||
"--listener=xinetd"
|
||||
]
|
||||
++ lib.optionals stdenv.hostPlatform.isDarwin [
|
||||
"--listener=mac"
|
||||
];
|
||||
|
||||
env = lib.optionalAttrs (!stdenv.buildPlatform.canExecute stdenv.hostPlatform) {
|
||||
HOSTCC = "${buildPackages.stdenv.cc}/bin/cc";
|
||||
CC = "${stdenv.cc.targetPrefix}cc";
|
||||
};
|
||||
|
||||
makeFlags = [
|
||||
"DESTDIR=${placeholder "out"}"
|
||||
];
|
||||
|
||||
strictDeps = true;
|
||||
__structuredAttrs = true;
|
||||
|
||||
installTargets = [
|
||||
"install"
|
||||
]
|
||||
++ lib.optionals systemdSupport [
|
||||
"install-systemd"
|
||||
];
|
||||
|
||||
doInstallCheck = true;
|
||||
nativeInstallCheckInputs = [ versionCheckHook ];
|
||||
versionCheckProgramArg = "-v";
|
||||
|
||||
passthru = {
|
||||
updateScript = nix-update-script { };
|
||||
tests.nixos = nixosTests.gophernicus;
|
||||
};
|
||||
|
||||
meta = {
|
||||
description = "Modern full-featured (and hopefully) secure gopher daemon";
|
||||
homepage = "https://gophernicus.org/";
|
||||
changelog = "https://github.com/gophernicus/gophernicus/blob/${finalAttrs.src.tag}/changelog";
|
||||
license = lib.licenses.bsd2;
|
||||
platforms = lib.platforms.unix;
|
||||
maintainers = with lib.maintainers; [
|
||||
felixalbrigtsen
|
||||
h7x4
|
||||
];
|
||||
mainProgram = "gophernicus";
|
||||
};
|
||||
})
|
||||
Reference in New Issue
Block a user