mirror of
https://github.com/ngoduykhanh/wireguard-ui.git
synced 2025-04-21 20:12:33 +03:00
Merge branch 'ngoduykhanh:master' into support-multi-subnet
This commit is contained in:
commit
655375258e
16 changed files with 204 additions and 99 deletions
64
.github/stale.yml
vendored
64
.github/stale.yml
vendored
|
@ -1,19 +1,57 @@
|
||||||
# Number of days of inactivity before an issue becomes stale
|
# Configuration for probot-stale - https://github.com/probot/stale
|
||||||
|
|
||||||
|
# Number of days of inactivity before an Issue or Pull Request becomes stale
|
||||||
daysUntilStale: 60
|
daysUntilStale: 60
|
||||||
# Number of days of inactivity before a stale issue is closed
|
|
||||||
|
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
|
||||||
|
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
|
||||||
daysUntilClose: 7
|
daysUntilClose: 7
|
||||||
# Issues with these labels will never be considered stale
|
|
||||||
exemptLabels:
|
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
|
||||||
- pinned
|
onlyLabels: []
|
||||||
- security
|
|
||||||
- enhancement
|
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
|
||||||
- feature request
|
exemptLabels: []
|
||||||
# Label to use when marking an issue as stale
|
|
||||||
staleLabel: wontfix
|
# Set to true to ignore issues in a project (defaults to false)
|
||||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
exemptProjects: false
|
||||||
|
|
||||||
|
# Set to true to ignore issues in a milestone (defaults to false)
|
||||||
|
exemptMilestones: false
|
||||||
|
|
||||||
|
# Set to true to ignore issues with an assignee (defaults to false)
|
||||||
|
exemptAssignees: false
|
||||||
|
|
||||||
|
# Label to use when marking as stale
|
||||||
|
staleLabel: stale
|
||||||
|
|
||||||
|
# Comment to post when marking as stale. Set to `false` to disable
|
||||||
markComment: >
|
markComment: >
|
||||||
This issue has been automatically marked as stale because it has not had
|
This issue has been automatically marked as stale because it has not had
|
||||||
recent activity. It will be closed if no further activity occurs. Thank you
|
recent activity. It will be closed if no further activity occurs. Thank you
|
||||||
for your contributions.
|
for your contributions.
|
||||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
|
||||||
closeComment: true
|
# Comment to post when closing a stale Issue or Pull Request.
|
||||||
|
# closeComment: >
|
||||||
|
# Your comment here.
|
||||||
|
|
||||||
|
# Limit the number of actions per hour, from 1-30. Default is 30
|
||||||
|
limitPerRun: 30
|
||||||
|
|
||||||
|
# Limit to only `issues` or `pulls`
|
||||||
|
# only: issues
|
||||||
|
|
||||||
|
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
|
||||||
|
# pulls:
|
||||||
|
# daysUntilStale: 30
|
||||||
|
# markComment: >
|
||||||
|
# This pull request has been automatically marked as stale because it has not had
|
||||||
|
# recent activity. It will be closed if no further activity occurs. Thank you
|
||||||
|
# for your contributions.
|
||||||
|
|
||||||
|
issues:
|
||||||
|
exemptLabels:
|
||||||
|
- enhancement
|
||||||
|
- feature request
|
||||||
|
- documentation
|
||||||
|
- bug
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
# Build stage
|
# Build stage
|
||||||
FROM golang:1.16.7-alpine3.14 as builder
|
FROM golang:1.16.7-alpine3.14 as builder
|
||||||
LABEL maintainer="Khanh Ngo <k@ndk.name"
|
LABEL maintainer="Khanh Ngo <k@ndk.name"
|
||||||
|
|
||||||
|
ARG TARGETOS=linux
|
||||||
|
ARG TARGETARCH=amd64
|
||||||
|
|
||||||
ARG BUILD_DEPENDENCIES="npm \
|
ARG BUILD_DEPENDENCIES="npm \
|
||||||
yarn"
|
yarn"
|
||||||
|
|
||||||
|
@ -44,7 +48,7 @@ RUN go mod download && \
|
||||||
|
|
||||||
# Build
|
# Build
|
||||||
RUN rice embed-go && \
|
RUN rice embed-go && \
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o wg-ui .
|
CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -a -o wg-ui .
|
||||||
|
|
||||||
# Release stage
|
# Release stage
|
||||||
FROM alpine:3.11
|
FROM alpine:3.11
|
||||||
|
@ -64,5 +68,5 @@ COPY --from=builder --chown=wgui:wgui /build/wg-ui /app
|
||||||
RUN chmod +x wg-ui
|
RUN chmod +x wg-ui
|
||||||
|
|
||||||
EXPOSE 5000/tcp
|
EXPOSE 5000/tcp
|
||||||
HEALTHCHECK CMD ["wget","--output-document=-","--quiet","--tries=1","http://127.0.0.1:5000/login"]
|
HEALTHCHECK CMD ["wget","--output-document=-","--quiet","--tries=1","http://127.0.0.1:5000/_health"]
|
||||||
ENTRYPOINT ["./wg-ui"]
|
ENTRYPOINT ["./wg-ui"]
|
||||||
|
|
2
Jenkinsfile
vendored
Normal file
2
Jenkinsfile
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
@Library('ndk-jenkins-shared-libs')_
|
||||||
|
imageBuilder('wireguard-ui')
|
|
@ -37,7 +37,7 @@ In order to sent the wireguard configuration to clients via email (using sendgri
|
||||||
|
|
||||||
```
|
```
|
||||||
SENDGRID_API_KEY: Your sendgrid api key
|
SENDGRID_API_KEY: Your sendgrid api key
|
||||||
EMAIL_FROM: the email address you registered on sendgrid
|
EMAIL_FROM_ADDRESS: the email address you registered on sendgrid
|
||||||
EMAIL_FROM_NAME: the sender's email address
|
EMAIL_FROM_NAME: the sender's email address
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -27,17 +27,25 @@ function renderClientList(data) {
|
||||||
<img src="${obj.QRCode}" />
|
<img src="${obj.QRCode}" />
|
||||||
<div class="info-box-content">
|
<div class="info-box-content">
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button onclick="location.href='/download?clientid=${obj.Client.id}'" type="button"
|
<a href="/download?clientid=${obj.Client.id}" class="btn btn-outline-success btn-sm">Download</a>
|
||||||
class="btn btn-outline-success btn-sm">Download</button>
|
</div>
|
||||||
<button type="button" class="btn btn-outline-warning btn-sm" data-toggle="modal"
|
<div class="btn-group">
|
||||||
|
<button type="button" class="btn btn-outline-secondary btn-sm" data-toggle="modal"
|
||||||
data-target="#modal_email_client" data-clientid="${obj.Client.id}"
|
data-target="#modal_email_client" data-clientid="${obj.Client.id}"
|
||||||
data-clientname="${obj.Client.name}">Email</button>
|
data-clientname="${obj.Client.name}">Email</button>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group">
|
||||||
<button type="button" class="btn btn-outline-primary btn-sm" data-toggle="modal"
|
<button type="button" class="btn btn-outline-primary btn-sm" data-toggle="modal"
|
||||||
data-target="#modal_edit_client" data-clientid="${obj.Client.id}"
|
data-target="#modal_edit_client" data-clientid="${obj.Client.id}"
|
||||||
data-clientname="${obj.Client.name}">Edit</button>
|
data-clientname="${obj.Client.name}">Edit</button>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group">
|
||||||
<button type="button" class="btn btn-outline-warning btn-sm" data-toggle="modal"
|
<button type="button" class="btn btn-outline-warning btn-sm" data-toggle="modal"
|
||||||
data-target="#modal_pause_client" data-clientid="${obj.Client.id}"
|
data-target="#modal_pause_client" data-clientid="${obj.Client.id}"
|
||||||
data-clientname="${obj.Client.name}">Disable</button>
|
data-clientname="${obj.Client.name}">Disable</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="btn-group">
|
||||||
<button type="button" class="btn btn-outline-danger btn-sm" data-toggle="modal"
|
<button type="button" class="btn btn-outline-danger btn-sm" data-toggle="modal"
|
||||||
data-target="#modal_remove_client" data-clientid="${obj.Client.id}"
|
data-target="#modal_remove_client" data-clientid="${obj.Client.id}"
|
||||||
data-clientname="${obj.Client.name}">Remove</button>
|
data-clientname="${obj.Client.name}">Remove</button>
|
||||||
|
@ -46,9 +54,9 @@ function renderClientList(data) {
|
||||||
<span class="info-box-text"><i class="fas fa-user"></i> ${obj.Client.name}</span>
|
<span class="info-box-text"><i class="fas fa-user"></i> ${obj.Client.name}</span>
|
||||||
<span class="info-box-text"><i class="fas fa-envelope"></i> ${obj.Client.email}</span>
|
<span class="info-box-text"><i class="fas fa-envelope"></i> ${obj.Client.email}</span>
|
||||||
<span class="info-box-text"><i class="fas fa-clock"></i>
|
<span class="info-box-text"><i class="fas fa-clock"></i>
|
||||||
${obj.Client.created_at}</span>
|
${prettyDateTime(obj.Client.created_at)}</span>
|
||||||
<span class="info-box-text"><i class="fas fa-history"></i>
|
<span class="info-box-text"><i class="fas fa-history"></i>
|
||||||
${obj.Client.updated_at}</span>
|
${prettyDateTime(obj.Client.updated_at)}</span>
|
||||||
<span class="info-box-text"><i class="fas fa-server" style="${obj.Client.use_server_dns ? "opacity: 1.0" : "opacity: 0.5"}"></i>
|
<span class="info-box-text"><i class="fas fa-server" style="${obj.Client.use_server_dns ? "opacity: 1.0" : "opacity: 0.5"}"></i>
|
||||||
${obj.Client.use_server_dns ? 'DNS enabled' : 'DNS disabled'}</span>
|
${obj.Client.use_server_dns ? 'DNS enabled' : 'DNS disabled'}</span>
|
||||||
<span class="info-box-text"><strong>IP Allocation</strong></span>`
|
<span class="info-box-text"><strong>IP Allocation</strong></span>`
|
||||||
|
@ -63,3 +71,10 @@ function renderClientList(data) {
|
||||||
$('#client-list').append(html);
|
$('#client-list').append(html);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function prettyDateTime(timeStr) {
|
||||||
|
const dt = new Date(timeStr);
|
||||||
|
const offsetMs = dt.getTimezoneOffset() * 60 * 1000;
|
||||||
|
const dateLocal = new Date(dt.getTime() - offsetMs);
|
||||||
|
return dateLocal.toISOString().slice(0, 19).replace(/-/g, "/").replace("T", " ");
|
||||||
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ services:
|
||||||
network_mode: host
|
network_mode: host
|
||||||
environment:
|
environment:
|
||||||
- SENDGRID_API_KEY
|
- SENDGRID_API_KEY
|
||||||
- EMAIL_FROM
|
- EMAIL_FROM_ADDRESS
|
||||||
- EMAIL_FROM_NAME
|
- EMAIL_FROM_NAME
|
||||||
- SESSION_SECRET
|
- SESSION_SECRET
|
||||||
- WGUI_USERNAME=alpha
|
- WGUI_USERNAME=alpha
|
||||||
|
|
|
@ -24,6 +24,13 @@ import (
|
||||||
"github.com/ngoduykhanh/wireguard-ui/util"
|
"github.com/ngoduykhanh/wireguard-ui/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Health check handler
|
||||||
|
func Health() echo.HandlerFunc {
|
||||||
|
return func(c echo.Context) error {
|
||||||
|
return c.String(http.StatusOK, "ok")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// LoginPage handler
|
// LoginPage handler
|
||||||
func LoginPage() echo.HandlerFunc {
|
func LoginPage() echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
|
@ -346,7 +353,7 @@ func DownloadClient(db store.IStore) echo.HandlerFunc {
|
||||||
reader := strings.NewReader(config)
|
reader := strings.NewReader(config)
|
||||||
|
|
||||||
// set response header for downloading
|
// set response header for downloading
|
||||||
c.Response().Header().Set(echo.HeaderContentDisposition, "attachment; filename=wg0.conf")
|
c.Response().Header().Set(echo.HeaderContentDisposition, fmt.Sprintf("attachment; filename=%s.conf", clientData.Client.Name))
|
||||||
return c.Stream(http.StatusOK, "text/plain", reader)
|
return c.Stream(http.StatusOK, "text/plain", reader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -621,7 +628,11 @@ func SuggestIPAllocation(db store.IStore) echo.HandlerFunc {
|
||||||
fmt.Sprintf("Cannot suggest ip allocation: failed to get available ip from network %s", cidr),
|
fmt.Sprintf("Cannot suggest ip allocation: failed to get available ip from network %s", cidr),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
suggestedIPs = append(suggestedIPs, fmt.Sprintf("%s/32", ip))
|
if (strings.Contains(ip, ":")) {
|
||||||
|
suggestedIPs = append(suggestedIPs, fmt.Sprintf("%s/128", ip))
|
||||||
|
} else {
|
||||||
|
suggestedIPs = append(suggestedIPs, fmt.Sprintf("%s/32", ip))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.JSON(http.StatusOK, suggestedIPs)
|
return c.JSON(http.StatusOK, suggestedIPs)
|
||||||
|
|
4
main.go
4
main.go
|
@ -34,7 +34,7 @@ var (
|
||||||
const (
|
const (
|
||||||
defaultEmailSubject = "Your wireguard configuration"
|
defaultEmailSubject = "Your wireguard configuration"
|
||||||
defaultEmailContent = `Hi,</br>
|
defaultEmailContent = `Hi,</br>
|
||||||
<p>in this email you can file your personal configuration for our wireguard server.</p>
|
<p>In this email you can find your personal configuration for our wireguard server.</p>
|
||||||
|
|
||||||
<p>Best</p>
|
<p>Best</p>
|
||||||
`
|
`
|
||||||
|
@ -43,6 +43,7 @@ const (
|
||||||
func init() {
|
func init() {
|
||||||
|
|
||||||
// command-line flags and env variables
|
// command-line flags and env variables
|
||||||
|
flag.BoolVar(&flagDisableLogin, "disable-login", util.LookupEnvOrBool("DISABLE_LOGIN", flagDisableLogin), "Disable authentication on the app. This is potentially dangerous.")
|
||||||
flag.StringVar(&flagBindAddress, "bind-address", util.LookupEnvOrString("BIND_ADDRESS", flagBindAddress), "Address:Port to which the app will be bound.")
|
flag.StringVar(&flagBindAddress, "bind-address", util.LookupEnvOrString("BIND_ADDRESS", flagBindAddress), "Address:Port to which the app will be bound.")
|
||||||
flag.StringVar(&flagSendgridApiKey, "sendgrid-api-key", util.LookupEnvOrString("SENDGRID_API_KEY", flagSendgridApiKey), "Your sendgrid api key.")
|
flag.StringVar(&flagSendgridApiKey, "sendgrid-api-key", util.LookupEnvOrString("SENDGRID_API_KEY", flagSendgridApiKey), "Your sendgrid api key.")
|
||||||
flag.StringVar(&flagEmailFrom, "email-from", util.LookupEnvOrString("EMAIL_FROM_ADDRESS", flagEmailFrom), "'From' email address.")
|
flag.StringVar(&flagEmailFrom, "email-from", util.LookupEnvOrString("EMAIL_FROM_ADDRESS", flagEmailFrom), "'From' email address.")
|
||||||
|
@ -104,6 +105,7 @@ func main() {
|
||||||
|
|
||||||
sendmail := emailer.NewSendgridApiMail(util.SendgridApiKey, util.EmailFromName, util.EmailFrom)
|
sendmail := emailer.NewSendgridApiMail(util.SendgridApiKey, util.EmailFromName, util.EmailFrom)
|
||||||
|
|
||||||
|
app.GET("/_health", handler.Health())
|
||||||
app.GET("/logout", handler.Logout(), handler.ValidSession)
|
app.GET("/logout", handler.Logout(), handler.ValidSession)
|
||||||
app.POST("/new-client", handler.NewClient(db), handler.ValidSession)
|
app.POST("/new-client", handler.NewClient(db), handler.ValidSession)
|
||||||
app.POST("/update-client", handler.UpdateClient(db), handler.ValidSession)
|
app.POST("/update-client", handler.UpdateClient(db), handler.ValidSession)
|
||||||
|
|
|
@ -4,7 +4,9 @@ set -e
|
||||||
DIR=$(dirname "$0")
|
DIR=$(dirname "$0")
|
||||||
|
|
||||||
# install node modules
|
# install node modules
|
||||||
yarn install --pure-lockfile --production
|
YARN=yarn
|
||||||
|
[ -x /usr/bin/lsb_release ] && [ -n "`lsb_release -i | grep Debian`" ] && YARN=yarnpkg
|
||||||
|
$YARN install --pure-lockfile --production
|
||||||
|
|
||||||
# Copy admin-lte dist
|
# Copy admin-lte dist
|
||||||
mkdir -p "${DIR}/assets/dist/js" "${DIR}/assets/dist/css" && \
|
mkdir -p "${DIR}/assets/dist/js" "${DIR}/assets/dist/css" && \
|
||||||
|
|
|
@ -44,17 +44,17 @@
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<!-- SEARCH FORM -->
|
<!-- SEARCH FORM -->
|
||||||
<form class="form-inline ml-3">
|
<!-- <form class="form-inline ml-3">-->
|
||||||
<div class="input-group input-group-sm">
|
<!-- <div class="input-group input-group-sm">-->
|
||||||
<input class="form-control form-control-navbar" type="search" placeholder="Search"
|
<!-- <input class="form-control form-control-navbar" type="search" placeholder="Search"-->
|
||||||
aria-label="Search">
|
<!-- aria-label="Search">-->
|
||||||
<div class="input-group-append">
|
<!-- <div class="input-group-append">-->
|
||||||
<button class="btn btn-navbar" type="submit">
|
<!-- <button class="btn btn-navbar" type="submit">-->
|
||||||
<i class="fas fa-search"></i>
|
<!-- <i class="fas fa-search"></i>-->
|
||||||
</button>
|
<!-- </button>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</form>
|
<!-- </form>-->
|
||||||
|
|
||||||
<!-- Right navbar links -->
|
<!-- Right navbar links -->
|
||||||
<div class="navbar-nav ml-auto">
|
<div class="navbar-nav ml-auto">
|
||||||
|
@ -238,7 +238,7 @@
|
||||||
<div class="float-right d-none d-sm-block">
|
<div class="float-right d-none d-sm-block">
|
||||||
<b>Version</b> {{ .appVersion }}
|
<b>Version</b> {{ .appVersion }}
|
||||||
</div>
|
</div>
|
||||||
<strong>Copyright © 2020 <a href="https://github.com/ngoduykhanh/wireguard-ui">Wireguard UI</a>.</strong> All rights
|
<strong>Copyright © <script>document.write(new Date().getFullYear())</script> <a href="https://github.com/ngoduykhanh/wireguard-ui">Wireguard UI</a>.</strong> All rights
|
||||||
reserved.
|
reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
@ -388,19 +388,11 @@
|
||||||
client_name: {
|
client_name: {
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
client_email: {
|
|
||||||
required: true,
|
|
||||||
email: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
messages: {
|
messages: {
|
||||||
client_name: {
|
client_name: {
|
||||||
required: "Please enter a name"
|
required: "Please enter a name"
|
||||||
},
|
},
|
||||||
client_email: {
|
|
||||||
required: "Please enter an email address",
|
|
||||||
email: "Please enter a valid email address"
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
errorElement: 'span',
|
errorElement: 'span',
|
||||||
errorPlacement: function (error, element) {
|
errorPlacement: function (error, element) {
|
||||||
|
|
|
@ -44,7 +44,7 @@ Wireguard Clients
|
||||||
<input type="hidden" id="e_client_id" name="e_client_id">
|
<input type="hidden" id="e_client_id" name="e_client_id">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="e_client_email" class="control-label">Email</label>
|
<label for="e_client_email" class="control-label">Email</label>
|
||||||
<input type="text" class="form-control" id="e_client_email" name="client_email">
|
<input type="text" class="form-control" id="e_client_email" name="e_client_email">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer justify-content-between">
|
<div class="modal-footer justify-content-between">
|
||||||
|
@ -447,50 +447,40 @@ Wireguard Clients
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Edit client form validation
|
// Edit client form validation
|
||||||
$("#frm_edit_client").validate({
|
$("#frm_edit_client").validate({
|
||||||
rules: {
|
|
||||||
client_name: {
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
client_email: {
|
|
||||||
required: true,
|
|
||||||
email: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
messages: {
|
|
||||||
client_name: {
|
|
||||||
required: "Please enter a name"
|
|
||||||
},
|
|
||||||
client_email: {
|
|
||||||
required: "Please enter an email address",
|
|
||||||
email: "Please enter a valid email address"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
errorElement: 'span',
|
|
||||||
errorPlacement: function (error, element) {
|
|
||||||
error.addClass('invalid-feedback');
|
|
||||||
element.closest('.form-group').append(error);
|
|
||||||
},
|
|
||||||
highlight: function (element, errorClass, validClass) {
|
|
||||||
$(element).addClass('is-invalid');
|
|
||||||
},
|
|
||||||
unhighlight: function (element, errorClass, validClass) {
|
|
||||||
$(element).removeClass('is-invalid');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Email client form validation
|
|
||||||
$("#frm_email_client").validate({
|
|
||||||
rules: {
|
rules: {
|
||||||
client_email: {
|
client_name: {
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
messages: {
|
||||||
|
client_name: {
|
||||||
|
required: "Please enter a name"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errorElement: 'span',
|
||||||
|
errorPlacement: function (error, element) {
|
||||||
|
error.addClass('invalid-feedback');
|
||||||
|
element.closest('.form-group').append(error);
|
||||||
|
},
|
||||||
|
highlight: function (element, errorClass, validClass) {
|
||||||
|
$(element).addClass('is-invalid');
|
||||||
|
},
|
||||||
|
unhighlight: function (element, errorClass, validClass) {
|
||||||
|
$(element).removeClass('is-invalid');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Email client form validation
|
||||||
|
$("#frm_email_client").validate({
|
||||||
|
rules: {
|
||||||
|
e_client_email: {
|
||||||
required: true,
|
required: true,
|
||||||
email: true,
|
email: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
messages: {
|
messages: {
|
||||||
client_email: {
|
e_client_email: {
|
||||||
required: "Please enter an email address",
|
required: "Please enter an email"
|
||||||
email: "Please enter a valid email address"
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
errorElement: 'span',
|
errorElement: 'span',
|
||||||
|
|
|
@ -47,13 +47,13 @@ Global Settings
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="mtu">MTU</label>
|
<label for="mtu">MTU</label>
|
||||||
<input type="text" class="form-control" id="mtu" name="mtu" placeholder="MTU"
|
<input type="text" class="form-control" id="mtu" name="mtu" placeholder="MTU"
|
||||||
value="{{ .globalSettings.MTU }}">
|
value="{{if .globalSettings.MTU}}{{ .globalSettings.MTU }}{{end}}">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="persistent_keepalive">Persistent Keepalive</label>
|
<label for="persistent_keepalive">Persistent Keepalive</label>
|
||||||
<input type="text" class="form-control" id="persistent_keepalive"
|
<input type="text" class="form-control" id="persistent_keepalive"
|
||||||
name="persistent_keepalive" placeholder="Persistent Keepalive"
|
name="persistent_keepalive" placeholder="Persistent Keepalive"
|
||||||
value="{{ .globalSettings.PersistentKeepalive }}">
|
value="{{if .globalSettings.PersistentKeepalive }}{{ .globalSettings.PersistentKeepalive }}{{end}}">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="config_file_path">Wireguard Config File Path</label>
|
<label for="config_file_path">Wireguard Config File Path</label>
|
||||||
|
@ -71,6 +71,37 @@ Global Settings
|
||||||
</div>
|
</div>
|
||||||
<!-- /.card -->
|
<!-- /.card -->
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card card-success">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title">Help</h3>
|
||||||
|
</div>
|
||||||
|
<!-- /.card-header -->
|
||||||
|
<div class="card-body">
|
||||||
|
<dl>
|
||||||
|
<dt>1. Endpoint Address</dt>
|
||||||
|
<dd>The public IP address of your Wireguard server that the client will connect to. Click on
|
||||||
|
<strong>Suggest</strong> button to auto detect the public IP address of your server.</dd>
|
||||||
|
<dt>2. DNS Servers</dt>
|
||||||
|
<dd>The DNS servers will be set to client config.</dd>
|
||||||
|
<dt>3. MTU</dt>
|
||||||
|
<dd>The MTU will be set to server config. By default it is <code>1420</code>. You might want
|
||||||
|
to adjust the MTU size if your connection (e.g PPPoE, 3G, satellite network, etc) has a low MTU.</dd>
|
||||||
|
<dd>Leave blank to omit this setting in the Server config.</dd>
|
||||||
|
<dt>4. Persistent Keepalive</dt>
|
||||||
|
<dd>By default, WireGuard peers remain silent while they do not need to communicate,
|
||||||
|
so peers located behind a NAT and/or firewall may be unreachable from other peers
|
||||||
|
until they reach out to other peers themselves. Adding <code>PersistentKeepalive</code>
|
||||||
|
can ensure that the connection remains open.</dd>
|
||||||
|
<dd>Leave blank to omit this setting in the Client config.</dd>
|
||||||
|
<dt>5. Wireguard Config File Path</dt>
|
||||||
|
<dd>The path of your Wireguard server config file. Please make sure the parent directory
|
||||||
|
exists and is writable.</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- /.card -->
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.row -->
|
<!-- /.row -->
|
||||||
</div>
|
</div>
|
||||||
|
@ -172,12 +203,10 @@ Global Settings
|
||||||
$("#frm_global_settings").validate({
|
$("#frm_global_settings").validate({
|
||||||
rules: {
|
rules: {
|
||||||
mtu: {
|
mtu: {
|
||||||
required: true,
|
|
||||||
digits: true,
|
digits: true,
|
||||||
range: [68, 65535]
|
range: [68, 65535]
|
||||||
},
|
},
|
||||||
persistent_keepalive: {
|
persistent_keepalive: {
|
||||||
required: true,
|
|
||||||
digits: true
|
digits: true
|
||||||
},
|
},
|
||||||
config_file_path: {
|
config_file_path: {
|
||||||
|
@ -186,12 +215,10 @@ Global Settings
|
||||||
},
|
},
|
||||||
messages: {
|
messages: {
|
||||||
mtu: {
|
mtu: {
|
||||||
required: "Please enter a MTU value",
|
|
||||||
digits: "MTU must be an integer",
|
digits: "MTU must be an integer",
|
||||||
range: "MTU must be in range 68..65535"
|
range: "MTU must be in range 68..65535"
|
||||||
},
|
},
|
||||||
persistent_keepalive: {
|
persistent_keepalive: {
|
||||||
required: "Please enter a Persistent Keepalive value",
|
|
||||||
digits: "Persistent keepalive must be an integer"
|
digits: "Persistent keepalive must be an integer"
|
||||||
},
|
},
|
||||||
config_file_path: {
|
config_file_path: {
|
||||||
|
|
|
@ -57,7 +57,7 @@
|
||||||
</div>
|
</div>
|
||||||
<!-- /.col -->
|
<!-- /.col -->
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
<button id="btn_login" type="button" class="btn btn-primary btn-block">Sign In</button>
|
<button id="btn_login" type="submit" class="btn btn-primary btn-block">Sign In</button>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.col -->
|
<!-- /.col -->
|
||||||
</div>
|
</div>
|
||||||
|
@ -91,6 +91,11 @@
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
|
$('form').on('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$("#btn_login").trigger('click');
|
||||||
|
});
|
||||||
|
|
||||||
$("#btn_login").click(function () {
|
$("#btn_login").click(function () {
|
||||||
const username = $("#username").val();
|
const username = $("#username").val();
|
||||||
const password = $("#password").val();
|
const password = $("#password").val();
|
||||||
|
|
|
@ -14,6 +14,20 @@ Connected Peers
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{define "page_content"}}
|
{{define "page_content"}}
|
||||||
|
<script>
|
||||||
|
function bytesToHumanReadable(temporal) {
|
||||||
|
const units = [" ", " K", " M", " G", " T", " P", " E", " Z", " Y"]
|
||||||
|
let pow = 0
|
||||||
|
|
||||||
|
while (temporal > 1024) {
|
||||||
|
temporal /= 1024
|
||||||
|
pow ++
|
||||||
|
if (pow == units.length-1) break
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseFloat(temporal.toFixed(3)) + units[pow]+"Bytes"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
<section class="content">
|
<section class="content">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
{{ if .error }}
|
{{ if .error }}
|
||||||
|
@ -41,8 +55,8 @@ Connected Peers
|
||||||
<td>{{ $peer.Name }}</td>
|
<td>{{ $peer.Name }}</td>
|
||||||
<td>{{ $peer.Email }}</td>
|
<td>{{ $peer.Email }}</td>
|
||||||
<td>{{ $peer.PublicKey }}</td>
|
<td>{{ $peer.PublicKey }}</td>
|
||||||
<td>{{ $peer.ReceivedBytes }}</td>
|
<td title="{{ $peer.ReceivedBytes }} Bytes"><script>document.write(bytesToHumanReadable({{ $peer.ReceivedBytes }}))</script></td>
|
||||||
<td>{{ $peer.TransmitBytes }}</td>
|
<td title="{{ $peer.TransmitBytes }} Bytes"><script>document.write(bytesToHumanReadable({{ $peer.TransmitBytes }}))</script></td>
|
||||||
<td>{{ $peer.Connected }}</td>
|
<td>{{ $peer.Connected }}</td>
|
||||||
<td>{{ $peer.LastHandshakeTime }}</td>
|
<td>{{ $peer.LastHandshakeTime }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# This file was generated using wireguard-ui (https://github.com/ngoduykhanh/wireguard-ui)
|
# This file was generated using wireguard-ui (https://github.com/ngoduykhanh/wireguard-ui)
|
||||||
# Please don't modify it manually, otherwise your change might got replaced.
|
# Please don't modify it manually, otherwise your change might get replaced.
|
||||||
|
|
||||||
# Address updated at: {{ .serverConfig.Interface.UpdatedAt }}
|
# Address updated at: {{ .serverConfig.Interface.UpdatedAt }}
|
||||||
# Private Key updated at: {{ .serverConfig.KeyPair.UpdatedAt }}
|
# Private Key updated at: {{ .serverConfig.KeyPair.UpdatedAt }}
|
||||||
|
@ -7,7 +7,7 @@
|
||||||
Address = {{$first :=true}}{{range .serverConfig.Interface.Addresses }}{{if $first}}{{$first = false}}{{else}},{{end}}{{.}}{{end}}
|
Address = {{$first :=true}}{{range .serverConfig.Interface.Addresses }}{{if $first}}{{$first = false}}{{else}},{{end}}{{.}}{{end}}
|
||||||
ListenPort = {{ .serverConfig.Interface.ListenPort }}
|
ListenPort = {{ .serverConfig.Interface.ListenPort }}
|
||||||
PrivateKey = {{ .serverConfig.KeyPair.PrivateKey }}
|
PrivateKey = {{ .serverConfig.KeyPair.PrivateKey }}
|
||||||
MTU = {{ .globalSettings.MTU }}
|
{{if .globalSettings.MTU}}MTU = {{ .globalSettings.MTU }}{{end}}
|
||||||
PostUp = {{ .serverConfig.Interface.PostUp }}
|
PostUp = {{ .serverConfig.Interface.PostUp }}
|
||||||
PostDown = {{ .serverConfig.Interface.PostDown }}
|
PostDown = {{ .serverConfig.Interface.PostDown }}
|
||||||
|
|
||||||
|
|
|
@ -41,12 +41,15 @@ func BuildClientConfig(client model.Client, server model.Server, setting model.G
|
||||||
if n, err := strconv.Atoi(split[1]); err == nil {
|
if n, err := strconv.Atoi(split[1]); err == nil {
|
||||||
desiredPort = n
|
desiredPort = n
|
||||||
} else {
|
} else {
|
||||||
log.Error("Endpoint appears to be incorrectly formated: ", err)
|
log.Error("Endpoint appears to be incorrectly formatted: ", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
peerEndpoint := fmt.Sprintf("Endpoint = %s:%d", desiredHost, desiredPort)
|
peerEndpoint := fmt.Sprintf("Endpoint = %s:%d", desiredHost, desiredPort)
|
||||||
|
|
||||||
peerPersistentKeepalive := fmt.Sprintf("PersistentKeepalive = %d", setting.PersistentKeepalive)
|
peerPersistentKeepalive := ""
|
||||||
|
if setting.PersistentKeepalive > 0 {
|
||||||
|
peerPersistentKeepalive = fmt.Sprintf("PersistentKeepalive = %d", setting.PersistentKeepalive)
|
||||||
|
}
|
||||||
|
|
||||||
// build the config as string
|
// build the config as string
|
||||||
strConfig := "[Interface]\n" +
|
strConfig := "[Interface]\n" +
|
||||||
|
@ -380,7 +383,7 @@ func LookupEnvOrBool(key string, defaultVal bool) bool {
|
||||||
if val, ok := os.LookupEnv(key); ok {
|
if val, ok := os.LookupEnv(key); ok {
|
||||||
v, err := strconv.ParseBool(val)
|
v, err := strconv.ParseBool(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "LookupEnvOrInt[%s]: %v\n", key, err)
|
fmt.Fprintf(os.Stderr, "LookupEnvOrBool[%s]: %v\n", key, err)
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue