rearrange
This commit is contained in:
parent
c4dc259881
commit
f8bd9bd885
7 changed files with 0 additions and 1 deletions
69
modules/dictionary.nix
Normal file
69
modules/dictionary.nix
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
{ pkgs, ... }:
|
||||
|
||||
let
|
||||
# Create dictionary setup script that downloads and extracts dictionaries
|
||||
setupDictionaries = pkgs.writeShellScript "setup-dictionaries" ''
|
||||
# Create dictionary directory
|
||||
mkdir -p "$HOME/.stardict/dic"
|
||||
|
||||
# Function to download and extract dictionary
|
||||
download_dict() {
|
||||
local url="$1"
|
||||
local filename="$2"
|
||||
local extract_dir="$HOME/.stardict/dic"
|
||||
|
||||
if [ ! -f "$extract_dir/.$(basename $filename)-extracted" ]; then
|
||||
echo "Downloading $filename..."
|
||||
if ${pkgs.curl}/bin/curl -L -o "/tmp/$filename" "$url"; then
|
||||
echo "Extracting $filename..."
|
||||
${pkgs.gnutar}/bin/tar -xf "/tmp/$filename" -C "$extract_dir" --strip-components=1 2>/dev/null || \
|
||||
${pkgs.gnutar}/bin/tar -xf "/tmp/$filename" -C "$extract_dir" 2>/dev/null || true
|
||||
|
||||
# Clean up
|
||||
rm -f "/tmp/$filename"
|
||||
touch "$extract_dir/.$(basename $filename)-extracted"
|
||||
echo "$filename setup complete!"
|
||||
else
|
||||
echo "Failed to download $filename"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Download dictionaries (using working URLs)
|
||||
download_dict "https://web.archive.org/web/20200702203642/http://download.huzheng.org/dict.org/stardict-dictd_www.dict.org_gcide-2.4.2.tar.bz2" "gcide-dict.tar.bz2"
|
||||
download_dict "https://cyphar.github.io/jpn-stardicts/JMdict-ja-en.tar.gz" "jmdict-ja-en.tar.gz"
|
||||
|
||||
echo "Dictionary setup process completed!"
|
||||
'';
|
||||
|
||||
in
|
||||
{
|
||||
home.packages = with pkgs; [
|
||||
sdcv
|
||||
curl # For downloading dictionaries
|
||||
gnutar # For extracting dictionaries
|
||||
];
|
||||
|
||||
# Environment variable for dictionary location
|
||||
home.sessionVariables = {
|
||||
STARDICT_DATA_DIR = "$HOME/.stardict/dic";
|
||||
};
|
||||
|
||||
# Note: Dictionary files will be downloaded automatically when you first run 'dict-setup'
|
||||
# or you can run the setup manually at any time
|
||||
|
||||
# Shell aliases for different dictionary types
|
||||
programs.zsh.shellAliases = {
|
||||
# English-English dictionary
|
||||
"e2e" = "sdcv";
|
||||
|
||||
# Japanese-English dictionary
|
||||
"j2e" = "sdcv -u JMdict-ja-en";
|
||||
|
||||
# English-Japanese dictionary (same as Japanese-English - JMdict is bidirectional)
|
||||
"e2j" = "sdcv -u JMdict-ja-en";
|
||||
|
||||
# Manual dictionary setup
|
||||
"dict-setup" = toString setupDictionaries;
|
||||
};
|
||||
}
|
||||
62
modules/dufs.nix
Normal file
62
modules/dufs.nix
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
cfg = config.services.dufs;
|
||||
authFile = "/etc/dufs-auth";
|
||||
in
|
||||
{
|
||||
options.services.dufs = {
|
||||
sharedPath = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
description = "Path to the folder to share via WebDAV. Set to null to disable dufs.";
|
||||
example = "/mnt/storage/shared";
|
||||
};
|
||||
|
||||
port = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 5099;
|
||||
description = "Port to listen on";
|
||||
};
|
||||
|
||||
user = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "root";
|
||||
description = "User account under which dufs runs";
|
||||
};
|
||||
|
||||
group = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "root";
|
||||
description = "Group under which dufs runs";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf (cfg.sharedPath != null) {
|
||||
# Install dufs package
|
||||
environment.systemPackages = [ pkgs.dufs ];
|
||||
|
||||
# Create systemd service
|
||||
# NOTE: Authentication credentials must be manually created in /etc/dufs-auth
|
||||
# The file should contain a single line in format: username:password
|
||||
# Make sure to set permissions: chmod 600 /etc/dufs-auth
|
||||
systemd.services.dufs = {
|
||||
description = "Dufs WebDAV File Server";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
UMask = "0022";
|
||||
ExecStart = ''/bin/sh -c "${pkgs.dufs}/bin/dufs ${cfg.sharedPath} --port ${toString cfg.port} --bind 0.0.0.0 --allow-all --auth $(cat ${authFile})@/:rw"'';
|
||||
Restart = "on-failure";
|
||||
RestartSec = "10s";
|
||||
};
|
||||
};
|
||||
|
||||
# Open firewall port (optional, since traffic comes through WireGuard)
|
||||
# networking.firewall.allowedTCPPorts = [ cfg.port ];
|
||||
};
|
||||
}
|
||||
25
modules/miniflux.nix
Normal file
25
modules/miniflux.nix
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
cfg = config.services.miniflux-custom;
|
||||
in
|
||||
{
|
||||
options.services.miniflux-custom = {
|
||||
port = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 8070;
|
||||
description = "Port for Miniflux to listen on";
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
services.miniflux = {
|
||||
enable = true;
|
||||
adminCredentialsFile = "/etc/miniflux-admin-credentials";
|
||||
config = {
|
||||
LISTEN_ADDR = "0.0.0.0:${toString cfg.port}";
|
||||
BASE_URL = "https://rss.yanlincs.com";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
52
modules/ntfy.nix
Normal file
52
modules/ntfy.nix
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
cfg = config.services.ntfy-custom;
|
||||
in
|
||||
{
|
||||
options.services.ntfy-custom = {
|
||||
port = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 8080;
|
||||
description = "Port for ntfy to listen on";
|
||||
};
|
||||
|
||||
baseUrl = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "https://ntfy.yanlincs.com";
|
||||
description = "Base URL for ntfy server";
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
services.ntfy-sh = {
|
||||
enable = true;
|
||||
settings = {
|
||||
listen-http = ":${toString cfg.port}";
|
||||
base-url = cfg.baseUrl;
|
||||
|
||||
# iOS push notification support
|
||||
upstream-base-url = "https://ntfy.sh";
|
||||
|
||||
# Authentication
|
||||
auth-file = "/var/lib/ntfy-sh/user.db";
|
||||
auth-default-access = "deny-all";
|
||||
|
||||
# File attachments
|
||||
attachment-cache-dir = "/var/lib/ntfy-sh/attachments";
|
||||
};
|
||||
};
|
||||
|
||||
# Ensure required directories exist
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /var/lib/ntfy-sh 0755 ntfy-sh ntfy-sh -"
|
||||
"d /var/lib/ntfy-sh/attachments 0755 ntfy-sh ntfy-sh -"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
# NOTE: After deployment, manage users via ntfy CLI:
|
||||
# sudo ntfy user add <username>
|
||||
# sudo ntfy user change-pass <username>
|
||||
# sudo ntfy access <username> <topic> <read-write|read-only|write-only|deny-all>
|
||||
# Example: sudo ntfy access alice "*" read-write
|
||||
179
modules/papis.nix
Normal file
179
modules/papis.nix
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
{ pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
# Platform-aware papis config directory
|
||||
papisConfigDir = if pkgs.stdenv.isDarwin then "Library/Application Support/papis" else ".config/papis";
|
||||
in
|
||||
|
||||
{
|
||||
# Install papis package
|
||||
home.packages = [
|
||||
(pkgs.symlinkJoin {
|
||||
name = "papis-wrapped";
|
||||
paths = [
|
||||
(pkgs.papis.overridePythonAttrs (old: {
|
||||
doCheck = false;
|
||||
}))
|
||||
];
|
||||
buildInputs = [ pkgs.makeWrapper ];
|
||||
postBuild = ''
|
||||
wrapProgram $out/bin/papis \
|
||||
--set PYTHONWARNINGS "ignore::UserWarning"
|
||||
'';
|
||||
})
|
||||
];
|
||||
# Papis configuration
|
||||
home.file."${papisConfigDir}/config".text = ''
|
||||
[settings]
|
||||
default-library = main
|
||||
editor = nvim
|
||||
opentool = ${if pkgs.stdenv.isDarwin then "open -a Preview" else "evince"}
|
||||
|
||||
# Document management
|
||||
ref-format = {doc[author]}{doc[year]}
|
||||
|
||||
# Search and display
|
||||
sort-field = year
|
||||
sort-reverse = True
|
||||
match-format = {doc[tags]}{doc[author]}{doc[title]}{doc[year]}
|
||||
|
||||
# Database and storage
|
||||
database-backend = papis
|
||||
use-git = False
|
||||
|
||||
# Interface
|
||||
fzf-binary = fzf
|
||||
picktool = fzf
|
||||
|
||||
[main]
|
||||
dir = ~/Documents/app-state/papis
|
||||
|
||||
# Local configuration for the main library
|
||||
local-config-file = .papisrc
|
||||
'';
|
||||
|
||||
# Create the papis library directory
|
||||
home.activation.createPapisDir = ''
|
||||
mkdir -p ~/Documents/app-state/papis
|
||||
'';
|
||||
|
||||
# Papis bibliography template
|
||||
home.file."${papisConfigDir}/templates/bibitem.template".text = ''
|
||||
{doc[title]} ({doc[year]}). {doc[author]}.
|
||||
Venue: {doc[journal]} {doc[booktitle]} {doc[eprinttype]} {doc[eprint]} {doc[eventtitle]}
|
||||
Tags: {doc[tags]}
|
||||
URL: {doc[url]}
|
||||
---
|
||||
'';
|
||||
|
||||
# Papis BibTeX template
|
||||
home.file."${papisConfigDir}/templates/bibtex.template".text = ''
|
||||
@{doc[type]}{{{doc[ref]},
|
||||
author = {{{doc[author]}}},
|
||||
title = {{{doc[title]}}},
|
||||
year = {{{doc[year]}}},
|
||||
journal = {{{doc[journal]}}},
|
||||
booktitle = {{{doc[booktitle]}}},
|
||||
volume = {{{doc[volume]}}},
|
||||
number = {{{doc[number]}}},
|
||||
pages = {{{doc[pages]}}},
|
||||
doi = {{{doc[doi]}}},
|
||||
url = {{{doc[url]}}}
|
||||
}}
|
||||
'';
|
||||
|
||||
# Papis citation template
|
||||
home.file."${papisConfigDir}/templates/citation.template".text = ''
|
||||
{doc[author]}. "{doc[title]}." {doc[journal]}{doc[booktitle]} ({doc[year]}).
|
||||
'';
|
||||
|
||||
# Shell aliases for papis workflow
|
||||
programs.zsh.shellAliases = {
|
||||
# Bibliography formatting
|
||||
pals = "papis list --template \"$HOME/${papisConfigDir}/templates/bibitem.template\"";
|
||||
|
||||
# Add new entry with bibtex
|
||||
paadd = "papis add --from bibtex";
|
||||
|
||||
# Remove/delete entries
|
||||
parm = "papis rm";
|
||||
|
||||
# BibTeX export
|
||||
pabib = "papis list --template \"$HOME/${papisConfigDir}/templates/bibtex.template\"";
|
||||
|
||||
# Citation formatting
|
||||
pacite = "papis list --template \"$HOME/${papisConfigDir}/templates/citation.template\"";
|
||||
|
||||
# File operations
|
||||
paurl = "papis addto -u";
|
||||
|
||||
# Open documents
|
||||
paopen = "papis open";
|
||||
|
||||
# Print document file path
|
||||
papwd = "papis list --file";
|
||||
|
||||
# Cache management
|
||||
pareset = "papis cache reset";
|
||||
};
|
||||
|
||||
# Shell functions for papis workflow
|
||||
programs.zsh.initContent = ''
|
||||
# Papis add file function - add file to existing document with proper parameter handling
|
||||
pafile() {
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "Usage: pafile <filename> [query]"
|
||||
echo "Example: pafile paper.pdf # Interactive selection"
|
||||
echo "Example: pafile paper.pdf \"einstein relativity\" # Direct match"
|
||||
echo "Example: pafile /path/to/paper.pdf \"quantum\" # Absolute path"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local filename="$1"
|
||||
shift # Remove first argument
|
||||
local query="$*" # All remaining arguments as query (empty if none)
|
||||
|
||||
# Check if filename is absolute path or relative to Downloads
|
||||
if [[ "$filename" == /* ]]; then
|
||||
# Absolute path
|
||||
if [ -n "$query" ]; then
|
||||
papis addto -f "$filename" "$query"
|
||||
else
|
||||
papis addto -f "$filename"
|
||||
fi
|
||||
else
|
||||
# Relative to Downloads
|
||||
if [ -n "$query" ]; then
|
||||
papis addto -f "$HOME/Downloads/$filename" "$query"
|
||||
else
|
||||
papis addto -f "$HOME/Downloads/$filename"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Papis tag function - rewrite tags using hash-separated format
|
||||
patag() {
|
||||
if [ $# -ne 2 ]; then
|
||||
echo "Usage: patag \"tag1#tag2#tag3\" <query>"
|
||||
echo "Example: patag \"materials#ai4science\" amorphous"
|
||||
echo "Example: patag \"quantum#computing\" \"author:einstein\""
|
||||
return 1
|
||||
fi
|
||||
|
||||
local tags_string="$1"
|
||||
local query="$2"
|
||||
|
||||
# First, drop all existing tags
|
||||
papis tag --drop "$query"
|
||||
|
||||
# Add each tag individually by splitting on #
|
||||
echo "$tags_string" | tr '#' '\n' | while read tag; do
|
||||
# Trim whitespace
|
||||
tag=$(echo "$tag" | xargs)
|
||||
if [ -n "$tag" ]; then
|
||||
papis tag --add "$tag" "$query"
|
||||
fi
|
||||
done
|
||||
}
|
||||
'';
|
||||
}
|
||||
200
modules/wireguard.nix
Normal file
200
modules/wireguard.nix
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.wireguard-custom;
|
||||
in
|
||||
|
||||
{
|
||||
options.services.wireguard-custom = {
|
||||
enable = mkEnableOption "WireGuard VPN";
|
||||
|
||||
mode = mkOption {
|
||||
type = types.enum [ "server" "client" ];
|
||||
description = "Whether to run as server (hub) or client (spoke)";
|
||||
};
|
||||
|
||||
interface = mkOption {
|
||||
type = types.str;
|
||||
default = "wg0";
|
||||
description = "WireGuard interface name";
|
||||
};
|
||||
|
||||
listenPort = mkOption {
|
||||
type = types.port;
|
||||
default = 51820;
|
||||
description = "UDP port to listen on (server mode only)";
|
||||
};
|
||||
|
||||
privateKeyFile = mkOption {
|
||||
type = types.str;
|
||||
default = "/etc/wireguard/private.key";
|
||||
description = "Path to private key file";
|
||||
};
|
||||
|
||||
serverConfig = mkOption {
|
||||
type = types.submodule {
|
||||
options = {
|
||||
address = mkOption {
|
||||
type = types.str;
|
||||
example = "10.2.2.1/24";
|
||||
description = "Server IP address with CIDR";
|
||||
};
|
||||
|
||||
peers = mkOption {
|
||||
type = types.listOf (types.submodule {
|
||||
options = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
description = "Peer name for identification";
|
||||
};
|
||||
|
||||
publicKey = mkOption {
|
||||
type = types.str;
|
||||
description = "Peer's public key";
|
||||
};
|
||||
|
||||
allowedIPs = mkOption {
|
||||
type = types.listOf types.str;
|
||||
description = "IP addresses this peer is allowed to use";
|
||||
};
|
||||
};
|
||||
});
|
||||
default = [];
|
||||
description = "List of client peers";
|
||||
};
|
||||
};
|
||||
};
|
||||
description = "Server-specific configuration";
|
||||
};
|
||||
|
||||
clientConfig = mkOption {
|
||||
type = types.submodule {
|
||||
options = {
|
||||
address = mkOption {
|
||||
type = types.str;
|
||||
example = "10.2.2.20/24";
|
||||
description = "Client IP address with CIDR";
|
||||
};
|
||||
|
||||
serverPublicKey = mkOption {
|
||||
type = types.str;
|
||||
description = "Server's public key";
|
||||
};
|
||||
|
||||
serverEndpoint = mkOption {
|
||||
type = types.str;
|
||||
example = "vpn.example.com:51820";
|
||||
description = "Server endpoint (host:port)";
|
||||
};
|
||||
|
||||
allowedIPs = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ "10.2.2.0/24" ];
|
||||
description = "IP ranges to route through the tunnel";
|
||||
};
|
||||
};
|
||||
};
|
||||
description = "Client-specific configuration";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
# Install WireGuard tools
|
||||
environment.systemPackages = with pkgs; [ wireguard-tools ];
|
||||
|
||||
# Create private key file if it doesn't exist
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /etc/wireguard 0700 root root - -"
|
||||
"f ${cfg.privateKeyFile} 0600 root root - -"
|
||||
];
|
||||
|
||||
# Generate private key on first run
|
||||
systemd.services.wireguard-keygen = {
|
||||
description = "Generate WireGuard private key";
|
||||
before = [ "wg-quick-${cfg.interface}.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
script = ''
|
||||
if [ ! -s ${cfg.privateKeyFile} ]; then
|
||||
echo "Generating WireGuard private key..."
|
||||
${pkgs.wireguard-tools}/bin/wg genkey > ${cfg.privateKeyFile}
|
||||
chmod 600 ${cfg.privateKeyFile}
|
||||
echo "Private key generated. Public key:"
|
||||
${pkgs.wireguard-tools}/bin/wg pubkey < ${cfg.privateKeyFile}
|
||||
echo "Please add this public key to your peer configurations."
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
# WireGuard interface configuration (combined server and client)
|
||||
networking.wg-quick.interfaces = {
|
||||
${cfg.interface} = mkMerge [
|
||||
# Common configuration
|
||||
{
|
||||
privateKeyFile = cfg.privateKeyFile;
|
||||
}
|
||||
|
||||
# Server-specific configuration
|
||||
(mkIf (cfg.mode == "server") {
|
||||
address = [ cfg.serverConfig.address ];
|
||||
listenPort = cfg.listenPort;
|
||||
|
||||
# Enable IP forwarding and NAT for server
|
||||
preUp = ''
|
||||
${pkgs.iptables}/bin/iptables -A FORWARD -i ${cfg.interface} -j ACCEPT
|
||||
${pkgs.iptables}/bin/iptables -A FORWARD -o ${cfg.interface} -j ACCEPT
|
||||
${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.2.2.0/24 -o eth0 -j MASQUERADE
|
||||
'';
|
||||
|
||||
postDown = ''
|
||||
${pkgs.iptables}/bin/iptables -D FORWARD -i ${cfg.interface} -j ACCEPT
|
||||
${pkgs.iptables}/bin/iptables -D FORWARD -o ${cfg.interface} -j ACCEPT
|
||||
${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.2.2.0/24 -o eth0 -j MASQUERADE
|
||||
'';
|
||||
|
||||
peers = map (peer: {
|
||||
publicKey = peer.publicKey;
|
||||
allowedIPs = peer.allowedIPs;
|
||||
}) cfg.serverConfig.peers;
|
||||
})
|
||||
|
||||
# Client-specific configuration
|
||||
(mkIf (cfg.mode == "client") {
|
||||
address = [ cfg.clientConfig.address ];
|
||||
|
||||
peers = [{
|
||||
publicKey = cfg.clientConfig.serverPublicKey;
|
||||
allowedIPs = cfg.clientConfig.allowedIPs;
|
||||
endpoint = cfg.clientConfig.serverEndpoint;
|
||||
persistentKeepalive = 25;
|
||||
}];
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
# Firewall configuration
|
||||
networking.firewall = mkMerge [
|
||||
# Server firewall rules
|
||||
(mkIf (cfg.mode == "server") {
|
||||
allowedUDPPorts = [ cfg.listenPort ];
|
||||
trustedInterfaces = [ cfg.interface ];
|
||||
})
|
||||
|
||||
# Client firewall rules
|
||||
(mkIf (cfg.mode == "client") {
|
||||
trustedInterfaces = [ cfg.interface ];
|
||||
})
|
||||
];
|
||||
|
||||
# Enable IP forwarding for server
|
||||
boot.kernel.sysctl = mkIf (cfg.mode == "server") {
|
||||
"net.ipv4.ip_forward" = 1;
|
||||
"net.ipv6.conf.all.forwarding" = 1;
|
||||
};
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue