mirror of
https://github.com/h44z/wg-portal.git
synced 2025-10-05 16:06:17 +00:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
1e35fb2538 | ||
|
400259a0be | ||
|
96c713a513 | ||
|
3645d75d8d | ||
|
a017775f8a | ||
|
e0968b3239 | ||
|
e1db939a18 | ||
|
92d09535bc |
59
.github/workflows/docker-publish.yml
vendored
Normal file
59
.github/workflows/docker-publish.yml
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
name: Docker
|
||||||
|
|
||||||
|
# This workflow uses actions that are not certified by GitHub.
|
||||||
|
# They are provided by a third-party and are governed by
|
||||||
|
# separate terms of service, privacy policy, and support
|
||||||
|
# documentation.
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
# Publish vX.X.X tags as releases.
|
||||||
|
tags: [ 'v*.*.*' ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
# Use docker.io for Docker Hub if empty
|
||||||
|
REGISTRY: ghcr.io
|
||||||
|
# github.repository as <account>/<repo>
|
||||||
|
IMAGE_NAME: ${{ github.repository }}
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
# Login against a Docker registry except on PR
|
||||||
|
# https://github.com/docker/login-action
|
||||||
|
- name: Log into registry ${{ env.REGISTRY }}
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
# Extract metadata (tags, labels) for Docker
|
||||||
|
# https://github.com/docker/metadata-action
|
||||||
|
- name: Extract Docker metadata
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
|
||||||
|
with:
|
||||||
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
|
|
||||||
|
# Build and push Docker image with Buildx (don't push on PR)
|
||||||
|
# https://github.com/docker/build-push-action
|
||||||
|
- name: Build and push Docker image
|
||||||
|
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
22
README.md
22
README.md
@@ -9,11 +9,11 @@
|
|||||||
[](https://hub.docker.com/r/h44z/wg-portal/)
|
[](https://hub.docker.com/r/h44z/wg-portal/)
|
||||||
|
|
||||||
A simple, web based configuration portal for [WireGuard](https://wireguard.com).
|
A simple, web based configuration portal for [WireGuard](https://wireguard.com).
|
||||||
The portal uses the WireGuard [wgctrl](https://github.com/WireGuard/wgctrl-go) library to manage the VPN
|
The portal uses the WireGuard [wgctrl](https://github.com/WireGuard/wgctrl-go) library to manage existing VPN
|
||||||
interface. This allows for seamless activation or deactivation of new users, without disturbing existing VPN
|
interfaces. This allows for seamless activation or deactivation of new users, without disturbing existing VPN
|
||||||
connections.
|
connections.
|
||||||
|
|
||||||
The configuration portal currently supports using SQLite, MySQL as a user source for authentication and profile data.
|
The configuration portal currently supports using SQLite and MySQL as a user source for authentication and profile data.
|
||||||
It also supports LDAP (Active Directory or OpenLDAP) as authentication provider.
|
It also supports LDAP (Active Directory or OpenLDAP) as authentication provider.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
@@ -35,6 +35,8 @@ It also supports LDAP (Active Directory or OpenLDAP) as authentication provider.
|
|||||||

|

|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
Make sure that your host system has at least one WireGuard interface (for example wg0) available.
|
||||||
|
If you did not start up a WireGuard interface yet, take a look at [wg-quick](https://manpages.debian.org/unstable/wireguard-tools/wg-quick.8.en.html) in order to get started.
|
||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
The easiest way to run WireGuard Portal is to use the Docker image provided.
|
The easiest way to run WireGuard Portal is to use the Docker image provided.
|
||||||
@@ -81,11 +83,11 @@ services:
|
|||||||
- LDAP_ADMIN_GROUP=CN=WireGuardAdmins,OU=Users,DC=COMPANY,DC=LOCAL
|
- LDAP_ADMIN_GROUP=CN=WireGuardAdmins,OU=Users,DC=COMPANY,DC=LOCAL
|
||||||
```
|
```
|
||||||
Please note that mapping ```/etc/wireguard``` to ```/etc/wireguard``` inside the docker, will erase your host's current configuration.
|
Please note that mapping ```/etc/wireguard``` to ```/etc/wireguard``` inside the docker, will erase your host's current configuration.
|
||||||
If needed, please make sure to backup your files from ```/etc/wireguard```.
|
If needed, please make sure to back up your files from ```/etc/wireguard```.
|
||||||
For a full list of configuration options take a look at the source file [internal/server/configuration.go](internal/server/configuration.go#L56).
|
For a full list of configuration options take a look at the source file [internal/server/configuration.go](internal/server/configuration.go#L56).
|
||||||
|
|
||||||
### Standalone
|
### Standalone
|
||||||
For a standalone application, use the Makefile provided in the repository to build the application.
|
For a standalone application, use the Makefile provided in the repository to build the application. Go version 1.16 or higher has to be installed to build WireGuard Portal.
|
||||||
|
|
||||||
```
|
```
|
||||||
make
|
make
|
||||||
@@ -200,10 +202,10 @@ The API is documented using OpenAPI 2.0, the Swagger UI can be found
|
|||||||
under the URL `http://<your wg-portal ip/domain>/swagger/index.html`.
|
under the URL `http://<your wg-portal ip/domain>/swagger/index.html`.
|
||||||
|
|
||||||
## What is out of scope
|
## What is out of scope
|
||||||
|
* Creating or removing WireGuard (wgX) interfaces.
|
||||||
* Generation or application of any `iptables` or `nftables` rules
|
* Generation or application of any `iptables` or `nftables` rules.
|
||||||
* Setting up or changing IP-addresses of the WireGuard interface on operating systems other than linux
|
* Setting up or changing IP-addresses of the WireGuard interface on operating systems other than linux.
|
||||||
* Importing private keys of an existing WireGuard setup
|
* Importing private keys of an existing WireGuard setup.
|
||||||
|
|
||||||
## Application stack
|
## Application stack
|
||||||
|
|
||||||
@@ -217,4 +219,4 @@ under the URL `http://<your wg-portal ip/domain>/swagger/index.html`.
|
|||||||
* MIT License. [MIT](LICENSE.txt) or https://opensource.org/licenses/MIT
|
* MIT License. [MIT](LICENSE.txt) or https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
|
||||||
This project was inspired by [wg-gen-web](https://github.com/vx3r/wg-gen-web).
|
This project was inspired by [wg-gen-web](https://github.com/vx3r/wg-gen-web).
|
||||||
|
2
assets/css/bootstrap-tokenfield.min.css
vendored
2
assets/css/bootstrap-tokenfield.min.css
vendored
@@ -2,4 +2,4 @@
|
|||||||
* bootstrap-tokenfield
|
* bootstrap-tokenfield
|
||||||
* https://github.com/sliptree/bootstrap-tokenfield
|
* https://github.com/sliptree/bootstrap-tokenfield
|
||||||
* Copyright 2013-2014 Sliptree and other contributors; Licensed MIT
|
* Copyright 2013-2014 Sliptree and other contributors; Licensed MIT
|
||||||
*/@-webkit-keyframes 'blink'{0%{border-color:#ededed}100%{border-color:#b94a48}}@-moz-keyframes 'blink'{0%{border-color:#ededed}100%{border-color:#b94a48}}@keyframes 'blink'{0%{border-color:#ededed}100%{border-color:#b94a48}}.tokenfield{height:auto;min-height:34px;padding-bottom:0}.tokenfield.focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.tokenfield .token{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;display:inline-block;border:1px solid #d9d9d9;background-color:#ededed;white-space:nowrap;margin:-1px 5px 5px 0;height:22px;vertical-align:top;cursor:default}.tokenfield .token:hover{border-color:#b9b9b9}.tokenfield .token.active{border-color:#52a8ec;border-color:rgba(82,168,236,.8)}.tokenfield .token.duplicate{border-color:#ebccd1;-webkit-animation-name:blink;animation-name:blink;-webkit-animation-duration:.1s;animation-duration:.1s;-webkit-animation-direction:normal;animation-direction:normal;-webkit-animation-timing-function:ease;animation-timing-function:ease;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.tokenfield .token.invalid{background:0 0;border:1px solid transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;border-bottom:1px dotted #d9534f}.tokenfield .token.invalid.active{background:#ededed;border:1px solid #ededed;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.tokenfield .token .token-label{display:inline-block;overflow:hidden;text-overflow:ellipsis;padding-left:4px;vertical-align:top}.tokenfield .token .close{font-family:Arial;display:inline-block;line-height:100%;font-size:1.1em;line-height:1.49em;margin-left:5px;float:none;height:100%;vertical-align:top;padding-right:4px}.tokenfield .token-input{background:0 0;width:60px;min-width:60px;border:0;height:20px;padding:0;margin-bottom:6px;-webkit-box-shadow:none;box-shadow:none}.tokenfield .token-input:focus{border-color:transparent;outline:0;-webkit-box-shadow:none;box-shadow:none}.tokenfield.disabled{cursor:not-allowed;background-color:#eee}.tokenfield.disabled .token-input{cursor:not-allowed}.tokenfield.disabled .token:hover{cursor:not-allowed;border-color:#d9d9d9}.tokenfield.disabled .token:hover .close{cursor:not-allowed;opacity:.2;filter:alpha(opacity=20)}.has-warning .tokenfield.focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-error .tokenfield.focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-success .tokenfield.focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.tokenfield.input-sm,.input-group-sm .tokenfield{min-height:30px;padding-bottom:0}.input-group-sm .token,.tokenfield.input-sm .token{height:20px;margin-bottom:4px}.input-group-sm .token-input,.tokenfield.input-sm .token-input{height:18px;margin-bottom:5px}.tokenfield.input-lg,.input-group-lg .tokenfield{min-height:45px;padding-bottom:4px}.input-group-lg .token,.tokenfield.input-lg .token{height:25px}.input-group-lg .token-label,.tokenfield.input-lg .token-label{line-height:23px}.input-group-lg .token .close,.tokenfield.input-lg .token .close{line-height:1.3em}.input-group-lg .token-input,.tokenfield.input-lg .token-input{height:23px;line-height:23px;margin-bottom:6px;vertical-align:top}.tokenfield.rtl{direction:rtl;text-align:right}.tokenfield.rtl .token{margin:-1px 0 5px 5px}.tokenfield.rtl .token .token-label{padding-left:0;padding-right:4px}
|
*/@-webkit-keyframes blink{0%{border-color:#ededed}100%{border-color:#b94a48}}@-moz-keyframes blink{0%{border-color:#ededed}100%{border-color:#b94a48}}@keyframes blink{0%{border-color:#ededed}100%{border-color:#b94a48}}.tokenfield{height:auto;min-height:34px;padding-bottom:0}.tokenfield.focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.tokenfield .token{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;display:inline-block;border:1px solid #d9d9d9;background-color:#ededed;white-space:nowrap;margin:-1px 5px 5px 0;height:22px;vertical-align:top;cursor:default}.tokenfield .token:hover{border-color:#b9b9b9}.tokenfield .token.active{border-color:#52a8ec;border-color:rgba(82,168,236,.8)}.tokenfield .token.duplicate{border-color:#ebccd1;-webkit-animation-name:blink;animation-name:blink;-webkit-animation-duration:.1s;animation-duration:.1s;-webkit-animation-direction:normal;animation-direction:normal;-webkit-animation-timing-function:ease;animation-timing-function:ease;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.tokenfield .token.invalid{background:0 0;border:1px solid transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;border-bottom:1px dotted #d9534f}.tokenfield .token.invalid.active{background:#ededed;border:1px solid #ededed;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.tokenfield .token .token-label{display:inline-block;overflow:hidden;text-overflow:ellipsis;padding-left:4px;vertical-align:top}.tokenfield .token .close{font-family:Arial;display:inline-block;line-height:100%;font-size:1.1em;line-height:1.49em;margin-left:5px;float:none;height:100%;vertical-align:top;padding-right:4px}.tokenfield .token-input{background:0 0;width:60px;min-width:60px;border:0;height:20px;padding:0;margin-bottom:6px;-webkit-box-shadow:none;box-shadow:none}.tokenfield .token-input:focus{border-color:transparent;outline:0;-webkit-box-shadow:none;box-shadow:none}.tokenfield.disabled{cursor:not-allowed;background-color:#eee}.tokenfield.disabled .token-input{cursor:not-allowed}.tokenfield.disabled .token:hover{cursor:not-allowed;border-color:#d9d9d9}.tokenfield.disabled .token:hover .close{cursor:not-allowed;opacity:.2;filter:alpha(opacity=20)}.has-warning .tokenfield.focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-error .tokenfield.focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-success .tokenfield.focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.tokenfield.input-sm,.input-group-sm .tokenfield{min-height:30px;padding-bottom:0}.input-group-sm .token,.tokenfield.input-sm .token{height:20px;margin-bottom:4px}.input-group-sm .token-input,.tokenfield.input-sm .token-input{height:18px;margin-bottom:5px}.tokenfield.input-lg,.input-group-lg .tokenfield{height:auto;min-height:45px;padding-bottom:4px}.input-group-lg .token,.tokenfield.input-lg .token{height:25px}.input-group-lg .token-label,.tokenfield.input-lg .token-label{line-height:23px}.input-group-lg .token .close,.tokenfield.input-lg .token .close{line-height:1.3em}.input-group-lg .token-input,.tokenfield.input-lg .token-input{height:23px;line-height:23px;margin-bottom:6px;vertical-align:top}.tokenfield.rtl{direction:rtl;text-align:right}.tokenfield.rtl .token{margin:-1px 0 5px 5px}.tokenfield.rtl .token .token-label{padding-left:0;padding-right:4px}
|
4
assets/js/bootstrap-tokenfield.min.js
vendored
4
assets/js/bootstrap-tokenfield.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -52,11 +52,19 @@
|
|||||||
if (!valid) {
|
if (!valid) {
|
||||||
$(e.relatedTarget).addClass('invalid')
|
$(e.relatedTarget).addClass('invalid')
|
||||||
}
|
}
|
||||||
|
}).on('tokenfield:createtoken', function (e) {
|
||||||
|
var existingTokens = $(this).tokenfield('getTokens');
|
||||||
|
$.each(existingTokens, function(index, token) {
|
||||||
|
if (token.value === e.attrs.value)
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
}).tokenfield({
|
}).tokenfield({
|
||||||
autocomplete: {
|
autocomplete: {
|
||||||
source: [{{range $i, $u :=.Users}}{{$u.Email}},{{end}}],
|
source: [{{range $i, $u :=.Users}}{{if ne $i 0}},{{end}}'{{$u.Email}}'{{end}}],
|
||||||
delay: 100
|
delay: 100
|
||||||
},
|
},
|
||||||
|
inputType: 'email',
|
||||||
|
createTokensOnBlur: true,
|
||||||
showAutocompleteOnFocus: false
|
showAutocompleteOnFocus: false
|
||||||
})</script>
|
})</script>
|
||||||
</body>
|
</body>
|
||||||
|
@@ -82,6 +82,12 @@
|
|||||||
<input type="text" name="allowedip" class="form-control" id="server_AllowedIP" value="{{.Peer.AllowedIPsStr}}">
|
<input type="text" name="allowedip" class="form-control" id="server_AllowedIP" value="{{.Peer.AllowedIPsStr}}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group col-md-12">
|
||||||
|
<label for="server_AllowedIPSrv">Extra Allowed IPs (Server sided)</label>
|
||||||
|
<input type="text" name="allowedipSrv" class="form-control" id="server_AllowedIPSrv" value="{{.Peer.AllowedIPsSrvStr}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<div class="form-group col-md-12 global-config">
|
<div class="form-group col-md-12 global-config">
|
||||||
<label for="server_DNS">Client DNS Servers</label>
|
<label for="server_DNS">Client DNS Servers</label>
|
||||||
|
@@ -29,6 +29,13 @@ func init() {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
migrations = append(migrations, Migration{
|
||||||
|
version: "1.0.8",
|
||||||
|
migrateFn: func(db *gorm.DB) error {
|
||||||
|
logrus.Infof("upgraded database format to version 1.0.8")
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type SupportedDatabase string
|
type SupportedDatabase string
|
||||||
|
@@ -64,6 +64,7 @@ func (s *Server) PostAdminEditPeer(c *gin.Context) {
|
|||||||
// Clean list input
|
// Clean list input
|
||||||
formPeer.IPsStr = common.ListToString(common.ParseStringList(formPeer.IPsStr))
|
formPeer.IPsStr = common.ListToString(common.ParseStringList(formPeer.IPsStr))
|
||||||
formPeer.AllowedIPsStr = common.ListToString(common.ParseStringList(formPeer.AllowedIPsStr))
|
formPeer.AllowedIPsStr = common.ListToString(common.ParseStringList(formPeer.AllowedIPsStr))
|
||||||
|
formPeer.AllowedIPsSrvStr = common.ListToString(common.ParseStringList(formPeer.AllowedIPsSrvStr))
|
||||||
|
|
||||||
disabled := c.PostForm("isdisabled") != ""
|
disabled := c.PostForm("isdisabled") != ""
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
@@ -121,6 +122,7 @@ func (s *Server) PostAdminCreatePeer(c *gin.Context) {
|
|||||||
// Clean list input
|
// Clean list input
|
||||||
formPeer.IPsStr = common.ListToString(common.ParseStringList(formPeer.IPsStr))
|
formPeer.IPsStr = common.ListToString(common.ParseStringList(formPeer.IPsStr))
|
||||||
formPeer.AllowedIPsStr = common.ListToString(common.ParseStringList(formPeer.AllowedIPsStr))
|
formPeer.AllowedIPsStr = common.ListToString(common.ParseStringList(formPeer.AllowedIPsStr))
|
||||||
|
formPeer.AllowedIPsSrvStr = common.ListToString(common.ParseStringList(formPeer.AllowedIPsSrvStr))
|
||||||
|
|
||||||
disabled := c.PostForm("isdisabled") != ""
|
disabled := c.PostForm("isdisabled") != ""
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
@@ -309,6 +309,11 @@ func (s *Server) DeleteUser(user users.User) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) CreateUserDefaultPeer(email, device string) error {
|
func (s *Server) CreateUserDefaultPeer(email, device string) error {
|
||||||
|
// Check if automatic peer creation is enabled
|
||||||
|
if !s.config.Core.CreateDefaultPeer {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Check if user is active, if not, quit
|
// Check if user is active, if not, quit
|
||||||
var existingUser *users.User
|
var existingUser *users.User
|
||||||
if existingUser = s.users.GetUser(email); existingUser == nil {
|
if existingUser = s.users.GetUser(email); existingUser == nil {
|
||||||
@@ -316,18 +321,26 @@ func (s *Server) CreateUserDefaultPeer(email, device string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if user already has a peer setup, if not, create one
|
// Check if user already has a peer setup, if not, create one
|
||||||
if s.config.Core.CreateDefaultPeer {
|
peers := s.peers.GetPeersByMail(email)
|
||||||
peers := s.peers.GetPeersByMail(email)
|
if len(peers) != 0 {
|
||||||
if len(peers) == 0 { // Create default vpn peer
|
return nil
|
||||||
if err := s.CreatePeer(device, wireguard.Peer{
|
}
|
||||||
Identifier: existingUser.Firstname + " " + existingUser.Lastname + " (Default)",
|
|
||||||
Email: existingUser.Email,
|
// Create default vpn peer
|
||||||
CreatedBy: existingUser.Email,
|
peer, err := s.PrepareNewPeer(device)
|
||||||
UpdatedBy: existingUser.Email,
|
if err != nil {
|
||||||
}); err != nil {
|
return errors.WithMessage(err, "failed to prepare new peer")
|
||||||
return errors.WithMessagef(err, "failed to automatically create vpn peer for %s", email)
|
}
|
||||||
}
|
peer.Email = email
|
||||||
}
|
if existingUser.Firstname != "" && existingUser.Lastname != "" {
|
||||||
|
peer.Identifier = fmt.Sprintf("%s %s (%s)", existingUser.Firstname, existingUser.Lastname, "Default")
|
||||||
|
} else {
|
||||||
|
peer.Identifier = fmt.Sprintf("%s (%s)", existingUser.Email, "Default")
|
||||||
|
}
|
||||||
|
peer.CreatedBy = existingUser.Email
|
||||||
|
peer.UpdatedBy = existingUser.Email
|
||||||
|
if err := s.CreatePeer(device, peer); err != nil {
|
||||||
|
return errors.WithMessagef(err, "failed to automatically create vpn peer for %s", email)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
var Version = "testbuild"
|
var Version = "testbuild"
|
||||||
var DatabaseVersion = "1.0.7"
|
var DatabaseVersion = "1.0.8"
|
||||||
|
@@ -63,8 +63,7 @@ func init() {
|
|||||||
//
|
//
|
||||||
|
|
||||||
type Peer struct {
|
type Peer struct {
|
||||||
Peer *wgtypes.Peer `gorm:"-" json:"-"` // WireGuard peer
|
Peer *wgtypes.Peer `gorm:"-" json:"-"` // WireGuard peer
|
||||||
Device *Device `gorm:"foreignKey:DeviceName" binding:"-" json:"-"` // linked WireGuard device
|
|
||||||
Config string `gorm:"-" json:"-"`
|
Config string `gorm:"-" json:"-"`
|
||||||
|
|
||||||
UID string `form:"uid" binding:"required,alphanum" json:"-"` // uid for html identification
|
UID string `form:"uid" binding:"required,alphanum" json:"-"` // uid for html identification
|
||||||
@@ -82,7 +81,8 @@ type Peer struct {
|
|||||||
// Core WireGuard Settings
|
// Core WireGuard Settings
|
||||||
PublicKey string `gorm:"primaryKey" form:"pubkey" binding:"required,base64"` // the public key of the peer itself
|
PublicKey string `gorm:"primaryKey" form:"pubkey" binding:"required,base64"` // the public key of the peer itself
|
||||||
PresharedKey string `form:"presharedkey" binding:"omitempty,base64"`
|
PresharedKey string `form:"presharedkey" binding:"omitempty,base64"`
|
||||||
AllowedIPsStr string `form:"allowedip" binding:"cidrlist"` // a comma separated list of IPs that are used in the client config file
|
AllowedIPsStr string `form:"allowedip" binding:"cidrlist"` // a comma separated list of IPs that are used in the client config file
|
||||||
|
AllowedIPsSrvStr string `form:"allowedipSrv" binding:"cidrlist"` // a comma separated list of IPs that are used in the server config file
|
||||||
Endpoint string `form:"endpoint" binding:"omitempty,hostname_port"`
|
Endpoint string `form:"endpoint" binding:"omitempty,hostname_port"`
|
||||||
PersistentKeepalive int `form:"keepalive" binding:"gte=0"`
|
PersistentKeepalive int `form:"keepalive" binding:"gte=0"`
|
||||||
|
|
||||||
@@ -124,6 +124,10 @@ func (p Peer) GetAllowedIPs() []string {
|
|||||||
return common.ParseStringList(p.AllowedIPsStr)
|
return common.ParseStringList(p.AllowedIPsStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p Peer) GetAllowedIPsSrv() []string {
|
||||||
|
return common.ParseStringList(p.AllowedIPsSrvStr)
|
||||||
|
}
|
||||||
|
|
||||||
func (p Peer) GetConfig(dev *Device) wgtypes.PeerConfig {
|
func (p Peer) GetConfig(dev *Device) wgtypes.PeerConfig {
|
||||||
publicKey, _ := wgtypes.ParseKey(p.PublicKey)
|
publicKey, _ := wgtypes.ParseKey(p.PublicKey)
|
||||||
|
|
||||||
@@ -154,6 +158,7 @@ func (p Peer) GetConfig(dev *Device) wgtypes.PeerConfig {
|
|||||||
peerAllowedIPs = p.GetAllowedIPs()
|
peerAllowedIPs = p.GetAllowedIPs()
|
||||||
case DeviceTypeServer:
|
case DeviceTypeServer:
|
||||||
peerAllowedIPs = p.GetIPAddresses()
|
peerAllowedIPs = p.GetIPAddresses()
|
||||||
|
peerAllowedIPs = append(peerAllowedIPs, p.GetAllowedIPsSrv()...)
|
||||||
}
|
}
|
||||||
for _, ip := range peerAllowedIPs {
|
for _, ip := range peerAllowedIPs {
|
||||||
_, ipNet, err := net.ParseCIDR(ip)
|
_, ipNet, err := net.ParseCIDR(ip)
|
||||||
@@ -236,6 +241,7 @@ const (
|
|||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
Interface *wgtypes.Device `gorm:"-" json:"-"`
|
Interface *wgtypes.Device `gorm:"-" json:"-"`
|
||||||
|
Peers []Peer `gorm:"foreignKey:DeviceName" binding:"-" json:"-"` // linked WireGuard peers
|
||||||
|
|
||||||
Type DeviceType `form:"devicetype" binding:"required,oneof=client server"`
|
Type DeviceType `form:"devicetype" binding:"required,oneof=client server"`
|
||||||
DeviceName string `form:"device" gorm:"primaryKey" binding:"required,alphanum"`
|
DeviceName string `form:"device" gorm:"primaryKey" binding:"required,alphanum"`
|
||||||
@@ -375,7 +381,7 @@ func NewPeerManager(db *gorm.DB, wg *Manager) (*PeerManager, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pm.db.AutoMigrate(&Peer{}, &Device{}); err != nil {
|
if err := pm.db.AutoMigrate(&Device{}, &Peer{}); err != nil {
|
||||||
return nil, errors.WithMessage(err, "failed to migrate peer database")
|
return nil, errors.WithMessage(err, "failed to migrate peer database")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -61,7 +61,7 @@ PublicKey = {{ .PublicKey }}
|
|||||||
PresharedKey = {{ .PresharedKey }}
|
PresharedKey = {{ .PresharedKey }}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
{{- if eq $.Interface.Type "server"}}
|
{{- if eq $.Interface.Type "server"}}
|
||||||
AllowedIPs = {{ .IPsStr }}
|
AllowedIPs = {{ .IPsStr }}{{if ne .AllowedIPsSrvStr ""}}, {{ .AllowedIPsSrvStr }}{{end}}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
{{- if eq $.Interface.Type "client"}}
|
{{- if eq $.Interface.Type "client"}}
|
||||||
{{- if .AllowedIPsStr}}
|
{{- if .AllowedIPsStr}}
|
||||||
|
Reference in New Issue
Block a user