feat: custom Stream port manager UI and WireGuard config Zip download API
This commit is contained in:
parent
7bf175da41
commit
34020bc562
4 changed files with 130 additions and 7 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import express from "express";
|
||||
import archiver from "archiver";
|
||||
import internalWireguard from "../internal/wireguard.js";
|
||||
import internalAuditLog from "../internal/audit-log.js";
|
||||
import jwtdecode from "../lib/express/jwt-decode.js";
|
||||
|
|
@ -274,4 +275,36 @@ router.get("/client/:id/qrcode.svg", async (req, res, next) => {
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /api/wireguard/client/:id/configuration.zip
|
||||
* Download WireGuard client configuration as a ZIP archive
|
||||
*/
|
||||
router.get("/client/:id/configuration.zip", async (req, res, next) => {
|
||||
try {
|
||||
const knex = db();
|
||||
const client = await knex("wg_client").where("id", req.params.id).first();
|
||||
if (!client) {
|
||||
return res.status(404).json({ error: { message: "Client not found" } });
|
||||
}
|
||||
|
||||
const configStr = await internalWireguard.getClientConfiguration(knex, req.params.id);
|
||||
const svgStr = await internalWireguard.getClientQRCode(knex, req.params.id);
|
||||
const safeName = client.name.replace(/[^a-zA-Z0-9_.-]/g, "-").substring(0, 32);
|
||||
|
||||
res.set("Content-Disposition", `attachment; filename="${safeName}.zip"`);
|
||||
res.set("Content-Type", "application/zip");
|
||||
|
||||
const archive = archiver("zip", { zlib: { level: 9 } });
|
||||
archive.on("error", (err) => next(err));
|
||||
archive.pipe(res);
|
||||
|
||||
archive.append(configStr, { name: `${safeName}.conf` });
|
||||
archive.append(svgStr, { name: `${safeName}-qrcode.svg` });
|
||||
|
||||
await archive.finalize();
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -79,3 +79,7 @@ export async function getWgClientConfig(id: number): Promise<string> {
|
|||
export function downloadWgConfig(id: number, name: string) {
|
||||
return api.download({ url: `/wireguard/client/${id}/configuration` }, `${name}.conf`);
|
||||
}
|
||||
|
||||
export function downloadWgConfigZip(id: number, name: string) {
|
||||
return api.download({ url: `/wireguard/client/${id}/configuration.zip` }, `${name}.zip`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,11 @@ import {
|
|||
IconServer,
|
||||
IconEdit,
|
||||
IconLink,
|
||||
IconZip,
|
||||
} from "@tabler/icons-react";
|
||||
import EasyModal from "ez-modal-react";
|
||||
import { useState } from "react";
|
||||
import { downloadWgConfig } from "src/api/backend/wireguard";
|
||||
import { downloadWgConfig, downloadWgConfigZip } from "src/api/backend/wireguard";
|
||||
import { Loading } from "src/components";
|
||||
import {
|
||||
useWgClients,
|
||||
|
|
@ -154,6 +155,11 @@ function WireGuard() {
|
|||
downloadWgConfig(id, cleanName);
|
||||
};
|
||||
|
||||
const handleDownloadZip = (id: number, name: string) => {
|
||||
const cleanName = name.replace(/[^a-zA-Z0-9_.-]/g, "-").substring(0, 32);
|
||||
downloadWgConfigZip(id, cleanName);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="container-xl">
|
||||
{/* Page Header */}
|
||||
|
|
@ -411,6 +417,16 @@ function WireGuard() {
|
|||
>
|
||||
<IconDownload size={16} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-primary"
|
||||
title="Download Config + QR (ZIP)"
|
||||
onClick={() =>
|
||||
handleDownloadZip(client.id, client.name)
|
||||
}
|
||||
>
|
||||
<IconZip size={16} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`btn ${client.enabled ? "btn-outline-warning" : "btn-outline-success"}`}
|
||||
|
|
|
|||
82
install.sh
82
install.sh
|
|
@ -139,6 +139,16 @@ generate_docker_compose() {
|
|||
fi
|
||||
|
||||
log_step "Generating docker-compose.yml..."
|
||||
|
||||
local custom_ports_block=""
|
||||
if [ -f ".custom_ports" ]; then
|
||||
while IFS= read -r port_mapping; do
|
||||
# Ignore empty lines or comments
|
||||
[[ -z "$port_mapping" || "$port_mapping" =~ ^# ]] && continue
|
||||
custom_ports_block+=" - \"${port_mapping}\"\n"
|
||||
done < ".custom_ports"
|
||||
fi
|
||||
|
||||
cat > "$COMPOSE_FILE" <<YAML
|
||||
services:
|
||||
d3v-npmwg:
|
||||
|
|
@ -156,7 +166,7 @@ services:
|
|||
- "81:81" # Admin UI
|
||||
- "443:443" # HTTPS
|
||||
- "51820-51830:51820-51830/udp" # WireGuard Multi-Server Range
|
||||
volumes:
|
||||
$(echo -e "$custom_ports_block" | sed '/^$/d') volumes:
|
||||
- ./data:/data
|
||||
- ./letsencrypt:/etc/letsencrypt
|
||||
- ./wireguard:/etc/wireguard
|
||||
|
|
@ -395,6 +405,62 @@ do_update() {
|
|||
log_ok "Done."
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# 7. Toggle Port 81 (Admin UI)
|
||||
# -----------------------------------------------------------
|
||||
# x. Custom Stream Ports Manager
|
||||
# -----------------------------------------------------------
|
||||
do_manage_ports() {
|
||||
require_root
|
||||
echo ""
|
||||
log_step "TCP/UDP Stream Ports Manager"
|
||||
echo "If you created a Stream in Nginx Proxy Manager (e.g., listening on port 10000),"
|
||||
echo "you must expose that port down to the Docker container."
|
||||
echo ""
|
||||
|
||||
local custom_ports_file=".custom_ports"
|
||||
touch "$custom_ports_file"
|
||||
|
||||
echo "Current custom exposed ports:"
|
||||
if [ -s "$custom_ports_file" ]; then
|
||||
cat -n "$custom_ports_file"
|
||||
else
|
||||
echo " (None)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
read -rp "$(echo -e "${CYAN}[?]${NC} Enter new port mapping (e.g. 10000:10000) or 'clear' to remove all: ")" new_port
|
||||
|
||||
if [[ "$new_port" == "clear" ]]; then
|
||||
> "$custom_ports_file"
|
||||
log_ok "All custom ports cleared."
|
||||
elif [[ -n "$new_port" ]]; then
|
||||
echo "$new_port" >> "$custom_ports_file"
|
||||
log_ok "Port $new_port added."
|
||||
else
|
||||
log_warn "No changes made."
|
||||
return
|
||||
fi
|
||||
|
||||
log_step "Regenerating docker-compose.yml and restarting container..."
|
||||
|
||||
local dc
|
||||
dc=$(get_compose_cmd)
|
||||
|
||||
local current_wg_host=""
|
||||
if [ -f "docker-compose.yml" ]; then
|
||||
current_wg_host=$(grep -E 'WG_HOST:' docker-compose.yml | awk -F'"' '{print $2}')
|
||||
fi
|
||||
if [ -z "$current_wg_host" ]; then
|
||||
current_wg_host=$(detect_public_ip)
|
||||
fi
|
||||
|
||||
generate_docker_compose "$current_wg_host"
|
||||
|
||||
$dc up -d
|
||||
log_ok "Container updated with new port configurations."
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# 7. Toggle Port 81 (Admin UI)
|
||||
# -----------------------------------------------------------
|
||||
|
|
@ -435,10 +501,11 @@ show_menu() {
|
|||
echo " 3) Uninstall D3V-NPMWG + Docker (Purge)"
|
||||
echo " 4) Reset Admin Password"
|
||||
echo " 5) Update D3V-NPMWG"
|
||||
echo " 6) Toggle Admin Port 81 (Block/Unblock)"
|
||||
echo " 7) Exit"
|
||||
echo " 6) Manage Custom Stream Ports"
|
||||
echo " 7) Toggle Admin Port 81 (Block/Unblock)"
|
||||
echo " 8) Exit"
|
||||
separator
|
||||
read -rp " Select [1-7]: " choice
|
||||
read -rp " Select [1-8]: " choice
|
||||
echo ""
|
||||
case "$choice" in
|
||||
1) do_install ;;
|
||||
|
|
@ -446,8 +513,9 @@ show_menu() {
|
|||
3) do_purge ;;
|
||||
4) do_reset_password ;;
|
||||
5) do_update ;;
|
||||
6) do_toggle_port_81 ;;
|
||||
7) echo "Bye!"; exit 0 ;;
|
||||
6) do_manage_ports ;;
|
||||
7) do_toggle_port_81 ;;
|
||||
8) echo "Bye!"; exit 0 ;;
|
||||
*) log_err "Invalid option." ;;
|
||||
esac
|
||||
done
|
||||
|
|
@ -462,6 +530,7 @@ show_help() {
|
|||
echo " purge Remove D3V-NPMWG AND Docker"
|
||||
echo " reset Reset web admin password"
|
||||
echo " update Pull latest image and restart"
|
||||
echo " manage-ports Add or remove custom exposed Stream TCP/UDP ports"
|
||||
echo " toggle-port Block or unblock external access to Admin UI (Port 81) using iptables"
|
||||
echo " help Show this help"
|
||||
echo ""
|
||||
|
|
@ -480,6 +549,7 @@ else
|
|||
purge) do_purge ;;
|
||||
reset) do_reset_password ;;
|
||||
update) do_update ;;
|
||||
manage-ports) do_manage_ports ;;
|
||||
toggle-port) do_toggle_port_81 ;;
|
||||
help|-h|--help) show_help ;;
|
||||
*)
|
||||
|
|
|
|||
Loading…
Reference in a new issue