make .onion domains declarative, site updates, add helpers
This commit is contained in:
parent
b3d2a34bc0
commit
450a5ce1d6
25 changed files with 341 additions and 109 deletions
79
helpers/services.nix
Normal file
79
helpers/services.nix
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
cfg = config.distrust.services;
|
||||
in {
|
||||
options = {
|
||||
distrust = {
|
||||
services = lib.mkOption {
|
||||
description = "Services configuration map";
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule {
|
||||
options = {
|
||||
url = lib.mkOption {
|
||||
description = "Clearnet URL";
|
||||
type = lib.types.str;
|
||||
};
|
||||
onion = lib.mkOption {
|
||||
description = "Onion service settings";
|
||||
type = lib.types.submodule {
|
||||
options = {
|
||||
url = lib.mkOption {
|
||||
description = ".onion URL";
|
||||
type = lib.types.str;
|
||||
};
|
||||
secretKey = lib.mkOption {
|
||||
description = "Path to onion secret key file";
|
||||
type = lib.types.path;
|
||||
};
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
};
|
||||
virtualHostConfig = lib.mkOption {
|
||||
description = "Caddy virtual host config";
|
||||
type = lib.types.str;
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
services.tor.relay.onionServices =
|
||||
builtins.foldl'
|
||||
(acc: key:
|
||||
acc
|
||||
// {
|
||||
"${key}" = {
|
||||
map = [80];
|
||||
inherit (cfg.${key}.onion) secretKey;
|
||||
};
|
||||
})
|
||||
{}
|
||||
(builtins.attrNames cfg);
|
||||
|
||||
services.caddy = {
|
||||
enable = true;
|
||||
virtualHosts = builtins.foldl' (acc: key: let
|
||||
site = cfg.${key};
|
||||
vhostKey = "${site.url} ${site.onion.url}";
|
||||
extraCfg = ''
|
||||
${site.virtualHostConfig or ""}
|
||||
header Onion-Location ${site.onion.url}
|
||||
'';
|
||||
in
|
||||
acc
|
||||
// {
|
||||
"${vhostKey}" = {
|
||||
extraConfig = extraCfg;
|
||||
};
|
||||
}) {} (builtins.attrNames cfg);
|
||||
};
|
||||
};
|
||||
}
|
||||
84
helpers/tor-hostname.nix
Normal file
84
helpers/tor-hostname.nix
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
{pkgs ? import <nixpkgs> {}}:
|
||||
pkgs.python3Packages.buildPythonApplication rec {
|
||||
pname = "tor-hostname";
|
||||
version = "1.0.0";
|
||||
|
||||
format = "other";
|
||||
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [
|
||||
pynacl
|
||||
cryptography
|
||||
];
|
||||
|
||||
dontUnpack = true;
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin
|
||||
cat > $out/bin/tor-hostname <<'EOF'
|
||||
#!/usr/bin/env python3
|
||||
"""Convert Tor v3 secret key to .onion hostname"""
|
||||
|
||||
import hashlib
|
||||
import base64
|
||||
import sys
|
||||
|
||||
def onion_address_from_public_key(public_key):
|
||||
"""Generate .onion address from ed25519 public key"""
|
||||
version = b'\x03'
|
||||
checksum = hashlib.sha3_256(b'.onion checksum' + public_key + version).digest()[:2]
|
||||
onion_address = base64.b32encode(public_key + checksum + version).decode().lower()
|
||||
return f"{onion_address}.onion"
|
||||
|
||||
def read_tor_secret_key(filepath):
|
||||
"""Read Tor hs_ed25519_secret_key file"""
|
||||
with open(filepath, 'rb') as f:
|
||||
content = f.read()
|
||||
|
||||
header = b'== ed25519v1-secret: type0 ==\x00\x00\x00'
|
||||
|
||||
if not content.startswith(header):
|
||||
raise ValueError("Invalid Tor secret key file format")
|
||||
|
||||
expanded_key = content[32:96]
|
||||
return expanded_key
|
||||
|
||||
def derive_public_from_expanded_secret(expanded_key):
|
||||
"""Derive ed25519 public key from 64-byte expanded secret key"""
|
||||
from nacl.bindings import crypto_scalarmult_ed25519_base_noclamp
|
||||
|
||||
secret_scalar = expanded_key[:32]
|
||||
public_key = crypto_scalarmult_ed25519_base_noclamp(secret_scalar)
|
||||
return public_key
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
print(f"Usage: {sys.argv[0]} <path_to_hs_ed25519_secret_key>")
|
||||
sys.exit(1)
|
||||
|
||||
secret_key_path = sys.argv[1]
|
||||
|
||||
try:
|
||||
expanded_key = read_tor_secret_key(secret_key_path)
|
||||
public_key = derive_public_from_expanded_secret(expanded_key)
|
||||
hostname = onion_address_from_public_key(public_key)
|
||||
print(hostname)
|
||||
except FileNotFoundError:
|
||||
print(f"Error: File not found: {secret_key_path}")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
EOF
|
||||
|
||||
chmod +x $out/bin/tor-hostname
|
||||
'';
|
||||
|
||||
meta = with pkgs.lib; {
|
||||
description = "Convert Tor v3 secret key to .onion hostname";
|
||||
license = licenses.mit;
|
||||
platforms = platforms.unix;
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue