Browse Source

Merge pull request #88 from perara/master

Update obfs branch
pull/89/head
Per-Arne Andersen 4 years ago
committed by GitHub
parent
commit
9c363b279f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 25
      .github/workflows/image.yml
  2. 16
      .travis.yml
  3. 53
      Dockerfile
  4. 11
      README.md
  5. 16
      back/test.py
  6. 1
      docker-compose.yaml
  7. 5
      docker/push.sh
  8. 113
      docs/install.md
  9. 59
      docs/install_docker_github.md
  10. 17
      scripts/ci.sh
  11. 2
      wg_dashboard_backend/const.py
  12. 4
      wg_dashboard_backend/db/api_key.py
  13. 7
      wg_dashboard_backend/main.py
  14. 2
      wg_dashboard_backend/migrations/versions/006_create_v6_subnet.py
  15. 21
      wg_dashboard_backend/migrations/versions/008_create_allowed_ips.py
  16. 21
      wg_dashboard_backend/migrations/versions/009_create_keep_alive.py
  17. 21
      wg_dashboard_backend/migrations/versions/010_create_keep_alive_peer.py
  18. 20
      wg_dashboard_backend/migrations/versions/011_alter_server_ipv6_subnet_nullable.py
  19. 3
      wg_dashboard_backend/models.py
  20. 2
      wg_dashboard_backend/requirements.txt
  21. 4
      wg_dashboard_backend/routers/v1/peer.py
  22. 3
      wg_dashboard_backend/schemas.py
  23. 7
      wg_dashboard_backend/script/wireguard.py
  24. 7
      wg_dashboard_backend/templates/peer.j2
  25. 4
      wg_dashboard_backend/templates/server.j2
  26. 13
      wg_dashboard_frontend/angular.json
  27. 31382
      wg_dashboard_frontend/package-lock.json
  28. 90
      wg_dashboard_frontend/package.json
  29. 2
      wg_dashboard_frontend/src/app/app-routing.module.ts
  30. 1
      wg_dashboard_frontend/src/app/interfaces/peer.ts
  31. 19
      wg_dashboard_frontend/src/app/page/dashboard/add-server/add-server.component.html
  32. 11
      wg_dashboard_frontend/src/app/page/dashboard/add-server/add-server.component.ts
  33. 7
      wg_dashboard_frontend/src/app/page/dashboard/peer/peer.component.html
  34. 18
      wg_dashboard_frontend/src/app/validators/ip-address.validator.ts
  35. 5
      wg_dashboard_frontend/src/theme/styles.scss
  36. 2
      wg_dashboard_frontend/tsconfig.json
  37. 3
      wg_dashboard_frontend/tslint.json

25
.github/workflows/image.yml

@ -0,0 +1,25 @@
name: build wg-dashboard
on:
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: checkout code
uses: actions/checkout@v2
- name: install buildx
id: buildx
uses: crazy-max/ghaction-docker-buildx@v1
with:
version: latest
- name: login to docker hub
run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
- name: build the image
run: |
docker buildx build --push \
--tag perara/wg-manager:latest \
--platform linux/amd64 .

16
.travis.yml

@ -0,0 +1,16 @@
dist: focal
os: linux
language: python
env:
global:
- DOCKER_REPO=perara/wg-manager
before_install:
- curl -fsSL https://get.docker.com | sh
- echo '{"experimental":"enabled"}' | sudo tee /etc/docker/daemon.json
- mkdir -p $HOME/.docker
- echo '{"experimental":"enabled"}' | sudo tee $HOME/.docker/config.json
- sudo service docker start
install:
- docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- docker buildx create --name xbuilder --use
script: bash scripts/ci.sh

53
Dockerfile

@ -1,25 +1,54 @@
FROM node
FROM ubuntu:20.04
ENV TZ=Europe/Minsk
ENV DEBIAN_FRONTEND=noninteractive
COPY ./wg_dashboard_frontend /tmp/build
WORKDIR /tmp/build
RUN npm install && npm install -g @angular/cli
RUN ng build --configuration="production"
RUN apt-get update && apt-get install -y \
nodejs \
npm \
&& rm -rf /var/lib/apt/lists/*
FROM alpine:latest
MAINTAINER per@sysx.no
RUN npm cache clean --force
RUN npm install
RUN npm install @angular/cli
RUN node_modules/@angular/cli/bin/ng build --configuration="production"
RUN rm -rf node_modules
RUN apt-get purge nodejs npm -y
FROM ubuntu:20.04
LABEL maintainer="per@sysx.no"
ENV IS_DOCKER True
WORKDIR /app
# Install dependencies
RUN apk add --no-cache --update wireguard-tools py3-gunicorn python3 py3-pip ip6tables
ENV LIBRARY_PATH=/lib:/usr/lib
ENV TZ=Europe/Oslo
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
COPY wg_dashboard_backend /app
# Install dependencies
RUN apk add --no-cache build-base python3-dev libffi-dev && \
pip3 install uvicorn && \
pip3 install -r requirements.txt && \
apk del build-base python3-dev libffi-dev
#RUN apk add --no-cache --update wireguard-tools py3-gunicorn python3 py3-pip ip6tables
RUN apt-get update && apt-get install -y \
wireguard-tools \
iptables \
iproute2 \
python3 \
python3-pip \
python3-dev \
python3-gunicorn \
python3-uvicorn \
gunicorn \
&& rm -rf /var/lib/apt/lists/*
RUN pip3 install -r requirements.txt
# Install dependencies
#RUN apk add --no-cache build-base python3-dev libffi-dev jpeg-dev zlib-dev && \
#pip3 install uvicorn && \
#pip3 install -r requirements.txt && \
#apk del build-base python3-dev libffi-dev jpeg-dev zlib-dev
# Copy startup scripts
COPY docker/ ./startup

11
README.md

@ -23,7 +23,7 @@ The features of wg-manager includes:
* Create and manage API-Keys
# Dependencies
* Linux >= 5.6 *(Alternatively: wireguard-dkms)*
* Linux Kernel >= 5.6 *(Alternatively: wireguard-dkms)*
# Common Installation Steps
1. Enable ip forwarding:
@ -41,7 +41,7 @@ The features of wg-manager includes:
3. It is recommended to have a firewall protecting your servers
## Notes
* A few people has experienced issues with running the dockerized method using bridged networking. To fix this, you can use `network_mode: host`. Note that you can no longer reverse-proxy the web interface from reverse proxies such as [jwilder/nginx-proxy](https://hub.docker.com/r/jwilder/nginx-proxy/).
* A few people has experienced issues with running the dockerized method using bridged networking. To workaround this, you can use `network_mode: host`. Note that you can no longer reverse-proxy the web interface from reverse proxies such as [jwilder/nginx-proxy](https://hub.docker.com/r/jwilder/nginx-proxy/).
## Method #1: Docker-compose
```yaml
@ -69,8 +69,9 @@ services:
WEB_CONCURRENCY: 1
```
or [plain docker here](./docs/guides/docker_configuration.md)
or [build docker image from github](./docs/install_docker_github.md)
# Method #2: Bare Metal
## Method #2: Bare Metal
- [Installation on Debian/Ubuntu/RPI4](./docs/install.md)
# Using the development branch
@ -198,6 +199,10 @@ networks:
| CLIENT_X_SERVER_INTERFACE | The wg-interface to create client on e.g"wg0". See docs | string |
| CLIENT_X_API_KEY | A valid API-Key that is active on the server. Works well with SERVER_STARTUP_API_KEY | string |
# Q&A
I'm trying to start the device but recieve the message: `Perhaps ip6tables or your kernel needs to be upgraded.`.
Try: `modprobe ip6table_nat` on the host.
# Showcase
![Illustration](docs/images/0.png)

16
back/test.py

@ -0,0 +1,16 @@
import requests
if __name__ == "__main__":
sess = requests.Session()
resp = sess.post("http://localhost:8888/api/v1/login", data={
"username": "admin",
"password": "admin"
})
print(resp.json())
sess.headers.update({
"Authorization": f"Bearer {resp.json()['access_token']}"
})
for _ in range(20):
print(sess.get("http://localhost:8888/api/v1/wg/generate_psk").json())

1
docker-compose.yaml

@ -50,6 +50,7 @@ services:
CLIENT: 1 # If you want to connect to servers
CLIENT_START_AUTOMATICALLY: 1 # If you want the client to start automatically
CLIENT_1_NAME: "client-1" # Name of first client
CLIENT_1_ROUTES: "10.0.200.0/24"
CLIENT_1_SERVER_HOST: "http://server:8888" # Endpoint of first server
CLIENT_1_SERVER_INTERFACE: "wg0" # Interface of first server (to get config)
CLIENT_1_API_KEY: "thisisasecretkeythatnobodyknows" # API-Key of first server (to get config)

5
docker/push.sh

@ -1,5 +1,6 @@
#!/usr/bin/env bash
cd ..
docker login
docker build -t perara/wg-manager .
docker push perara/wg-manager
docker build -t perara/wg-manager:dev .
docker push perara/wg-manager:dev

113
docs/install.md

@ -1,31 +1,56 @@
# Installation for raspberry-pi 4
These instructions are untested, and should be verified by someone. Please create a ticket :)
# Installation for Linux (Ubuntu, Debian, Raspberry Pi)
These instructions are tested working on:\
:heavy_check_mark: Ubuntu 20.04\
:heavy_check_mark: Ubuntu 18.04\
:x: Ubuntu 16.04 (fails when starting the http server `uvicorn main:app --host=0.0.0.0`)\
:heavy_check_mark: Debian 10\
:x: Debian 9
  (fails at `pip install -r requirements.txt` error: `Could not find a version that satisfies the requirement fastapi (from -r requirements.txt (line 2)) (from versions: `)
## 1. Setup required environment variables
```
export <ENV> <VALUE>
export <ENV>=<VALUE>
```
You will need the following:
```
export ADMIN_USERNAME=admin
export ADMIN_PASSWORD=admin
```
Make it permanent with putting it in bashrc
Refer to the list in the main readme file.
## 2. Install Depedencies
### Python
```
sudo apt-get update && sudo apt-get install git python3 python3-pip python3-venv -y
```
### Node.JS
### Node.JS: Ubuntu
```
curl -sL https://deb.nodesource.com/setup_13.x | sudo bash -
sudo apt-get install -y nodejs
```
### Node.JS: Debian
```
sudo apt install curl
curl -sL https://deb.nodesource.com/setup_13.x | sudo bash -
sudo apt-get install -y nodejs
```
### WireGuard: Ubuntu
#### 18.04 and later
```
sudo apt update
sudo apt install wireguard wireguard-tools -y
```
#### 16.04 and earlier
```
sudo add-apt-repository ppa:wireguard/wireguard -y
sudo apt install wireguard wireguard-tools -y
```
### WireGuard: Debian/RPI
### WireGuard: Debian 10/Raspberry Pi (with Raspbian 10)
```
# Get signing keys to verify the new packages, otherwise they will not install
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 04EE7237B7D453EC 648ACFD622F3D138
@ -37,14 +62,26 @@ sudo apt update
sudo apt install wireguard wireguard-tools -y
```
### WireGuard: Debian 9/Raspberry Pi (with Raspbian 9)
```
# Get signing keys to verify the new packages, otherwise they will not install
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 04EE7237B7D453EC 648ACFD622F3D138
echo "deb http://deb.debian.org/debian/ unstable main" | sudo tee -a /etc/apt/sources.list.d/unstable.list
sudo apt update
sudo apt install wireguard wireguard-tools -y
```
## 3. Building front-end
```
# Building frontend
sudo git clone https://github.com/perara/wg-manager.git /opt/wg-manager
cd /opt/wg-manager/wg_dashboard_frontend
sudo npm install > /dev/null && sudo npm install @angular/cli > /dev/null
sudo node_modules/@angular/cli/bin/ng build --configuration="production" > /dev/null
sudo node_modules/@angular/cli/bin/ng build --configuration="production"
```
One thing to be aware of is that when issuing the `sudo node_modules/@angular/cli/bin/ng build --configuration="production"` command, if you do not have enough memory on your server, the process will get "Killed". This happens when trying to compile on the lowest tier DIgital Ocean droplet. To get around this you can either add more memory or create a swap file. Here is a great guide on [creating a swap file](https://linuxize.com/post/create-a-linux-swap-file/).
## 4. Setup back-end
```
@ -64,10 +101,68 @@ You should now see the following
#INFO: Application startup complete.
#INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
```
## 6. Default routing not working?
## 6. Troubleshooting tips
### Default routing not working?
Try these.
PostUp `iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i %i -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE`
PostDown `iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i %i -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE`
### Debain 10 wg0 won't start
When you try to start wg0 from the web interface, you may see on your terminal session:
`RNETLINK answers: Operation not supported. Unable to access interface: Protocol not supported`
This can sometimes be fixed with ```sudo apt upgrade```
To fix this, we need to reconfigure the Kernel module. In some cases, the following commands will fix your issue:
```
dpkg-reconfigure wireguard-dkms
modprobe wireguard
```
You may get an error on the first command
```
Module build for kernel 4.19.0-10-cloud-amd64 was skipped since the
kernel headers for this kernel does not seem to be installed.
```
We'll need to install the Kernel headers.
Find out which Kernel we are already on
```
uname -r
```
Search if your Kernel headers are in the repositories.
```
apt search linux-headers-$(uname -r)
```
If so then install them:
```
apt install linux-headers-$(uname -r)
```
If not, we'll need to upgrade your Kernel. My Kernel was 4.19.0.10 so I did a search for 4.19.0 and found 4.19.0.11. This will be a minnor release so nothing to be too worried about.
```
apt search linux-headers-*
```
Install the new Kernel and Reboot
```
apt install linux-image-4.19.0-11-cloud-amd64
reboot
```
Install the headers for your Kernel
```
apt install linux-headers-4.19.0-11-cloud-amd64
```
Reconfigure your dkms module and load it.
```
dpkg-reconfigure wireguard-dkms
modprobe wireguard
```

59
docs/install_docker_github.md

@ -0,0 +1,59 @@
# Build Docker Image from Github Repo
The steps below will walk you through installing the application in a docker container from the latest github version.
---
First thing we need to do is clone the github repository
```bash
git clone https://github.com/perara/wg-manager.git
```
Next we need to build the image. This will take some time.
```bash
docker build -t wg-manager .
```
Now that our image is built, we can either launch the container via _docker-compose_ or through the _docker CLI_.
## Docker Compose
```yaml
version: "2.1"
services:
wireguard:
container_name: wg-manager
image: wg-manager
restart: always
sysctls:
net.ipv6.conf.all.disable_ipv6: 0 # Required for IPV6
cap_add:
- NET_ADMIN
network_mode: host
ports:
- 51802:51802/udp
- 8888:8888
volumes:
- ./wg-manager:/config
environment:
HOST: 0.0.0.0
PORT: 8888
ADMIN_USERNAME: admin
ADMIN_PASSWORD: admin
WEB_CONCURRENCY: 1
```
## Docker CLI
```bash
docker run -d \
--sysctl net.ipv6.conf.all.disable_ipv6=0 \
--cap-add NET_ADMIN \
--name wg-manager \
--net host \
-p "51802:51802/udp" \
-p "8888:8888" \
-v wg-manager:/config \
-e HOST="0.0.0.0" \
-e PORT="8888" \
-e ADMIN_USERNAME="admin" \
-e ADMIN_PASSWORD="admin" \
wg-manager
```

17
scripts/ci.sh

@ -0,0 +1,17 @@
#!/bin/bash
if [ "$TRAVIS_PULL_REQUEST" = "true" ] || [ "$TRAVIS_BRANCH" != "master" ]; then
docker buildx build \
--progress plain \
--platform=linux/amd64,linux/arm64/v8,linux/arm64,linux/arm/v7,linux/arm/v6 \
.
exit $?
fi
echo $DOCKER_PASSWORD | docker login -u qmcgaw --password-stdin &> /dev/null
TAG="${TRAVIS_TAG:-latest}"
docker buildx build \
--progress plain \
--platform=linux/amd64,linux/arm64/v8,linux/arm64,linux/arm/v7,linux/arm/v6 \
-t $DOCKER_REPO:$TAG \
--push \
.

2
wg_dashboard_backend/const.py

@ -43,8 +43,6 @@ else:
DEFAULT_CONFIG_DIR = "/config"
os.makedirs(DEFAULT_CONFIG_DIR, exist_ok=True)
PEER_DEFAULT_ALLOWED_IPS = ["0.0.0.0/0", "::/0"]
ENV_CONFIG_DIR = os.getenv("ENV_CONFIG_DIR", DEFAULT_CONFIG_DIR)
os.makedirs(ENV_CONFIG_DIR, exist_ok=True)

4
wg_dashboard_backend/db/api_key.py

@ -3,10 +3,10 @@ from sqlalchemy.orm import Session
import models
def add_initial_api_key_for_admin(sess: Session, api_key):
def add_initial_api_key_for_admin(sess: Session, api_key, ADMIN_USERNAME):
db_user = sess.query(models.User)\
.filter_by(username="admin")\
.filter_by(username=ADMIN_USERNAME)\
.one()
exists_api_key = sess.query(models.UserAPIKey)\

7
wg_dashboard_backend/main.py

@ -44,12 +44,12 @@ _db: Session = SessionLocal()
if not database_exists(engine.url):
ADMIN_USERNAME = os.getenv("ADMIN_USERNAME")
if not ADMIN_USERNAME:
raise RuntimeError("Database does not exist and the environment variable ADMIN_USERNAME is set")
raise RuntimeError("Database does not exist and the environment variable ADMIN_USERNAME is not set")
ADMIN_PASSWORD = os.getenv("ADMIN_PASSWORD")
if not ADMIN_PASSWORD:
raise RuntimeError("Database does not exist and the environment variable ADMIN_PASSWORD is set")
raise RuntimeError("Database does not exist and the environment variable ADMIN_PASSWORD is not set")
# Create database from metadata
models.Base.metadata.create_all(engine)
@ -89,7 +89,8 @@ if const.SERVER_INIT_INTERFACE is not None:
db.wireguard.server_add_on_init(_db)
if const.SERVER_STARTUP_API_KEY is not None:
db.api_key.add_initial_api_key_for_admin(_db, const.SERVER_STARTUP_API_KEY)
ADMIN_USERNAME = os.getenv("ADMIN_USERNAME")
db.api_key.add_initial_api_key_for_admin(_db, const.SERVER_STARTUP_API_KEY, ADMIN_USERNAME)
_db.close()

2
wg_dashboard_backend/migrations/versions/006_create_v6_subnet.py

@ -6,7 +6,7 @@ def upgrade(migrate_engine):
try:
meta = MetaData(bind=migrate_engine)
peer = Table('server', meta, autoload=True)
v6_subnet = Column('v6_subnet', INTEGER)
v6_subnet = Column('v6_subnet', INTEGER, nullable=True)
v6_subnet.create(peer)
except:
pass

21
wg_dashboard_backend/migrations/versions/008_create_allowed_ips.py

@ -0,0 +1,21 @@
from sqlalchemy import *
from migrate import *
def upgrade(migrate_engine):
try:
meta = MetaData(bind=migrate_engine)
server = Table('server', meta, autoload=True)
allowed_ips = Column('allowed_ips', Text)
allowed_ips.create(server)
except:
pass
def downgrade(migrate_engine):
try:
meta = MetaData(bind=migrate_engine)
server = Table('server', meta, autoload=True)
server.c.allowed_ips.drop()
except:
pass

21
wg_dashboard_backend/migrations/versions/009_create_keep_alive.py

@ -0,0 +1,21 @@
from sqlalchemy import *
from migrate import *
def upgrade(migrate_engine):
try:
meta = MetaData(bind=migrate_engine)
server = Table('server', meta, autoload=True)
keep_alive = Column('keep_alive', Integer)
keep_alive.create(server)
except:
pass
def downgrade(migrate_engine):
try:
meta = MetaData(bind=migrate_engine)
server = Table('server', meta, autoload=True)
server.c.keep_alive.drop()
except:
pass

21
wg_dashboard_backend/migrations/versions/010_create_keep_alive_peer.py

@ -0,0 +1,21 @@
from sqlalchemy import *
from migrate import *
def upgrade(migrate_engine):
try:
meta = MetaData(bind=migrate_engine)
peer = Table('peer', meta, autoload=True)
keep_alive = Column('keep_alive', Integer)
keep_alive.create(peer)
except:
pass
def downgrade(migrate_engine):
try:
meta = MetaData(bind=migrate_engine)
peer = Table('peer', meta, autoload=True)
peer.c.keep_alive.drop()
except:
pass

20
wg_dashboard_backend/migrations/versions/011_alter_server_ipv6_subnet_nullable.py

@ -0,0 +1,20 @@
from sqlalchemy import *
from migrate import *
def upgrade(migrate_engine):
try:
meta = MetaData(bind=migrate_engine)
server = Table('server', meta, autoload=True)
server.c.v6_subnet.alter(nullable=True)
except:
pass
def downgrade(migrate_engine):
try:
meta = MetaData(bind=migrate_engine)
server = Table('server', meta, autoload=True)
server.c.v6_subnet.alter(nullable=False)
except:
pass

3
wg_dashboard_backend/models.py

@ -41,6 +41,8 @@ class WGServer(Base):
public_key = Column(sqlalchemy.String)
endpoint = Column(sqlalchemy.String)
dns = Column(sqlalchemy.String)
allowed_ips = Column(sqlalchemy.String)
keep_alive = Column(sqlalchemy.Integer, default=0)
read_only = Column(sqlalchemy.Integer, default=0)
post_up = Column(sqlalchemy.String)
@ -63,6 +65,7 @@ class WGPeer(Base):
shared_key = Column(sqlalchemy.Text)
dns = Column(sqlalchemy.Text)
allowed_ips = Column(sqlalchemy.String)
keep_alive = Column(sqlalchemy.Integer, default=0)
read_only = Column(sqlalchemy.Integer, default=0)
server_id = Column(Integer, sqlalchemy.ForeignKey('server.id', ondelete="CASCADE", onupdate="CASCADE"))

2
wg_dashboard_backend/requirements.txt

@ -13,4 +13,6 @@ sqlalchemy_utils
sqlalchemy-migrate
requests
uvicorn
uvloop
httptools
qrcode[pil]

4
wg_dashboard_backend/routers/v1/peer.py

@ -64,8 +64,8 @@ def add_peer(
peer.private_key = keys["private_key"]
peer.public_key = keys["public_key"]
# Set 0.0.0.0/0, ::/0 as default allowed ips
peer.allowed_ips = ', '.join(const.PEER_DEFAULT_ALLOWED_IPS)
peer.allowed_ips = server.allowed_ips
peer.keep_alive = server.keep_alive
# Set unnamed
peer.name = "Unnamed" if not peer_add.name else peer_add.name

3
wg_dashboard_backend/schemas.py

@ -132,6 +132,7 @@ class WGPeer(GenericModel):
server_id: str
dns: str = None
allowed_ips: str = None
keep_alive: int = None
configuration: str = None
class Meta:
@ -169,6 +170,8 @@ class WGServer(GenericModel):
post_up: str = None
post_down: str = None
dns: str = None
allowed_ips: str = None
keep_alive: int = None
read_only: int = None
peers: pydantic.typing.List['WGPeer'] = []

7
wg_dashboard_backend/script/wireguard.py

@ -259,7 +259,7 @@ def retrieve_client_conf_from_server(
return response.text
def create_client_config(sess: Session, configuration, client_name):
def create_client_config(sess: Session, configuration, client_name, client_routes):
parser = configparser.ConfigParser()
parser.read_string(configuration)
@ -332,7 +332,7 @@ def create_client_config(sess: Session, configuration, client_name):
db_peer.private_key = parser["Interface"]["PrivateKey"]
db_peer.public_key = "N/A"
db_peer.allowed_ips = parser["Peer"]["AllowedIPs"]
db_peer.allowed_ips = client_routes if client_routes else parser["Peer"]["AllowedIPs"]
db_peer.configuration = configuration
db_server.interface = f"client_{db_peer.name}"
db_server.configuration = configuration
@ -368,6 +368,7 @@ def load_environment_clients(sess: Session):
client_server_interface = os.getenv(f"CLIENT_{i}_SERVER_INTERFACE", None)
client_server_host = os.getenv(f"CLIENT_{i}_SERVER_HOST", None)
client_api_key = os.getenv(f"CLIENT_{i}_API_KEY", None)
client_routes = os.getenv(f"CLIENT_{i}_ROUTES", None)
if client_api_key is None or \
client_server_interface is None or \
@ -385,7 +386,7 @@ def load_environment_clients(sess: Session):
server_api_key=client_api_key
)
create_client_config(sess, configuration=config, client_name=client_name)
create_client_config(sess, configuration=config, client_name=client_name, client_routes=client_routes)
i += 1

7
wg_dashboard_backend/templates/peer.j2

@ -1,12 +1,13 @@
[Interface]
Address = {{ data.peer.address }}/{{ data.server.subnet }}{%- if is_ipv6 -%},{{ data.peer.v6_address }}/{{ data.server.v6_subnet }}{%- endif %}
PrivateKey = {{ data.peer.private_key }}
{% if data.peer.dns %}
DNS = {{ data.peer.dns }}
{% endif %}
[Peer]
PublicKey = {{ data.server.public_key }}
AllowedIPs = {{ data.peer.allowed_ips }}
Endpoint = {{ data.server.endpoint }}:{{ data.server.listen_port }}
{% if data.peer.shared_key %}
PresharedKey = {{ data.peer.shared_key }}
{% endif %}
{% if data.peer.shared_key %}PresharedKey = {{ data.peer.shared_key }}{% endif %}
{% if data.peer.keep_alive %}PersistentKeepalive = {{data.peer.keep_alive}}{% endif %}

4
wg_dashboard_backend/templates/server.j2

@ -3,8 +3,12 @@ Address = {{ data.address }}/{{ data.subnet }}{%- if is_ipv6 -%},{{ data.v6_addr
ListenPort = {{ data.listen_port }}
PrivateKey = {{ data.private_key }}
{% if data.post_up or data.v6_post_up %}
PostUp = {{ data.post_up }}{%- if is_ipv6 -%} {{ data.v6_post_up }}{%- endif %}
{%- endif %}
{% if data.post_down or data.v6_post_down %}
PostDown = {{ data.post_down }}{%- if is_ipv6 -%} {{ data.v6_post_down }}{%- endif %}
{%- endif %}
{% for peer in data.peers %}
[Peer]

13
wg_dashboard_frontend/angular.json

@ -3,7 +3,7 @@
"version": 1,
"newProjectRoot": "projects",
"projects": {
"material-angular-dashboard": {
"wg-manager": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
@ -38,7 +38,6 @@
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
@ -56,19 +55,19 @@
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "material-angular-dashboard:build",
"browserTarget": "wg-manager:build",
"proxyConfig": "proxy.conf.json"
},
"configurations": {
"production": {
"browserTarget": "material-angular-dashboard:build:production"
"browserTarget": "wg-manager:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "material-angular-dashboard:build"
"browserTarget": "wg-manager:build"
}
},
"lint": {
@ -84,13 +83,13 @@
}
}
},
"material-angular-dashboard-e2e": {
"wg-manager-e2e": {
"root": "",
"sourceRoot": "",
"projectType": "application"
}
},
"defaultProject": "material-angular-dashboard",
"defaultProject": "wg-manager",
"cli": {
"packageManager": "yarn"
},

31382
wg_dashboard_frontend/package-lock.json

File diff suppressed because it is too large

90
wg_dashboard_frontend/package.json

@ -16,71 +16,73 @@
"tlint:fix": "ng lint --fix",
"slint": "stylelint --syntax scss ./**/*.scss",
"slint:fix": "stylelint --syntax scss --fix ./**/*.scss",
"lint": "ng lint && stylelint --syntax scss ./**/*.scss"
"lint": "ng lint && stylelint --syntax scss ./**/*.scss",
"postinstall": "ngcc"
},
"pre-commit": "lint",
"private": true,
"private": false,
"repository": {
"type": "git",
"url": "https://github.com/CreativeIT/material-angular-dashboard"
"url": "https://github.com/perara/wg-manager"
},
"bugs": {
"url": "https://github.com/CreativeIT/material-angular-dashboard/issues"
"url": "https://github.com/perara/wg-manager/issues"
},
"homepage": "https://github.com/CreativeIT/material-angular-dashboard",
"homepage": "https://github.com/perara/wg-manager",
"dependencies": {
"@angular/animations": "9.1.0",
"@angular/cdk": "^9.2.0",
"@angular/common": "9.1.0",
"@angular/compiler": "9.1.0",
"@angular/core": "9.1.0",
"@angular/flex-layout": "^9.0.0-beta.29",
"@angular/forms": "9.1.0",
"@angular/localize": "9.1.0",
"@angular/material": "^9.2.0",
"@angular/platform-browser": "9.1.0",
"@angular/platform-browser-dynamic": "9.1.0",
"@angular/router": "9.1.0",
"@jedmao/ini-parser": "^0.2.4",
"angular-material-dynamic-themes": "^1.0.4",
"angular-notifier": "^6.0.1",
"angularx-qrcode": "^2.1.0",
"@angular/animations": "11.0.5",
"@angular/cdk": "11.0.3",
"@angular/common": "11.0.5",
"@angular/compiler": "11.0.5",
"@angular/core": "11.0.5",
"@angular/flex-layout": "11.0.0-beta.33",
"@angular/forms": "11.0.5",
"@angular/localize": "11.0.5",
"@angular/material": "11.0.3",
"@angular/platform-browser": "11.0.5",
"@angular/platform-browser-dynamic": "11.0.5",
"@angular/router": "11.0.5",
"@jedmao/ini-parser": "0.2.4",
"angular-material-dynamic-themes": "1.0.4",
"angular-notifier": "6.0.1",
"angularx-qrcode": "10.0.11",
"classlist.js": "1.1.20150312",
"core-js": "3.6.4",
"file-saver": "^2.0.2",
"hammerjs": "^2.0.8",
"install": "^0.13.0",
"ip-cidr": "^2.0.10",
"js-file-download": "^0.4.11",
"jszip": "^3.3.0",
"material-icons": "^0.3.1",
"ngx-cookie-service": "^3.0.4",
"npm": "^6.14.4",
"remove": "^0.1.5",
"file-saver": "2.0.5",
"hammerjs": "2.0.8",
"install": "0.13.0",
"ip-address": "^7.1.0",
"ip-cidr": "2.1.1",
"js-file-download": "0.4.12",
"jszip": "3.5.0",
"material-icons": "0.5.1",
"ngx-cookie-service": "11.0.2",
"npm": "6.14.6",
"remove": "0.1.5",
"rxjs": "6.5.5",
"tslib": "^1.10.0",
"web-animations-js": "^2.3.2",
"widdershins": "^4.0.1",
"zone.js": "^0.10.3"
"tslib": "2.0.3",
"web-animations-js": "2.3.2",
"widdershins": "4.0.1",
"zone.js": "0.10.3"
},
"devDependencies": {
"@angular-devkit/schematics": "^9.1.1",
"@angular-devkit/build-angular": "~0.901.0",
"@angular/cli": "9.1.0",
"@angular/compiler-cli": "9.1.0",
"@angular/language-service": "9.1.0",
"@angular-devkit/schematics": "^11.0.5",
"@angular-devkit/build-angular": "~0.1100.5",
"@angular/cli": "11.0.5",
"@angular/compiler-cli": "11.0.5",
"@angular/language-service": "11.0.5",
"@types/node": "^13.11.0",
"codelyzer": "^5.1.2",
"node-sass": "4.13.1",
"codelyzer": "^6.0.0",
"sass": "1.32.0",
"pre-commit": "1.2.2",
"stylelint": "13.3.0",
"stylelint-config-recommended-scss": "4.2.0",
"stylelint-config-standard": "20.0.0",
"stylelint-scss": "3.16.0",
"ts-node": "8.8.2",
"tslint": "6.1.1",
"tslint": "~6.1.0",
"tslint-angular": "3.0.2",
"tslint-config-airbnb": "5.11.2",
"typescript": "3.8.3"
"typescript": "4.0.5"
}
}

