11 Commits

Author SHA1 Message Date
98797b25cf ci: override github access token
All checks were successful
CI / checks (nur) (push) Successful in 4m0s
CI / build-and-update (xeals, xeals) (push) Successful in 5m6s
CI / checks (nur) (pull_request) Successful in 3m8s
CI / build-and-update (xeals, xeals) (pull_request) Successful in 3m3s
2023-11-14 22:06:28 +11:00
0a0ce21db9 ci: downgrade actions/checkout to v3
Some checks failed
CI / build-and-update (xeals, xeals) (push) Successful in 6m10s
CI / checks (nur) (push) Failing after 47s
v4 is not mirrored by Gitea
2023-11-14 21:28:19 +11:00
c1563bf348 ci: namespace all uses 2023-11-14 21:23:39 +11:00
f496e54902 ci: move github workflows to gitea 2023-11-14 21:22:13 +11:00
4720d618ae flake: update inputs (#71)
Some checks failed
CI / checks (nur) (push) Failing after 1m35s
CI / build-and-update (xeals, xeals) (push) Failing after 1s
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/a0b3b06b7a82c965ae0bb1d59f6e386fe755001d' (2023-11-05)
  → 'github:NixOS/nixpkgs/911ad1e67f458b6bcf0278fa85e33bb9924fed7e' (2023-11-11)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-11-14 21:18:55 +11:00
0fe44e3a8b atlauncher: 3.4.34.0 -> 3.4.35.2 2023-11-13 09:28:45 +11:00
ef2a2412ff monaspace: init at 1.000 2023-11-10 10:45:21 +11:00
149270cfb1 modules/porkbun-ddns: init 2023-11-09 09:50:08 +11:00
273d1906e1 porkbun-ddns: init 2023-11-09 09:46:17 +11:00
a28eebd24f flake: update inputs (#70)
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/90e85bc7c1a6fc0760a94ace129d3a1c61c3d035' (2023-10-29)
  → 'github:NixOS/nixpkgs/a0b3b06b7a82c965ae0bb1d59f6e386fe755001d' (2023-11-05)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-11-06 22:40:14 +00:00
2fb4aa7a7d flake: update inputs (#69)
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/51d906d2341c9e866e48c2efcaac0f2d70bfd43e' (2023-10-21)
  → 'github:NixOS/nixpkgs/90e85bc7c1a6fc0760a94ace129d3a1c61c3d035' (2023-10-29)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-10-31 02:20:44 +00:00
11 changed files with 371 additions and 10 deletions

View File

@ -14,8 +14,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- uses: cachix/install-nix-action@v23
uses: https://gitea.com/actions/checkout@v3
- name: Install nix
uses: https://github.com/cachix/install-nix-action@v23
with:
github_access_token: ${{ secrets.INPUT_GITHUB_ACCESS_TOKEN }}
- name: Check ${{ matrix.check }}
# Depends on nixos/nix#7759 to simply `nix flake check`
run: nix run .#checks.$(nix eval --raw --impure --expr "builtins.currentSystem").${{ matrix.check }}
@ -43,13 +46,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: https://gitea.com/actions/checkout@v3
- name: Install nix
uses: cachix/install-nix-action@v23
uses: https://github.com/cachix/install-nix-action@v23
- name: Show nixpkgs version
run: nix eval --impure --expr '(import ./flake-compat.nix { src = ./.; }).lib.version'
- name: Setup cachix
uses: cachix/cachix-action@v12
uses: https://github.com/cachix/cachix-action@v12
if: ${{ matrix.cachixName != '<YOUR_CACHIX_NAME>' }}
with:
name: ${{ matrix.cachixName }}

6
flake.lock generated
View File

@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1697915759,
"narHash": "sha256-WyMj5jGcecD+KC8gEs+wFth1J1wjisZf8kVZH13f1Zo=",
"lastModified": 1699725108,
"narHash": "sha256-NTiPW4jRC+9puakU4Vi8WpFEirhp92kTOSThuZke+FA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "51d906d2341c9e866e48c2efcaac0f2d70bfd43e",
"rev": "911ad1e67f458b6bcf0278fa85e33bb9924fed7e",
"type": "github"
},
"original": {

View File

@ -4,6 +4,7 @@
amdgpu-pwm = ./services/hardware/amdgpu-pwm.nix;
betanin = ./services/web-apps/betanin.nix;
dunst = ./services/x11/dunst.nix;
porkbun-ddns = ./services/networking/porkbun-ddns.nix;
radeon-profile-daemon = ./services/hardware/radeon-profile-daemon.nix;
}

View File

@ -0,0 +1,74 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkOption types;
cfg = config.services.porkbun-ddns;
in
{
options = {
services.porkbun-ddns = {
enable = lib.mkEnableOption "Porkbun dynamic DNS client";
package = mkOption {
# TODO: How do I use mkPackageOption when the package isn't in the
# package set?
type = types.package;
default = pkgs.callPackage ../../../pkgs/by-name/po/porkbun-ddns/package.nix { };
defaultText = "pkgs.porkbun-ddns";
description = lib.mdDoc "The porkbun-ddns package to use.";
};
interval = mkOption {
type = types.str;
default = "10m";
description = lib.mdDoc ''
Interval to update dynamic DNS records. The default is to update every
10 minutes. The format is described in {manpage}`systemd.time(7)`.
'';
};
domains = mkOption {
type = types.listOf types.str;
default = [ ];
description = lib.mdDoc "Domains to update.";
};
apiKeyFile = mkOption {
type = types.nullOr types.path;
description = lib.mdDoc ''
File containing the API key to use when running the client.
'';
};
secretApiKeyFile = mkOption {
type = types.nullOr types.path;
description = lib.mdDoc ''
File containing the secret API key to use when running the
client.
'';
};
};
};
config = lib.mkIf cfg.enable {
systemd.services.porkbun-ddns = {
description = "Porkbun dynamic DNS client";
script = ''
${cfg.package}/bin/porkbun-ddns \
-K ${cfg.apiKeyFile} \
-S ${cfg.secretApiKeyFile} \
${lib.concatStringsSep " " cfg.domains}
'';
};
systemd.timers.porkbun-ddns = {
description = "Porkbun dynamic DNS client";
wants = [ "network-online.target" ];
wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = cfg.interval;
OnUnitActiveSec = cfg.interval;
};
};
};
}

View File

@ -9,11 +9,11 @@
stdenv.mkDerivation rec {
pname = "atlauncher";
version = "3.4.34.0";
version = "3.4.35.2";
src = fetchurl {
url = "https://github.com/ATLauncher/ATLauncher/releases/download/v${version}/ATLauncher-${version}.jar";
hash = "sha256-gHUYZaxADchikoCmAfqFjVbMYhhiwg2BZKctmww1Mlw=";
hash = "sha256-CVJQGMnETW9BOn2To09/UuLrseNfovUyEFhcz/zyHOQ=";
};
dontUnpack = true;

View File

@ -0,0 +1,25 @@
{ lib
, stdenv
, python3
}:
let
python = python3.withPackages (py: [ py.requests ]);
in
stdenv.mkDerivation {
name = "porkbun-ddns";
src = ./.;
inherit python;
installPhase = ''
mkdir -p $out/bin
install -Dm0755 $src/porkbun-ddns.py $out/bin/porkbun-ddns
substituteAllInPlace $out/bin/porkbun-ddns
'';
meta = {
description = "Porkbun dynamic DNS script";
license = lib.licenses.gpl3;
platforms = python.meta.platforms;
};
}

View File

@ -0,0 +1,176 @@
#!@python@/bin/python
import argparse
import json
import os
import re
import requests
from dataclasses import dataclass, fields as datafields
from enum import Enum, unique
from typing import List, Optional
APIBASE = "https://porkbun.com/api/json/v3/dns"
def dataclass_from_dict(klass: object, d: dict):
try:
fieldtypes = {f.name: f.type for f in datafields(klass)}
return klass(**{f: dataclass_from_dict(fieldtypes[f], d[f]) for f in d})
except:
return d # Not a dataclass field
def remove_domain(domain: str, name: str):
return re.sub(f"\\.?{domain}$", "", name)
@unique
class RecordType(Enum):
a = "A"
aaaa = "AAAA"
cname = "CNAME"
mx = "MX"
srv = "SRV"
txt = "TXT"
@dataclass
class Record:
id: str
name: str
type: str
content: str
ttl: str
prio: str = ""
notes: str = ""
@dataclass
class Retrieval:
status: str
records: List[Record]
class ApiError(Exception):
pass
class ArgumentError(Exception):
pass
class PorkbunClient:
def __init__(self, apikey: str, secretapikey: str):
self.apikey = apikey
self.secretapikey = secretapikey
def _make_payload(self, **kwargs):
return json.dumps(
{"apikey": self.apikey, "secretapikey": self.secretapikey, **kwargs}
)
def edit_record(
self,
domain: str,
record: Record,
name: Optional[str] = None,
type: Optional[RecordType] = None,
content: Optional[str] = None,
ttl: Optional[int] = None,
priority: Optional[str] = None,
) -> bool:
return self.edit(
domain,
record.id,
name=name or record.name,
type=type or RecordType(record.type),
content=content or record.content,
ttl=ttl or record.ttl,
priority=priority or record.prio,
)
def edit(
self,
domain: str,
id: str,
name: str,
type: RecordType,
content: str,
ttl: int = 300,
priority: Optional[str] = None,
) -> bool:
# API returns FQN name rather than the actual prefix, so scrub it
name = remove_domain(domain, name)
payload = self._make_payload(
name=name, type=type.value, content=content, ttl=str(ttl), prio=priority
)
res = requests.post(f"{APIBASE}/edit/{domain}/{id}", data=payload)
body = res.json()
if body["status"] != "SUCCESS":
raise ApiError(body["message"])
return True
def delete(self, domain: str, id: str) -> bool:
payload = self._make_payload()
res = requests.post(f"{APIBASE}/delete/{domain}/{id}", data=payload)
body = res.json()
if body["status"] != "SUCCESS":
raise ApiError(body["message"])
return True
def retrieve(self, domain: str) -> List[Retrieval]:
payload = self._make_payload()
res = requests.post(f"{APIBASE}/retrieve/{domain}", data=payload)
body = res.json()
if body["status"] != "SUCCESS":
raise ApiError(body["message"])
return [dataclass_from_dict(Record, d) for d in body["records"]]
def current_ip() -> str:
return requests.get("https://ifconfig.me").text
def _load_key(key: Optional[str], keyfile: Optional[str]) -> str:
if keyfile is not None:
with open(keyfile) as f:
return f.read().strip()
if key is not None:
return key
raise ArgumentError("key or key file is required")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Wrapper around Porkbun DNS API")
keyarg = parser.add_mutually_exclusive_group(required=True)
keyarg.add_argument("-k", "--key", metavar="KEY", type=str, help="API key")
keyarg.add_argument(
"-K", "--key-file", metavar="FILE", type=str, help="API key file"
)
secretarg = parser.add_mutually_exclusive_group(required=True)
secretarg.add_argument(
"-s", "--secret", metavar="SECRET", type=str, help="secret API key"
)
secretarg.add_argument(
"-S", "--secret-file", metavar="FILE", type=str, help="secret API key file"
)
parser.add_argument("domains", type=str, nargs="+", help="domain(s) to update")
args = parser.parse_args()
try:
apikey = _load_key(args.key, args.key_file)
secretapikey = _load_key(args.secret, args.secret_file)
except Exception as e:
print("error: " + str(e))
parser.print_help()
exit(1)
current_ip = current_ip()
client = PorkbunClient(apikey, secretapikey)
for domain in args.domains:
recs = client.retrieve(domain)
arecs = [r for r in recs if r.type == RecordType.a.value]
for arec in arecs:
if arec.content != current_ip:
client.edit_record(domain, arec, content=current_ip)
print(f"Pointed '{arec.name}' to {current_ip}")

View File

@ -0,0 +1,73 @@
{ lib
, stdenvNoCC
, fetchFromGitHub
}:
let
mkMonaspace =
{ pname
, variants ? [ ]
}: stdenvNoCC.mkDerivation rec {
inherit pname;
version = "1.000";
src = fetchFromGitHub {
owner = "githubnext";
repo = "monaspace";
rev = "v${version}";
hash = "sha256-Zo56r0QoLwxwGQtcWP5cDlasx000G9BFeGINvvwEpQs=";
};
_variants = map (builtins.replaceStrings [ " " ] [ "" ]) variants;
installPhase = ''
local out_font=$out/share/fonts/monaspace
'' + (if variants == [ ] then ''
install -m444 -Dt $out_font fonts/otf/*.otf
install -m444 -Dt $out_font fonts/variable/*.ttf
'' else ''
for variant in $_variants; do
install -m444 -Dt $out_font fonts/otf/"$variant"-*.otf
install -m444 -Dt $out_font fonts/variable/"$variant"Var*.ttf
done
'');
meta = {
description = "An innovative superfamily of fonts for code";
homepage = "https://monaspace.githubnext.com/";
longDescription = ''
Since the earliest days of the teletype machine, code has been set in
monospaced typeletters, on a grid. Monaspace is a new type system
that advances the state of the art for the display of code on screen.
'';
license = lib.licenses.ofl;
platforms = lib.platforms.all;
};
};
in
{
monaspace = mkMonaspace {
pname = "monaspace";
};
monaspace-argon = mkMonaspace {
pname = "monaspace-argon";
variants = [ "Monaspace Argon" ];
};
monaspace-krypton = mkMonaspace {
pname = "monaspace-krypton";
variants = [ "Monaspace Krypton" ];
};
monaspace-neon = mkMonaspace {
pname = "monaspace-neon";
variants = [ "Monaspace Neon" ];
};
monaspace-radon = mkMonaspace {
pname = "monaspace-radon";
variants = [ "Monaspace Radon" ];
};
monaspace-xenon = mkMonaspace {
pname = "monaspace-xenon";
variants = [ "Monaspace Xenon" ];
};
}

View File

@ -21,6 +21,15 @@ rec {
ideaUltimateWithPlugins = ideaUltimatePlugins.jetbrainsWithPlugins;
};
monaspace-fonts = pkgs.callPackage ../data/fonts/monaspace/default.nix { };
inherit (monaspace-fonts)
monaspace
monaspace-argon
monaspace-krypton
monaspace-neon
monaspace-radon
monaspace-xenon;
mopidy-subidy = pkgs.callPackage ../applications/audio/mopidy/subidy.nix {
python3Packages = pkgs.python3Packages // python3Packages;
};