@jaspermayone.com's dotfiles

wip

+672
common/bore.nix

This is a binary file and will not be displayed.

common/git.nix

This is a binary file and will not be displayed.

common/shell.nix

This is a binary file and will not be displayed.

darwin/default.nix

This is a binary file and will not be displayed.

flake.nix

This is a binary file and will not be displayed.

home/default.nix

This is a binary file and will not be displayed.

hosts/connector/configuration.nix

This is a binary file and will not be displayed.

hosts/connector/hardware-configuration.nix

This is a binary file and will not be displayed.

hosts/remus/default.nix

This is a binary file and will not be displayed.

+131
modules/bore/bore.1.md
··· 1 + % BORE(1) bore 1.0 2 + % Kieran Klukas 3 + % December 2024 4 + 5 + # NAME 6 + 7 + bore - secure tunneling service for exposing local services to the internet 8 + 9 + # SYNOPSIS 10 + 11 + **bore** [*SUBDOMAIN*] [*PORT*] [**--protocol** *PROTOCOL*] [**--label** *LABEL*] [**--save**] 12 + 13 + **bore** **--list** | **-l** 14 + 15 + **bore** **--saved** | **-s** 16 + 17 + # DESCRIPTION 18 + 19 + **bore** is a tunneling service that uses frp (fast reverse proxy) to expose local services to the internet via bore.dunkirk.sh. It provides a simple CLI for creating and managing HTTP, TCP, and UDP tunnels with optional labels and persistent configuration. 20 + 21 + # OPTIONS 22 + 23 + **-l**, **--list** 24 + : List all active tunnels on the bore server. 25 + 26 + **-s**, **--saved** 27 + : List all saved tunnel configurations from bore.toml in the current directory. 28 + 29 + **-p**, **--protocol** *PROTOCOL* 30 + : Specify the protocol to use for the tunnel: **http** (default), **tcp**, or **udp**. 31 + 32 + **--label** *LABEL* 33 + : Assign a label/tag to the tunnel for organization and identification. 34 + 35 + **--save** 36 + : Save the tunnel configuration to bore.toml in the current directory for future use. 37 + 38 + # ARGUMENTS 39 + 40 + *SUBDOMAIN* 41 + : The subdomain to use for the tunnel (e.g., "myapp" creates myapp.bore.dunkirk.sh). Must contain only lowercase letters, numbers, and hyphens. 42 + 43 + *PORT* 44 + : The local port to expose (e.g., 8000 for localhost:8000). 45 + 46 + # CONFIGURATION 47 + 48 + Tunnel configurations can be saved to a **bore.toml** file in the current directory. This file uses TOML format and can be committed to repositories. 49 + 50 + ## bore.toml Format 51 + 52 + ```toml 53 + [myapp] 54 + port = 8000 55 + 56 + [api] 57 + port = 3000 58 + protocol = "http" 59 + label = "dev" 60 + 61 + [database] 62 + port = 5432 63 + protocol = "tcp" 64 + label = "postgres" 65 + 66 + [game-server] 67 + port = 27015 68 + protocol = "udp" 69 + label = "game" 70 + ``` 71 + 72 + When running **bore** without arguments in a directory with bore.toml, you'll be prompted to choose between creating a new tunnel or using a saved configuration. 73 + 74 + # EXAMPLES 75 + 76 + Create a simple HTTP tunnel: 77 + ``` 78 + $ bore myapp 8000 79 + ``` 80 + 81 + Create an HTTP tunnel with a label: 82 + ``` 83 + $ bore api 3000 --label dev 84 + ``` 85 + 86 + Create a TCP tunnel for a database: 87 + ``` 88 + $ bore database 5432 --protocol tcp --label postgres 89 + ``` 90 + 91 + Create a UDP tunnel for a game server: 92 + ``` 93 + $ bore game-server 27015 --protocol udp --label game 94 + ``` 95 + 96 + Save a tunnel configuration: 97 + ``` 98 + $ bore frontend 5173 --label local --save 99 + ``` 100 + 101 + List active tunnels: 102 + ``` 103 + $ bore --list 104 + ``` 105 + 106 + List saved configurations: 107 + ``` 108 + $ bore --saved 109 + ``` 110 + 111 + Interactive mode (choose saved or new): 112 + ``` 113 + $ bore 114 + ``` 115 + 116 + # FILES 117 + 118 + **bore.toml** 119 + : Local tunnel configuration file (current directory) 120 + 121 + # SEE ALSO 122 + 123 + Dashboard: https://tun.hogwarts.dev 124 + 125 + # BUGS 126 + 127 + Report bugs at: https://github.com/jaspermayone/dots/issues 128 + 129 + # AUTHORS 130 + 131 + Kieran Klukas <crush@charm.land>
+42
modules/bore/completions/bore.zsh
··· 1 + #compdef bore 2 + 3 + _bore() { 4 + local -a tunnels 5 + local curcontext="$curcontext" state line 6 + typeset -A opt_args 7 + 8 + # Read saved tunnels from bore.toml if it exists 9 + if [[ -f "bore.toml" ]]; then 10 + tunnels=(${(f)"$(grep '^\[' bore.toml | sed 's/^\[\(.*\)\]$/\1/')"}) 11 + fi 12 + 13 + _arguments -C \ 14 + '1: :->subdomain' \ 15 + '2: :->port' \ 16 + '--list[List active tunnels]' \ 17 + '-l[List active tunnels]' \ 18 + '--saved[List saved tunnels from bore.toml]' \ 19 + '-s[List saved tunnels from bore.toml]' \ 20 + '--protocol[Specify protocol]:protocol:(http tcp udp)' \ 21 + '-p[Specify protocol]:protocol:(http tcp udp)' \ 22 + '--label[Assign a label to the tunnel]:label:' \ 23 + '--save[Save tunnel configuration to bore.toml]' \ 24 + && return 0 25 + 26 + case $state in 27 + subdomain) 28 + if [[ ${#tunnels[@]} -gt 0 ]]; then 29 + _describe 'saved tunnels' tunnels 30 + else 31 + _message 'subdomain (e.g., myapp)' 32 + fi 33 + ;; 34 + port) 35 + _message 'local port (e.g., 8000)' 36 + ;; 37 + esac 38 + 39 + return 0 40 + } 41 + 42 + _bore "$@"
+499
modules/bore/default.nix
··· 1 + { 2 + config, 3 + lib, 4 + pkgs, 5 + ... 6 + }: 7 + let 8 + cfg = config.atelier.bore; 9 + 10 + boreScript = pkgs.writeShellScript "bore" '' 11 + CONFIG_FILE="bore.toml" 12 + 13 + # Trap exit signals to ensure cleanup and exit immediately 14 + trap 'exit 130' INT 15 + trap 'exit 143' TERM 16 + trap 'exit 129' HUP 17 + 18 + # Enable immediate exit on error or pipe failure 19 + set -e 20 + set -o pipefail 21 + 22 + # Check for flags 23 + if [ "$1" = "--list" ] || [ "$1" = "-l" ]; then 24 + ${pkgs.gum}/bin/gum style --bold --foreground 212 "Active tunnels" 25 + echo 26 + 27 + tunnels=$(${pkgs.curl}/bin/curl -s https://${cfg.domain}/api/proxy/http) 28 + 29 + if ! echo "$tunnels" | ${pkgs.jq}/bin/jq -e '.proxies | length > 0' >/dev/null 2>&1; then 30 + ${pkgs.gum}/bin/gum style --foreground 117 "No active tunnels" 31 + exit 0 32 + fi 33 + 34 + # Filter only online tunnels with valid conf 35 + echo "$tunnels" | ${pkgs.jq}/bin/jq -r '.proxies[] | select(.status == "online" and .conf != null) | if .type == "http" then "\(.name) → https://\(.conf.subdomain).${cfg.domain} [http]" elif .type == "tcp" then "\(.name) → tcp://\(.conf.remotePort) → localhost:\(.conf.localPort) [tcp]" elif .type == "udp" then "\(.name) → udp://\(.conf.remotePort) → localhost:\(.conf.localPort) [udp]" else "\(.name) [\(.type)]" end' | while read -r line; do 36 + ${pkgs.gum}/bin/gum style --foreground 35 "✓ $line" 37 + done 38 + exit 0 39 + fi 40 + 41 + if [ "$1" = "--saved" ] || [ "$1" = "-s" ]; then 42 + if [ ! -f "$CONFIG_FILE" ]; then 43 + ${pkgs.gum}/bin/gum style --foreground 117 "No bore.toml found in current directory" 44 + exit 0 45 + fi 46 + 47 + ${pkgs.gum}/bin/gum style --bold --foreground 212 "Saved tunnels in bore.toml" 48 + echo 49 + 50 + # Parse TOML and show tunnels 51 + while IFS= read -r line; do 52 + if [[ "$line" =~ ^\[([^]]+)\] ]]; then 53 + current_tunnel="''${BASH_REMATCH[1]}" 54 + elif [[ "$line" =~ ^port[[:space:]]*=[[:space:]]*([0-9]+) ]]; then 55 + port="''${BASH_REMATCH[1]}" 56 + elif [[ "$line" =~ ^protocol[[:space:]]*=[[:space:]]*\"([^\"]+)\" ]]; then 57 + protocol="''${BASH_REMATCH[1]}" 58 + elif [[ "$line" =~ ^label[[:space:]]*=[[:space:]]*\"([^\"]+)\" ]]; then 59 + label="''${BASH_REMATCH[1]}" 60 + proto_display="''${protocol:-http}" 61 + ${pkgs.gum}/bin/gum style --foreground 35 "✓ $current_tunnel → localhost:$port [$proto_display] [$label]" 62 + label="" 63 + protocol="" 64 + elif [[ -z "$line" ]] && [[ -n "$current_tunnel" ]] && [[ -n "$port" ]]; then 65 + proto_display="''${protocol:-http}" 66 + ${pkgs.gum}/bin/gum style --foreground 35 "✓ $current_tunnel → localhost:$port [$proto_display]" 67 + current_tunnel="" 68 + port="" 69 + protocol="" 70 + fi 71 + done < "$CONFIG_FILE" 72 + 73 + # Handle last entry if file doesn't end with blank line 74 + if [[ -n "$current_tunnel" ]] && [[ -n "$port" ]]; then 75 + proto_display="''${protocol:-http}" 76 + if [[ -n "$label" ]]; then 77 + ${pkgs.gum}/bin/gum style --foreground 35 "✓ $current_tunnel → localhost:$port [$proto_display] [$label]" 78 + else 79 + ${pkgs.gum}/bin/gum style --foreground 35 "✓ $current_tunnel → localhost:$port [$proto_display]" 80 + fi 81 + fi 82 + exit 0 83 + fi 84 + 85 + # Get tunnel name/subdomain 86 + if [ -n "$1" ]; then 87 + tunnel_name="$1" 88 + else 89 + # Check if we have a bore.toml in current directory 90 + if [ -f "$CONFIG_FILE" ]; then 91 + # Count tunnels in TOML 92 + tunnel_count=$(${pkgs.gnugrep}/bin/grep -c '^\[' "$CONFIG_FILE" 2>/dev/null || echo "0") 93 + 94 + if [ "$tunnel_count" -gt 0 ]; then 95 + ${pkgs.gum}/bin/gum style --bold --foreground 212 "Creating bore tunnel" 96 + echo 97 + 98 + # Show choice between new or saved 99 + choice=$(${pkgs.gum}/bin/gum choose "New tunnel" "Use saved tunnel") 100 + 101 + if [ "$choice" = "Use saved tunnel" ]; then 102 + # Extract tunnel names from TOML 103 + saved_names=$(${pkgs.gnugrep}/bin/grep '^\[' "$CONFIG_FILE" | ${pkgs.gnused}/bin/sed 's/^\[\(.*\)\]$/\1/') 104 + tunnel_name=$(echo "$saved_names" | ${pkgs.gum}/bin/gum choose) 105 + 106 + if [ -z "$tunnel_name" ]; then 107 + ${pkgs.gum}/bin/gum style --foreground 196 "No tunnel selected" 108 + exit 1 109 + fi 110 + 111 + # Parse TOML for this tunnel's config 112 + in_section=false 113 + while IFS= read -r line; do 114 + if [[ "$line" =~ ^\[([^]]+)\] ]]; then 115 + if [[ "''${BASH_REMATCH[1]}" = "$tunnel_name" ]]; then 116 + in_section=true 117 + else 118 + in_section=false 119 + fi 120 + elif [[ "$in_section" = true ]]; then 121 + if [[ "$line" =~ ^port[[:space:]]*=[[:space:]]*([0-9]+) ]]; then 122 + port="''${BASH_REMATCH[1]}" 123 + elif [[ "$line" =~ ^protocol[[:space:]]*=[[:space:]]*\"([^\"]+)\" ]]; then 124 + protocol="''${BASH_REMATCH[1]}" 125 + elif [[ "$line" =~ ^label[[:space:]]*=[[:space:]]*\"([^\"]+)\" ]]; then 126 + label="''${BASH_REMATCH[1]}" 127 + fi 128 + fi 129 + done < "$CONFIG_FILE" 130 + 131 + proto_display="''${protocol:-http}" 132 + ${pkgs.gum}/bin/gum style --foreground 35 "✓ Loaded from bore.toml: $tunnel_name → localhost:$port [$proto_display]''${label:+ [$label]}" 133 + else 134 + # New tunnel - prompt for protocol first to determine what to ask for 135 + protocol=$(${pkgs.gum}/bin/gum choose --header "Protocol:" "http" "tcp" "udp") 136 + if [ -z "$protocol" ]; then 137 + protocol="http" 138 + fi 139 + 140 + if [ "$protocol" = "http" ]; then 141 + tunnel_name=$(${pkgs.gum}/bin/gum input --placeholder "myapp" --prompt "Subdomain: ") 142 + else 143 + tunnel_name=$(${pkgs.gum}/bin/gum input --placeholder "my-tunnel" --prompt "Tunnel name: ") 144 + fi 145 + 146 + if [ -z "$tunnel_name" ]; then 147 + ${pkgs.gum}/bin/gum style --foreground 196 "No name provided" 148 + exit 1 149 + fi 150 + fi 151 + else 152 + ${pkgs.gum}/bin/gum style --bold --foreground 212 "Creating bore tunnel" 153 + echo 154 + # Prompt for protocol first 155 + protocol=$(${pkgs.gum}/bin/gum choose --header "Protocol:" "http" "tcp" "udp") 156 + if [ -z "$protocol" ]; then 157 + protocol="http" 158 + fi 159 + 160 + if [ "$protocol" = "http" ]; then 161 + tunnel_name=$(${pkgs.gum}/bin/gum input --placeholder "myapp" --prompt "Subdomain: ") 162 + else 163 + tunnel_name=$(${pkgs.gum}/bin/gum input --placeholder "my-tunnel" --prompt "Tunnel name: ") 164 + fi 165 + 166 + if [ -z "$tunnel_name" ]; then 167 + ${pkgs.gum}/bin/gum style --foreground 196 "No name provided" 168 + exit 1 169 + fi 170 + fi 171 + else 172 + ${pkgs.gum}/bin/gum style --bold --foreground 212 "Creating bore tunnel" 173 + echo 174 + # Prompt for protocol first 175 + protocol=$(${pkgs.gum}/bin/gum choose --header "Protocol:" "http" "tcp" "udp") 176 + if [ -z "$protocol" ]; then 177 + protocol="http" 178 + fi 179 + 180 + if [ "$protocol" = "http" ]; then 181 + tunnel_name=$(${pkgs.gum}/bin/gum input --placeholder "myapp" --prompt "Subdomain: ") 182 + else 183 + tunnel_name=$(${pkgs.gum}/bin/gum input --placeholder "my-tunnel" --prompt "Tunnel name: ") 184 + fi 185 + 186 + if [ -z "$tunnel_name" ]; then 187 + ${pkgs.gum}/bin/gum style --foreground 196 "No name provided" 188 + exit 1 189 + fi 190 + fi 191 + fi 192 + 193 + # Validate tunnel name (only for http subdomains) 194 + if [ "$protocol" = "http" ]; then 195 + if ! echo "$tunnel_name" | ${pkgs.gnugrep}/bin/grep -qE '^[a-z0-9-]+$'; then 196 + ${pkgs.gum}/bin/gum style --foreground 196 "Invalid subdomain (use only lowercase letters, numbers, and hyphens)" 197 + exit 1 198 + fi 199 + fi 200 + 201 + # Get port (skip if loaded from saved config) 202 + if [ -z "$port" ]; then 203 + if [ -n "$2" ]; then 204 + port="$2" 205 + else 206 + port=$(${pkgs.gum}/bin/gum input --placeholder "8000" --prompt "Local port: ") 207 + if [ -z "$port" ]; then 208 + ${pkgs.gum}/bin/gum style --foreground 196 "No port provided" 209 + exit 1 210 + fi 211 + fi 212 + fi 213 + 214 + # Validate port 215 + if ! echo "$port" | ${pkgs.gnugrep}/bin/grep -qE '^[0-9]+$'; then 216 + ${pkgs.gum}/bin/gum style --foreground 196 "Invalid port (must be a number)" 217 + exit 1 218 + fi 219 + 220 + # Get optional protocol, label and save flag (skip if loaded from saved config) 221 + save_config=false 222 + if [ -z "$label" ]; then 223 + shift 2 2>/dev/null || true 224 + while [[ $# -gt 0 ]]; do 225 + case "$1" in 226 + --protocol|-p) 227 + protocol="$2" 228 + shift 2 229 + ;; 230 + --label|-l) 231 + label="$2" 232 + shift 2 233 + ;; 234 + --save) 235 + save_config=true 236 + shift 237 + ;; 238 + *) 239 + shift 240 + ;; 241 + esac 242 + done 243 + 244 + # Prompt for protocol if not provided via flag and not loaded from saved config and not already set 245 + if [ -z "$protocol" ]; then 246 + protocol=$(${pkgs.gum}/bin/gum choose --header "Protocol:" "http" "tcp" "udp") 247 + if [ -z "$protocol" ]; then 248 + protocol="http" 249 + fi 250 + fi 251 + 252 + # Prompt for label if not provided via flag and not loaded from saved config 253 + if [ -z "$label" ]; then 254 + # Allow multiple labels selection 255 + labels=$(${pkgs.gum}/bin/gum choose --no-limit --header "Labels (select multiple):" "dev" "prod" "custom") 256 + 257 + if [ -n "$labels" ]; then 258 + # Check if custom was selected 259 + if echo "$labels" | ${pkgs.gnugrep}/bin/grep -q "custom"; then 260 + custom_label=$(${pkgs.gum}/bin/gum input --placeholder "my-label" --prompt "Custom label: ") 261 + if [ -z "$custom_label" ]; then 262 + ${pkgs.gum}/bin/gum style --foreground 196 "No custom label provided" 263 + exit 1 264 + fi 265 + # Replace 'custom' with the actual custom label 266 + labels=$(echo "$labels" | ${pkgs.gnused}/bin/sed "s/custom/$custom_label/") 267 + fi 268 + # Join labels with comma 269 + label=$(echo "$labels" | ${pkgs.coreutils}/bin/tr '\n' ',' | ${pkgs.gnused}/bin/sed 's/,$//') 270 + fi 271 + fi 272 + fi 273 + 274 + # Default protocol to http if still not set 275 + if [ -z "$protocol" ]; then 276 + protocol="http" 277 + fi 278 + 279 + # Check if local port is accessible 280 + if ! ${pkgs.netcat}/bin/nc -z 127.0.0.1 "$port" 2>/dev/null; then 281 + ${pkgs.gum}/bin/gum style --foreground 214 "! Warning: Nothing listening on localhost:$port" 282 + fi 283 + 284 + # Save configuration if requested 285 + if [ "$save_config" = true ]; then 286 + # Check if tunnel already exists in TOML 287 + if [ -f "$CONFIG_FILE" ] && ${pkgs.gnugrep}/bin/grep -q "^\[$tunnel_name\]" "$CONFIG_FILE"; then 288 + # Update existing entry 289 + ${pkgs.gnused}/bin/sed -i "/^\[$tunnel_name\]/,/^\[/{ 290 + s/^port[[:space:]]*=.*/port = $port/ 291 + s/^protocol[[:space:]]*=.*/protocol = \"$protocol\"/ 292 + ''${label:+s/^label[[:space:]]*=.*/label = \"$label\"/} 293 + }" "$CONFIG_FILE" 294 + else 295 + # Append new entry 296 + { 297 + echo "" 298 + echo "[$tunnel_name]" 299 + echo "port = $port" 300 + if [ "$protocol" != "http" ]; then 301 + echo "protocol = \"$protocol\"" 302 + fi 303 + if [ -n "$label" ]; then 304 + echo "label = \"$label\"" 305 + fi 306 + } >> "$CONFIG_FILE" 307 + fi 308 + 309 + ${pkgs.gum}/bin/gum style --foreground 35 "✓ Configuration saved to bore.toml" 310 + echo 311 + fi 312 + 313 + # Create config file 314 + config_file=$(${pkgs.coreutils}/bin/mktemp) 315 + trap "${pkgs.coreutils}/bin/rm -f $config_file" EXIT 316 + 317 + # Encode label into proxy name if provided (format: tunnel_name[label1,label2]) 318 + proxy_name="$tunnel_name" 319 + if [ -n "$label" ]; then 320 + proxy_name="''${tunnel_name}[''${label}]" 321 + fi 322 + 323 + # Build proxy configuration based on protocol 324 + if [ "$protocol" = "http" ]; then 325 + ${pkgs.coreutils}/bin/cat > $config_file <<EOF 326 + serverAddr = "${cfg.serverAddr}" 327 + serverPort = ${toString cfg.serverPort} 328 + 329 + auth.method = "token" 330 + auth.tokenSource.type = "file" 331 + auth.tokenSource.file.path = "${cfg.authTokenFile}" 332 + 333 + [[proxies]] 334 + name = "$proxy_name" 335 + type = "http" 336 + localIP = "127.0.0.1" 337 + localPort = $port 338 + subdomain = "$tunnel_name" 339 + EOF 340 + elif [ "$protocol" = "tcp" ] || [ "$protocol" = "udp" ]; then 341 + # For TCP/UDP, enable admin API to query allocated port 342 + # Use Python to find a free port (cross-platform and guaranteed to work) 343 + admin_port=$(${pkgs.python3}/bin/python3 -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()') 344 + 345 + ${pkgs.coreutils}/bin/cat > $config_file <<EOF 346 + serverAddr = "${cfg.serverAddr}" 347 + serverPort = ${toString cfg.serverPort} 348 + 349 + auth.method = "token" 350 + auth.tokenSource.type = "file" 351 + auth.tokenSource.file.path = "${cfg.authTokenFile}" 352 + 353 + webServer.addr = "127.0.0.1" 354 + webServer.port = $admin_port 355 + 356 + [[proxies]] 357 + name = "$proxy_name" 358 + type = "$protocol" 359 + localIP = "127.0.0.1" 360 + localPort = $port 361 + remotePort = 0 362 + EOF 363 + else 364 + ${pkgs.gum}/bin/gum style --foreground 196 "Invalid protocol: $protocol (must be http, tcp, or udp)" 365 + exit 1 366 + fi 367 + 368 + # Start tunnel 369 + echo 370 + ${pkgs.gum}/bin/gum style --foreground 35 "✓ Tunnel configured" 371 + ${pkgs.gum}/bin/gum style --foreground 117 " Local: localhost:$port" 372 + if [ "$protocol" = "http" ]; then 373 + public_url="https://$tunnel_name.${cfg.domain}" 374 + ${pkgs.gum}/bin/gum style --foreground 117 " Public: $public_url" 375 + else 376 + ${pkgs.gum}/bin/gum style --foreground 117 " Protocol: $protocol" 377 + ${pkgs.gum}/bin/gum style --foreground 214 " Waiting for server to allocate port..." 378 + fi 379 + echo 380 + ${pkgs.gum}/bin/gum style --foreground 214 "Connecting to ${cfg.serverAddr}:${toString cfg.serverPort}..." 381 + echo 382 + 383 + # For TCP/UDP, capture output to parse allocated port 384 + if [ "$protocol" = "tcp" ] || [ "$protocol" = "udp" ]; then 385 + # Start frpc in background and capture its PID 386 + ${pkgs.frp}/bin/frpc -c $config_file 2>&1 | while IFS= read -r line; do 387 + echo "$line" 388 + 389 + # Look for successful proxy start 390 + if echo "$line" | ${pkgs.gnugrep}/bin/grep -q "start proxy success"; then 391 + # Wait a moment for the proxy to fully initialize 392 + sleep 1 393 + 394 + # Query the frpc admin API for proxy status 395 + proxy_status=$(${pkgs.curl}/bin/curl -s http://127.0.0.1:$admin_port/api/status 2>/dev/null || echo "{}") 396 + 397 + # Try to extract remote port from JSON response 398 + # Format: "remote_addr":"tun.hogwarts.dev:20097" 399 + remote_addr=$(echo "$proxy_status" | ${pkgs.jq}/bin/jq -r ".tcp[]? | select(.name == \"$proxy_name\") | .remote_addr" 2>/dev/null) 400 + if [ -z "$remote_addr" ] || [ "$remote_addr" = "null" ]; then 401 + remote_addr=$(echo "$proxy_status" | ${pkgs.jq}/bin/jq -r ".udp[]? | select(.name == \"$proxy_name\") | .remote_addr" 2>/dev/null) 402 + fi 403 + 404 + # Extract just the port number 405 + remote_port=$(echo "$remote_addr" | ${pkgs.gnugrep}/bin/grep -oP ':\K[0-9]+$') 406 + 407 + if [ -n "$remote_port" ] && [ "$remote_port" != "null" ]; then 408 + echo 409 + ${pkgs.gum}/bin/gum style --foreground 35 "✓ Tunnel established" 410 + ${pkgs.gum}/bin/gum style --foreground 117 " Local: localhost:$port" 411 + ${pkgs.gum}/bin/gum style --foreground 117 " Remote: ${cfg.serverAddr}:$remote_port" 412 + ${pkgs.gum}/bin/gum style --foreground 117 " Type: $protocol" 413 + echo 414 + fi 415 + fi 416 + done 417 + else 418 + exec ${pkgs.frp}/bin/frpc -c $config_file 419 + fi 420 + ''; 421 + 422 + bore = pkgs.stdenv.mkDerivation { 423 + pname = "bore"; 424 + version = "1.0"; 425 + 426 + dontUnpack = true; 427 + 428 + nativeBuildInputs = with pkgs; [ pandoc installShellFiles ]; 429 + 430 + manPageSrc = ./bore.1.md; 431 + bashCompletionSrc = ./completions/bore.bash; 432 + zshCompletionSrc = ./completions/bore.zsh; 433 + fishCompletionSrc = ./completions/bore.fish; 434 + 435 + buildPhase = '' 436 + # Convert markdown man page to man format 437 + ${pkgs.pandoc}/bin/pandoc -s -t man $manPageSrc -o bore.1 438 + ''; 439 + 440 + installPhase = '' 441 + mkdir -p $out/bin 442 + 443 + # Install binary 444 + cp ${boreScript} $out/bin/bore 445 + chmod +x $out/bin/bore 446 + 447 + # Install man page 448 + installManPage bore.1 449 + 450 + # Install completions 451 + installShellCompletion --bash --name bore $bashCompletionSrc 452 + installShellCompletion --zsh --name _bore $zshCompletionSrc 453 + installShellCompletion --fish --name bore.fish $fishCompletionSrc 454 + ''; 455 + 456 + meta = with lib; { 457 + description = "Secure tunneling service CLI"; 458 + homepage = "https://tun.hogwarts.dev"; 459 + license = licenses.mit; 460 + maintainers = [ ]; 461 + }; 462 + }; 463 + in 464 + { 465 + options.atelier.bore = { 466 + enable = lib.mkEnableOption "bore tunneling service"; 467 + 468 + serverAddr = lib.mkOption { 469 + type = lib.types.str; 470 + default = "tun.hogwarts.dev"; 471 + description = "bore server address"; 472 + }; 473 + 474 + serverPort = lib.mkOption { 475 + type = lib.types.port; 476 + default = 7000; 477 + description = "bore server port"; 478 + }; 479 + 480 + domain = lib.mkOption { 481 + type = lib.types.str; 482 + default = "tun.hogwarts.dev"; 483 + description = "Domain for public tunnel URLs"; 484 + }; 485 + 486 + authTokenFile = lib.mkOption { 487 + type = lib.types.nullOr lib.types.path; 488 + default = null; 489 + description = "Path to file containing authentication token"; 490 + }; 491 + }; 492 + 493 + config = lib.mkIf cfg.enable { 494 + home.packages = [ 495 + pkgs.frp 496 + bore 497 + ]; 498 + }; 499 + }
modules/frps/default.nix

This is a binary file and will not be displayed.