Compare commits

...

8 Commits

Author SHA1 Message Date
Donald Zou
b1d7199e84 Improve peer details access and update signin footer UI
Peer details button is now hidden for restricted peers, showing a message instead. The signin page footer layout is updated for better alignment, and the client app link is moved to the right with improved styling.
2025-12-16 17:51:45 +08:00
Donald Zou
0a64b1b377 Merge pull request #1044 from WGDashboard/client_app_button
feat: add client app button
2025-12-16 17:09:25 +08:00
Donald Zou
bc20057de6 Merge pull request #1043 from WGDashboard/main
Merging main into v4.3.2-dev
2025-12-16 07:12:19 +08:00
Donald Zou
c7c9d62e80 Update WireguardConfiguration.py 2025-12-15 21:02:22 +08:00
Donald Zou
f5ccbdf9d3 Fixed Restricted Peer might still appear after restricted 2025-12-15 17:13:46 +08:00
Donald Zou
a09342ed2a Added fallback when instance is completely disconnected from internet 2025-12-15 16:25:13 +08:00
Daan Selen
306e17eb4d refac: some exit logic
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-12-14 20:56:18 +01:00
DaanSelen
d75c7ad418 feat: add better docker stopping response (#1025) 2025-12-14 17:32:46 +01:00
5 changed files with 66 additions and 32 deletions

View File

@@ -1,6 +1,7 @@
#!/bin/bash #!/bin/bash
config_file="/data/wg-dashboard.ini" config_file="/data/wg-dashboard.ini"
runtime_pid=""
trap 'stop_service' SIGTERM trap 'stop_service' SIGTERM
@@ -52,7 +53,31 @@ set_ini() {
stop_service() { stop_service() {
echo "[WGDashboard] Stopping WGDashboard..." echo "[WGDashboard] Stopping WGDashboard..."
/bin/bash ./wgd.sh stop
local max_rounds="10"
local round="0"
local runtime_pid=""
while true; do
round=$((round + 1))
if [[ -f ${WGDASH}/src/gunicorn.pid ]]; then
runtime_pid=$(cat ${WGDASH}/src/gunicorn.pid)
echo "Running as PID: ${runtime_pid}"
return 0
fi
if [[ $round -eq $max_rounds ]]; then
echo "Reached breaking point!"
return 1
fi
sleep 0.5s
done
kill $runtime_pid
exit 0 exit 0
} }
@@ -192,9 +217,10 @@ start_and_monitor() {
[[ ! -d ${WGDASH}/src/log ]] && mkdir ${WGDASH}/src/log [[ ! -d ${WGDASH}/src/log ]] && mkdir ${WGDASH}/src/log
[[ ! -d ${WGDASH}/src/download ]] && mkdir ${WGDASH}/src/download [[ ! -d ${WGDASH}/src/download ]] && mkdir ${WGDASH}/src/download
${WGDASH}/src/venv/bin/gunicorn --config ${WGDASH}/src/gunicorn.conf.py ${WGDASH}/src/venv/bin/gunicorn --config ${WGDASH}/src/gunicorn.conf.py
resolvconf -u /usr/sbin/resolvconf -u
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Loading WGDashboard failed... Look above for details." echo "Loading WGDashboard failed... Look above for details."
@@ -203,13 +229,14 @@ start_and_monitor() {
# Wait a second before continuing, to give the python program some time to get ready. # Wait a second before continuing, to give the python program some time to get ready.
echo -e "\nEnsuring container continuation." echo -e "\nEnsuring container continuation."
max_rounds="10" local max_rounds="10"
round="0" local round="0"
# Hang in there for 10s for Gunicorn to get ready # Hang in there for 10s for Gunicorn to get ready
while true; do while true; do
round=$((round + 1)) round=$((round + 1))
latest_error=$(ls -t ${WGDASH}/src/log/error_*.log 2> /dev/null | head -n 1)
local latest_error=$(ls -t ${WGDASH}/src/log/error_*.log 2> /dev/null | head -n 1)
if [[ $round -eq $max_rounds ]]; then if [[ $round -eq $max_rounds ]]; then
echo "Reached breaking point!" echo "Reached breaking point!"
@@ -235,13 +262,10 @@ start_and_monitor() {
else else
tail -f "$latest_error" & tail -f "$latest_error" &
wait $! tail_pid=$!
wait $tail_pid
fi fi
echo "The blocking command has been broken! Script will exit in 3 minutes... Investigate!"
sleep 180s
exit 1
} }
# Main execution flow # Main execution flow

View File

@@ -18,10 +18,18 @@ def GetRemoteEndpoint() -> str:
@return: @return:
""" """
import socket import socket
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s: try:
s.connect(("1.1.1.1", 80)) # Connecting to a public IP with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect(("1.1.1.1", 80)) # Connecting to a public IP
wgd_remote_endpoint = s.getsockname()[0] wgd_remote_endpoint = s.getsockname()[0]
return str(wgd_remote_endpoint) return str(wgd_remote_endpoint)
except (socket.error, OSError):
pass
try:
return socket.gethostbyname(socket.gethostname())
except (socket.error, OSError):
pass
return "127.0.0.1"
def StringToBoolean(value: str): def StringToBoolean(value: str):

View File

@@ -404,6 +404,7 @@ class WireguardConfiguration:
try: try:
if "[Peer]" not in content: if "[Peer]" not in content:
current_app.logger.info(f"{self.Name} config has no [Peer] section") current_app.logger.info(f"{self.Name} config has no [Peer] section")
self.Peers = []
return return
peerStarts = content.index("[Peer]") peerStarts = content.index("[Peer]")
@@ -665,9 +666,8 @@ class WireguardConfiguration:
if not self.__wgSave(): if not self.__wgSave():
return False, "Failed to save configuration through WireGuard" return False, "Failed to save configuration through WireGuard"
self.getRestrictedPeers()
self.getPeers() self.getPeers()
if numOfRestrictedPeers == len(listOfPublicKeys): if numOfRestrictedPeers == len(listOfPublicKeys):
return True, f"Restricted {numOfRestrictedPeers} peer(s)" return True, f"Restricted {numOfRestrictedPeers} peer(s)"
return False, f"Restricted {numOfRestrictedPeers} peer(s) successfully. Failed to restrict {numOfFailedToRestrictPeers} peer(s)" return False, f"Restricted {numOfRestrictedPeers} peer(s) successfully. Failed to restrict {numOfFailedToRestrictPeers} peer(s)"
@@ -783,9 +783,7 @@ class WireguardConfiguration:
) )
).mappings().fetchone() ).mappings().fetchone()
if cur_i is not None: if cur_i is not None:
# print(cur_i is None)
total_sent = cur_i['total_sent'] total_sent = cur_i['total_sent']
# print(cur_i is None)
total_receive = cur_i['total_receive'] total_receive = cur_i['total_receive']
cur_total_sent = float(data_usage[i][2]) / (1024 ** 3) cur_total_sent = float(data_usage[i][2]) / (1024 ** 3)
cur_total_receive = float(data_usage[i][1]) / (1024 ** 3) cur_total_receive = float(data_usage[i][1]) / (1024 ** 3)
@@ -1226,7 +1224,6 @@ class WireguardConfiguration:
def __validateOverridePeerSettings(self, key: str, value: str | int) -> tuple[bool, None] | tuple[bool, str]: def __validateOverridePeerSettings(self, key: str, value: str | int) -> tuple[bool, None] | tuple[bool, str]:
status = True status = True
msg = None msg = None
print(value)
if key == "DNS" and value: if key == "DNS" and value:
status, msg = ValidateDNSAddress(value) status, msg = ValidateDNSAddress(value)
elif key == "EndpointAllowedIPs" and value: elif key == "EndpointAllowedIPs" and value:

View File

@@ -134,12 +134,17 @@ export default {
</div> </div>
</div> </div>
</div> </div>
<div class="card-footer" role="button" @click="$emit('details')"> <div class="card-footer" role="button" @click="$emit('details')" v-if="!this.Peer.restricted">
<small class="d-flex align-items-center"> <small class="d-flex align-items-center">
<LocaleText t="Details"></LocaleText> <LocaleText t="Details"></LocaleText>
<i class="bi bi-chevron-right ms-auto"></i> <i class="bi bi-chevron-right ms-auto"></i>
</small> </small>
</div> </div>
<div class="card-footer" v-else>
<small class="d-flex align-items-center text-muted">
<LocaleText t="Allow access to view details"></LocaleText>
</small>
</div>
</div> </div>
</template> </template>

View File

@@ -172,16 +172,6 @@ export default {
<RemoteServerList v-else></RemoteServerList> <RemoteServerList v-else></RemoteServerList>
<div class="d-flex mt-3" v-if="!this.store.IsElectronApp"> <div class="d-flex mt-3" v-if="!this.store.IsElectronApp">
<!-- Left: Client App link -->
<a
href="/client"
class="btn btn-sm btn-outline-secondary"
>
<i class="bi bi-box-arrow-up-right me-1"></i>
<LocaleText t="Client App" />
</a>
<!-- Right: Remote server switch -->
<div class="form-check form-switch ms-auto"> <div class="form-check form-switch ms-auto">
<input <input
v-model="this.store.CrossServerConfiguration.Enable" v-model="this.store.CrossServerConfiguration.Enable"
@@ -197,10 +187,20 @@ export default {
</div> </div>
</div> </div>
</div> </div>
<small class="text-muted pb-3 d-block w-100 text-center mt-3"> <div class="d-flex container-fluid align-items-center my-1 w-100">
WGDashboard {{ this.version }} | Developed with by <small class="text-muted">
<a href="https://github.com/donaldzou" target="_blank"><strong>Donald Zou</strong></a> WGDashboard <strong>{{ this.version }}</strong> | Made with by
</small> <a href="https://github.com/WGDashboard"
class="text-decoration-none text-body"
target="_blank"><strong>WGDashboard</strong></a>
</small>
<a href="./client" target="_blank"
class="text-decoration-none ms-auto text-body"
style="white-space: nowrap">
<small><i class="bi bi-box-arrow-up-right me-1"></i>
<LocaleText t="Client App" /></small>
</a>
</div>
<div class="messageCentre text-body position-absolute d-flex"> <div class="messageCentre text-body position-absolute d-flex">
<TransitionGroup name="message" tag="div" <TransitionGroup name="message" tag="div"
class="position-relative flex-sm-grow-0 flex-grow-1 d-flex align-items-end ms-sm-auto flex-column gap-2"> class="position-relative flex-sm-grow-0 flex-grow-1 d-flex align-items-end ms-sm-auto flex-column gap-2">