2
wg_dashboard_frontend/src/app/app-routing.module.ts

@ -29,7 +29,7 @@ import { ErrorComponent } from './page/error';
{ path: '**', redirectTo: '/page/404' },
],
{ useHash: true },
{ useHash: true, relativeLinkResolution: 'legacy' },
),
LayoutModule,
],

1
wg_dashboard_frontend/src/app/interfaces/peer.ts

@ -7,6 +7,7 @@ export interface Peer {
shared_key: string;
dns: string;
allowed_ips: string;
keep_alive: number;
name: string;
configuration: string;
stats: {

19
wg_dashboard_frontend/src/app/page/dashboard/add-server/add-server.component.html

@ -107,7 +107,24 @@
<input formControlName="dns" matInput [placeholder]="defaultIPv4Address">
</mat-form-field>
</td>
</tr></table>
</tr>
<tr>
<td>
<mat-form-field class="add-server-full-width">
<mat-label>Default allowed IPs</mat-label>
<input formControlName="allowed_ips" matInput [placeholder]="defaultAllowedIPs">
</mat-form-field>
</td>
</tr>
<tr>
<td>
<mat-form-field class="add-server-full-width">
<mat-label>Default PersistentKeepalive interval</mat-label>
<input formControlName="keep_alive" matInput [placeholder]="defaultPersistentKeepalive">
</mat-form-field>
</td>
</tr>
</table>
<p><b>Keys</b></p>
<p>

11
wg_dashboard_frontend/src/app/page/dashboard/add-server/add-server.component.ts

@ -44,6 +44,8 @@ export class AddServerComponent implements OnInit {
defaultIPv4Address = "10.0.200.1"
defaultDNS = this.defaultIPv4Address + ",8.8.8.8"
defaultIPv6Address = "fd42:42:42::1"
defaultAllowedIPs = "0.0.0.0/0, ::/0"
defaultPersistentKeepalive = 0;
serverForm: FormGroup = null;
@ -60,11 +62,13 @@ export class AddServerComponent implements OnInit {
listen_port: new FormControl(this.defaultListenPort, [Validators.required, NumberValidator.stringIsNumber]),
endpoint: new FormControl('', Validators.required),
dns: new FormControl(this.defaultDNS),
allowed_ips: new FormControl(this.defaultAllowedIPs),
keep_alive: new FormControl(this.defaultPersistentKeepalive),
private_key: new FormControl('' ),
public_key: new FormControl('' ),
post_up: new FormControl(''),
post_down: new FormControl(''),
read_only: new FormControl(''),
read_only: new FormControl(0),
// Unused on backend
configuration: new FormControl(''),
@ -224,18 +228,17 @@ export class AddServerComponent implements OnInit {
const idx = this.servers.indexOf(this.editServer);
this.serverAPI.editServer(this.editServer, form).subscribe((server: Server) => {
this.servers[idx] = server;
this.resetForm();
});
} else {
this.serverAPI.addServer(form).subscribe((server: Server) => {
this.servers.push(server);
this.resetForm();
});
}
this.resetForm();
}
getKeyPair() {

7
wg_dashboard_frontend/src/app/page/dashboard/peer/peer.component.html

@ -40,6 +40,13 @@
</mat-form-field>
</p>
<p>
<mat-form-field class="full-width">
<mat-label>PersistentKeepalive interval</mat-label>
<input [disabled]="!peer._edit" name="keep_alive" [(ngModel)]="peer.keep_alive" matInput>
</mat-form-field>
</p>
<p>Keys</p>
<p>

18
wg_dashboard_frontend/src/app/validators/ip-address.validator.ts

@ -1,12 +1,22 @@
import { AbstractControl, ValidationErrors } from '@angular/forms';
import * as IPCIDR from 'ip-cidr';
import {Address4, Address6} from 'ip-address'
export class IPValidator {
static isIPAddress(control: AbstractControl): ValidationErrors | null {
if (!control.value || !(new IPCIDR(control.value).isValid())) {
return { validIP: true };
}
return null;
try {
new Address4(control.value)
return null
} catch (e) {}
try{
new Address6(control.value)
return null
} catch (e) {}
return { validIP: true };
}
}

5
wg_dashboard_frontend/src/theme/styles.scss

@ -78,3 +78,8 @@ body {
.red{
color:red;
}
.mat-form-field{
// TODO this is a sleezy fix for cutting text in input boxes. need to figure out the root cause eventually.
line-height: 1.5;
}

2
wg_dashboard_frontend/tsconfig.json

@ -2,7 +2,7 @@
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./src",
"module": "esnext",
"module": "es2020",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,

3
wg_dashboard_frontend/tslint.json

@ -14,6 +14,9 @@
"ignore-pattern": "(\"|'|`).*?\\1"
}
],
"deprecation": {
"severity": "warning"
},
"function-name": [
true,
{

Loading…
Cancel
Save