Browse Source

Merge branch 'dev' into main

pull/109/head
Per-Arne Andersen 3 years ago
parent
commit
1af076e1a0
  1. 1
      .github/FUNDING.yml
  2. 51
      .github/workflows/image.yml
  3. 26
      .gitignore
  4. 5
      Dockerfile
  5. 6
      docs/install.md
  6. 0
      wg-manager-backend/__init__.py
  7. 89
      wg-manager-backend/alembic.ini
  8. 0
      wg-manager-backend/const.py
  9. 0
      wg-manager-backend/database/__init__.py
  10. 21
      wg-manager-backend/database/database.py
  11. 2
      wg-manager-backend/database/models.py
  12. 62
      wg-manager-backend/database/util.py
  13. 0
      wg-manager-backend/db/__init__.py
  14. 2
      wg-manager-backend/db/api_key.py
  15. 3
      wg-manager-backend/db/user.py
  16. 52
      wg-manager-backend/db/wireguard.py
  17. 21
      wg-manager-backend/logger.py
  18. 11
      wg-manager-backend/logging.json
  19. 102
      wg-manager-backend/main.py
  20. 12
      wg-manager-backend/middleware.py
  21. 1
      wg-manager-backend/migrations/README
  22. 84
      wg-manager-backend/migrations/env.py
  23. 24
      wg-manager-backend/migrations/script.py.mako
  24. 117
      wg-manager-backend/migrations/versions/4ac3e58519eb_base.py
  25. 3
      wg-manager-backend/requirements.txt
  26. 0
      wg-manager-backend/routers/__init__.py
  27. 0
      wg-manager-backend/routers/v1/__init__.py
  28. 3
      wg-manager-backend/routers/v1/peer.py
  29. 6
      wg-manager-backend/routers/v1/server.py
  30. 4
      wg-manager-backend/routers/v1/user.py
  31. 0
      wg-manager-backend/routers/v1/wg.py
  32. 7
      wg-manager-backend/schemas.py
  33. 0
      wg-manager-backend/script/__init__.py
  34. 0
      wg-manager-backend/script/obfuscate/__init__.py
  35. 0
      wg-manager-backend/script/obfuscate/obfs4.py
  36. 0
      wg-manager-backend/script/obfuscate/shapeshifter.py
  37. 0
      wg-manager-backend/script/obfuscate/tor.py
  38. 7
      wg-manager-backend/script/wireguard.py
  39. 34
      wg-manager-backend/script/wireguard_startup.py
  40. 0
      wg-manager-backend/templates/peer.j2
  41. 0
      wg-manager-backend/templates/server.j2
  42. 0
      wg-manager-backend/tests/__init__.py
  43. 0
      wg-manager-backend/tests/database.db
  44. 0
      wg-manager-backend/tests/test_pytest.py
  45. 14
      wg-manager-backend/util.py
  46. 0
      wg-manager-frontend/.editorconfig
  47. 51
      wg-manager-frontend/.eslintrc.json
  48. 0
      wg-manager-frontend/.github/CONTRIBUTING.md
  49. 0
      wg-manager-frontend/.github/ISSUE_TEMPLATE.md
  50. 0
      wg-manager-frontend/.github/PULL_REQUEST_TEMPLATE.md
  51. 0
      wg-manager-frontend/.stylelintrc
  52. 0
      wg-manager-frontend/LICENSE
  53. 16
      wg-manager-frontend/angular.json
  54. 90
      wg-manager-frontend/package.json
  55. 0
      wg-manager-frontend/proxy.conf.json
  56. 0
      wg-manager-frontend/src/app/app-routing.module.ts
  57. 0
      wg-manager-frontend/src/app/app.component.ts
  58. 0
      wg-manager-frontend/src/app/app.module.ts
  59. 0
      wg-manager-frontend/src/app/directives/var.directive.ts
  60. 0
      wg-manager-frontend/src/app/index.ts
  61. 0
      wg-manager-frontend/src/app/interfaces/peer.ts
  62. 0
      wg-manager-frontend/src/app/interfaces/server.ts
  63. 0
      wg-manager-frontend/src/app/interfaces/user.ts
  64. 0
      wg-manager-frontend/src/app/layout/layout.module.ts
  65. 0
      wg-manager-frontend/src/app/layout/layout/layout.component.html
  66. 0
      wg-manager-frontend/src/app/layout/layout/layout.component.scss
  67. 0
      wg-manager-frontend/src/app/layout/layout/layout.component.spec.ts
  68. 0
      wg-manager-frontend/src/app/layout/layout/layout.component.ts
  69. 0
      wg-manager-frontend/src/app/page/components/components.component.html
  70. 0
      wg-manager-frontend/src/app/page/components/components.component.scss
  71. 0
      wg-manager-frontend/src/app/page/components/components.component.ts
  72. 0
      wg-manager-frontend/src/app/page/components/components.module.ts
  73. 0
      wg-manager-frontend/src/app/page/components/index.ts
  74. 0
      wg-manager-frontend/src/app/page/components/modal-confirm/index.ts
  75. 0
      wg-manager-frontend/src/app/page/components/modal-confirm/modal-confirm.component.html
  76. 0
      wg-manager-frontend/src/app/page/components/modal-confirm/modal-confirm.component.scss
  77. 0
      wg-manager-frontend/src/app/page/components/modal-confirm/modal-confirm.component.ts
  78. 206
      wg-manager-frontend/src/app/page/dashboard/add-server/add-server.component.html
  79. 0
      wg-manager-frontend/src/app/page/dashboard/add-server/add-server.component.scss
  80. 9
      wg-manager-frontend/src/app/page/dashboard/add-server/add-server.component.ts
  81. 0
      wg-manager-frontend/src/app/page/dashboard/dashboard.component.css
  82. 16
      wg-manager-frontend/src/app/page/dashboard/dashboard.component.html
  83. 0
      wg-manager-frontend/src/app/page/dashboard/dashboard.component.ts
  84. 0
      wg-manager-frontend/src/app/page/dashboard/dashboard.module.ts
  85. 0
      wg-manager-frontend/src/app/page/dashboard/peer/peer.component.html
  86. 0
      wg-manager-frontend/src/app/page/dashboard/peer/peer.component.scss
  87. 0
      wg-manager-frontend/src/app/page/dashboard/peer/peer.component.ts
  88. 0
      wg-manager-frontend/src/app/page/dashboard/server/server.component.html
  89. 0
      wg-manager-frontend/src/app/page/dashboard/server/server.component.scss
  90. 0
      wg-manager-frontend/src/app/page/dashboard/server/server.component.ts
  91. 0
      wg-manager-frontend/src/app/page/error/error.component.css
  92. 0
      wg-manager-frontend/src/app/page/error/error.component.html
  93. 0
      wg-manager-frontend/src/app/page/error/error.component.ts
  94. 0
      wg-manager-frontend/src/app/page/error/index.ts
  95. 0
      wg-manager-frontend/src/app/page/page-routing.module.ts
  96. 0
      wg-manager-frontend/src/app/page/page.module.ts
  97. 0
      wg-manager-frontend/src/app/page/user/edit/api-key/api-key.component.html
  98. 0
      wg-manager-frontend/src/app/page/user/edit/api-key/api-key.component.scss
  99. 0
      wg-manager-frontend/src/app/page/user/edit/api-key/api-key.component.spec.ts
  100. 0
      wg-manager-frontend/src/app/page/user/edit/api-key/api-key.component.ts

1
.github/FUNDING.yml

@ -1,4 +1,3 @@
# These are supported funding model platforms
github: [perara]
custom: ["https://www.etherchain.org/account/002CbB62a1254C4ABFfad1798faCfADD827c43bE#txs"]

51
.github/workflows/image.yml

@ -1,25 +1,46 @@
name: build wg-dashboard
name: build and publish
on:
push:
branches:
- master
- '**'
jobs:
build:
docker:
runs-on: ubuntu-latest
steps:
- name: checkout code
-
name: Checkout
uses: actions/checkout@v2
- name: install buildx
id: buildx
uses: crazy-max/ghaction-docker-buildx@v1
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
-
name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
-
name: Build and push main
uses: docker/build-push-action@v2
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: perara/wg-manager:latest
if: github.ref == 'refs/heads/main'
-
name: Build and push dev
uses: docker/build-push-action@v2
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 .
context: .
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
tags: perara/wg-manager:dev
if: github.ref == 'refs/heads/dev'

26
.gitignore

@ -48,22 +48,32 @@ Thumbs.db
docker/__pycache__/
wg_dashboard_backend/__pycache__/
wg-manager-backend/__pycache__/
wg_dashboard_frontend/yarn.lock
wg-manager-frontend/yarn.lock
wg_dashboard_backend/config/server/wg0/clients/4.conf
wg-manager-backend/config/server/wg0/clients/4.conf
wg_dashboard_backend/config/server/wg0/clients/5.conf
wg-manager-backend/config/server/wg0/clients/5.conf
wg_dashboard_backend/config/server/wg0/clients/6.conf
wg-manager-backend/config/server/wg0/clients/6.conf
wg_dashboard_backend/config/server/wg0/clients/7.conf
wg-manager-backend/config/server/wg0/clients/7.conf
wg_dashboard_backend/config/server/wg0/wg0.conf
wg-manager-backend/config/server/wg0/wg0.conf
wg-dashboard-py.iml
docker/wg0.conf
wg_dashboard_backend/database.db
wg-manager-backend/database.db
wg-manager-backend/logsaccess.log
wg-manager-backend/database.db_initial_v1 copy
wg-manager-backend/database.db_new_ver
wg-manager-backend/script/obfuscate/binary/shapeshifter-dispatcher
wg-manager/database.db

5
Dockerfile

@ -2,7 +2,8 @@ FROM ubuntu:20.04
ENV TZ=Europe/Minsk
ENV DEBIAN_FRONTEND=noninteractive
COPY ./wg_dashboard_frontend /tmp/build
#COPY ./wg-manager /tmp/build
RUN mkdir -p /tmp/build
WORKDIR /tmp/build
RUN apt-get update && apt-get install -y \
@ -25,7 +26,7 @@ WORKDIR /app
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
COPY wg-manager-backend /app
# Install dependencies
#RUN apk add --no-cache --update wireguard-tools py3-gunicorn python3 py3-pip ip6tables

6
docs/install.md

@ -77,7 +77,7 @@ sudo apt install wireguard wireguard-tools -y
```
# Building frontend
sudo git clone https://github.com/perara/wg-manager.git /opt/wg-manager
cd /opt/wg-manager/wg_dashboard_frontend
cd /opt/wg-manager/wg-manager-frontend
sudo npm install --unsafe-perm > /dev/null && sudo npm install @angular/cli > /dev/null
sudo node_modules/@angular/cli/bin/ng build --configuration="production"
```
@ -85,8 +85,8 @@ One thing to be aware of is that when issuing the `sudo node_modules/@angular/cl
## 4. Setup back-end
```
sudo mv dist ../wg_dashboard_backend/build
cd ../wg_dashboard_backend/
sudo mv dist ../wg-manager-backend/build
cd ../wg-manager-backend/
sudo python3 -m venv venv && source venv/bin/activate
sudo pip3 install -r requirements.txt
sudo pip3 install uvicorn

0
wg_dashboard_backend/__init__.py → wg-manager-backend/__init__.py

89
wg-manager-backend/alembic.ini

@ -0,0 +1,89 @@
# A generic, single database configuration.
[alembic]
# path to migration scripts
script_location = migrations
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s
# sys.path path, will be prepended to sys.path if present.
# defaults to the current working directory.
prepend_sys_path = .
# timezone to use when rendering the date
# within the migration file as well as the filename.
# string value is passed to dateutil.tz.gettz()
# leave blank for localtime
# timezone =
# max length of characters to apply to the
# "slug" field
# truncate_slug_length = 40
# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false
# set to 'true' to allow .pyc and .pyo files without
# a source .py file to be detected as revisions in the
# versions/ directory
# sourceless = false
# version location specification; this defaults
# to alembic/versions. When using multiple version
# directories, initial revisions must be specified with --version-path
# version_locations = %(here)s/bar %(here)s/bat alembic/versions
# the output encoding used when revision files
# are written from script.py.mako
# output_encoding = utf-8
sqlalchemy.url = sqlite:///database.db
[post_write_hooks]
# post_write_hooks defines scripts or Python functions that are run
# on newly generated revision scripts. See the documentation for further
# detail and examples
# format using "black" - use the console_scripts runner, against the "black" entrypoint
# hooks=black
# black.type=console_scripts
# black.entrypoint=black
# black.options=-l 79
# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = WARN
handlers = console
qualname =
[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine
[logger_alembic]
level = INFO
handlers =
qualname = alembic
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S

0
wg_dashboard_backend/const.py → wg-manager-backend/const.py

0
wg_dashboard_backend/db/__init__.py → wg-manager-backend/database/__init__.py

21
wg-manager-backend/database/database.py

@ -0,0 +1,21 @@
import sqlalchemy
from sqlalchemy import MetaData
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
import const
engine = sqlalchemy.create_engine(
const.DATABASE_URL, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
meta = MetaData(naming_convention={
"ix": "ix_%(column_0_label)s",
"uq": "uq_%(table_name)s_%(column_0_name)s",
"ck": "ck_%(table_name)s_%(column_0_name)s",
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
"pk": "pk_%(table_name)s"
})
Base = declarative_base(metadata=meta)

2
wg_dashboard_backend/models.py → wg-manager-backend/database/models.py

@ -4,7 +4,7 @@ import sqlalchemy
from sqlalchemy import Integer, Column, DateTime
from sqlalchemy.orm import relationship, backref
from database import Base
from database.database import Base
class User(Base):

62
wg-manager-backend/database/util.py

@ -0,0 +1,62 @@
import contextlib
import os
import alembic.command
from alembic.config import Config
from sqlalchemy.orm import Session
from sqlalchemy_utils import database_exists
import middleware
from database.database import engine, Base, SessionLocal
from database import models
from loguru import logger
def perform_migrations():
logger.info("Performing migrations...")
alembic_cfg = Config("alembic.ini")
alembic_cfg.attributes['configure_logger'] = False
alembic_cfg.set_main_option('script_location', "migrations")
alembic_cfg.set_main_option('sqlalchemy.url', str(engine.url))
alembic.command.upgrade(alembic_cfg, 'head')
logger.info("Migrations done!")
def setup_initial_database():
if not database_exists(engine.url):
logger.info("Database does not exists. Creating initial database...")
# Create database from metadata
Base.metadata.create_all(engine)
logger.info("Database creation done!")
# Create default user
_db: Session = SessionLocal()
admin_exists = (
_db.query(models.User.id)
.filter_by(role="admin")
.first()
) is not None
if not admin_exists:
logger.info("Admin user does not exists. Creating with env variables ADMIN_USERNAME, ADMIN_PASSWORD")
ADMIN_USERNAME = os.getenv("ADMIN_USERNAME")
ADMIN_PASSWORD = os.getenv("ADMIN_PASSWORD")
if not ADMIN_USERNAME:
raise RuntimeError("Database does not exist and the environment variable ADMIN_USERNAME is set")
if not ADMIN_PASSWORD:
raise RuntimeError("Database does not exist and the environment variable ADMIN_PASSWORD is set")
_db.merge(models.User(
username=ADMIN_USERNAME,
password=middleware.get_password_hash(ADMIN_PASSWORD),
full_name="Admin",
role="admin",
email=""
))
_db.commit()
_db.close()

0
wg_dashboard_backend/migrations/__init__.py → wg-manager-backend/db/__init__.py

2
wg_dashboard_backend/db/api_key.py → wg-manager-backend/db/api_key.py

@ -1,6 +1,6 @@
from sqlalchemy.orm import Session
import models
from database import models
def add_initial_api_key_for_admin(sess: Session, api_key, ADMIN_USERNAME):

3
wg_dashboard_backend/db/user.py → wg-manager-backend/db/user.py

@ -1,8 +1,7 @@
from typing import Optional
from sqlalchemy.orm import Session
import models
from passlib.context import CryptContext
from database import models
import schemas

52
wg_dashboard_backend/db/wireguard.py → wg-manager-backend/db/wireguard.py

@ -8,15 +8,12 @@ from starlette.exceptions import HTTPException
import const
import script.wireguard
from sqlalchemy import exists
from sqlalchemy.orm import Session, joinedload
import util
import models
from sqlalchemy.orm import Session
from database import models
import schemas
import logging
from loguru import logger
_LOGGER = logging.getLogger(__name__)
_LOGGER.setLevel(logging.DEBUG)
from util import WGMHTTPException
def start_client(sess: Session, peer: schemas.WGPeer):
@ -163,8 +160,8 @@ def server_add_on_init(sess: Session):
# Only add if it does not already exists.
server_add(schemas.WGServerAdd(**init_data), sess, start=const.SERVER_INIT_INTERFACE_START)
except Exception as e:
_LOGGER.warning("Failed to setup initial server interface with exception:")
_LOGGER.exception(e)
logger.warning("Failed to setup initial server interface with exception:")
logger.exception(e)
def server_add(server: schemas.WGServerAdd, sess: Session, start=False):
@ -182,16 +179,30 @@ def server_add(server: schemas.WGServerAdd, sess: Session, start=False):
peers = server.peers if server.peers else []
# Public/Private key
try:
if sess.query(models.WGServer) \
.filter(
(models.WGServer.interface == server.interface) |
(models.WGServer.address == server.address) |
(models.WGServer.v6_address == server.v6_address)).count() != 0:
raise HTTPException(status_code=400,
detail="The server interface or ip %s already exists in the database" % server.interface)
all_interfaces = sess.query(models.WGServer).all()
check_interface_exists = any(map(lambda el: el.interface == server.interface, all_interfaces))
check_v4_address_exists = any(map(lambda el: el.address == server.address, all_interfaces))
check_v6_address_exists = any(map(lambda el: el.v6_address == server.v6_address, all_interfaces))
check_listen_port_exists = any(map(lambda el: str(el.listen_port) == str(server.listen_port), all_interfaces))
if check_interface_exists:
raise WGMHTTPException(
status_code=400,
detail=f"There is already a interface with the name: {server.interface}")
if check_v4_address_exists:
raise WGMHTTPException(
status_code=400,
detail=f"There is already a interface with the IPv4 address: {server.address}")
if server.v6_support and check_v6_address_exists:
raise WGMHTTPException(
status_code=400,
detail=f"There is already a interface with the IPv6 address: {server.v6_address}")
if check_listen_port_exists:
raise WGMHTTPException(
status_code=400,
detail=f"There is already a interface listening on port: {server.listen_port}")
if not server.private_key:
keys = script.wireguard.generate_keys()
@ -217,9 +228,6 @@ def server_add(server: schemas.WGServerAdd, sess: Session, start=False):
server.from_db(sess)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
if start and not script.wireguard.is_running(server):
script.wireguard.start_interface(server)

21
wg-manager-backend/logger.py

@ -0,0 +1,21 @@
def setup_logging():
import logging
from loguru import logger
class InterceptHandler(logging.Handler):
def emit(self, record):
# Get corresponding Loguru level if it exists
try:
level = logger.level(record.levelname).name
except ValueError:
level = record.levelno
# Find caller from where originated the logged message
frame, depth = logging.currentframe(), 2
while frame.f_code.co_filename == logging.__file__:
frame = frame.f_back
depth += 1
logger.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage())
logging.basicConfig(handlers=[InterceptHandler()], level=1)

11
wg-manager-backend/logging.json

@ -0,0 +1,11 @@
{
"logger": {
"path": "./logs",
"filename": "access.log",
"level": "info",
"rotation": "20 days",
"retention": "1 months",
"format": "<level>{level: <8}</level> <green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> {extra[request_id]} - <cyan>{name}</cyan>:<cyan>{function}</cyan> - <level>{message}</level>"
}
}

102
wg-manager-backend/main.py

@ -0,0 +1,102 @@
from logger import setup_logging
setup_logging()
import const
from uvicorn_loguru_integration import run_uvicorn_loguru
import time
from starlette.middleware.base import BaseHTTPMiddleware
import middleware
from routers.v1 import user, server, peer, wg
import script.wireguard_startup
import pkg_resources
import uvicorn as uvicorn
from fastapi.staticfiles import StaticFiles
from starlette.responses import FileResponse
from fastapi import Depends, FastAPI
import database.util
app = FastAPI()
app.add_middleware(BaseHTTPMiddleware, dispatch=middleware.db_session_middleware)
app.add_middleware(BaseHTTPMiddleware, dispatch=middleware.logging_middleware)
app.include_router(
user.router,
prefix="/api/v1",
tags=["user"],
dependencies=[],
responses={404: {"description": "Not found"}}
)
app.include_router(
server.router,
prefix="/api/v1/server",
tags=["server"],
dependencies=[Depends(middleware.auth)],
responses={404: {"description": "Not found"}}
)
app.include_router(
peer.router,
prefix="/api/v1/peer",
tags=["peer"],
dependencies=[Depends(middleware.auth)],
responses={404: {"description": "Not found"}}
)
app.include_router(
wg.router,
prefix="/api/v1/wg",
tags=["wg"],
dependencies=[Depends(middleware.auth)],
responses={404: {"description": "Not found"}}
)
@app.get("/", include_in_schema=True)
def root():
return FileResponse('build/index.html')
app.mount("/", StaticFiles(directory=pkg_resources.resource_filename(__name__, 'build')), name="static")
@app.on_event("startup")
async def startup():
pass
@app.on_event("shutdown")
async def shutdown():
pass
if __name__ == "__main__":
# Sleep the wait timer.
time.sleep(const.INIT_SLEEP)
# Ensure database existence
database.util.setup_initial_database()
# Perform Migrations
database.util.perform_migrations()
# Configure wireguard
script.wireguard_startup.setup_on_start()
run_uvicorn_loguru(
uvicorn.Config(
"__main__:app",
host="0.0.0.0",
port=8000,
log_level="warning",
reload=True,
workers=1
)
)

12
wg_dashboard_backend/middleware.py → wg-manager-backend/middleware.py

@ -4,6 +4,7 @@ import jwt
from fastapi import Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer
from jwt import PyJWTError
from loguru import logger
from passlib.context import CryptContext
from sqlalchemy.orm import Session
from starlette import status
@ -11,10 +12,9 @@ from starlette.requests import Request
from starlette.responses import Response
import const
import models
import schemas
from database import SessionLocal
import db.user
from database import models
from database.database import SessionLocal
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/login", auto_error=False)
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
@ -28,6 +28,12 @@ def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
async def logging_middleware(request: Request, call_next):
response = await call_next(request)
logger.opt(depth=2).info(f"{request.method} {request.url} - Code: {response.status_code}")
return response
async def db_session_middleware(request: Request, call_next):
response = Response("Internal server error (Database error)", status_code=500)
try:

1
wg-manager-backend/migrations/README

@ -0,0 +1 @@
Generic single-database configuration.

84
wg-manager-backend/migrations/env.py

@ -0,0 +1,84 @@
from logging.config import fileConfig
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
import database.models
import database.database
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
if config.attributes.get('configure_logger', True):
fileConfig(config.config_file_name)
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = database.database.Base.metadata
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
render_as_batch=False
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
render_as_batch=False
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()

24
wg-manager-backend/migrations/script.py.mako

@ -0,0 +1,24 @@
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}
"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}
def upgrade():
${upgrades if upgrades else "pass"}
def downgrade():
${downgrades if downgrades else "pass"}

117
wg-manager-backend/migrations/versions/4ac3e58519eb_base.py

@ -0,0 +1,117 @@
"""base
Revision ID: 4ac3e58519eb
Revises:
Create Date: 2021-03-13 20:29:10.062757
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
from sqlalchemy.exc import OperationalError
revision = '4ac3e58519eb'
down_revision = None
branch_labels = None
depends_on = None
def ignore_duplicate(fn):
try:
fn()
except OperationalError as e:
if "duplicate" in str(e):
pass
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
try:
op.create_table('api_keys',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('key', sa.String(), nullable=True),
sa.Column('user_id', sa.Integer(), nullable=True),
sa.Column('created_date', sa.DateTime(), nullable=True),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], name='fk_user_api_key_user_id', onupdate='CASCADE', ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('key')
)
except OperationalError:
pass
try:
op.drop_table('migrate_version')
except OperationalError:
pass
naming_convention = {
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
}
with op.batch_alter_table("peer", naming_convention=naming_convention) as batch_op:
batch_op.drop_constraint("fk_peer_server_id_server", type_="foreignkey")
with op.batch_alter_table('peer', schema=None) as batch_op:
batch_op.create_foreign_key('fk_peer_server_id_server', 'server', ['server_id'], ['id'], onupdate='CASCADE', ondelete='CASCADE')
ignore_duplicate(lambda: op.add_column('peer', sa.Column('configuration', sa.Text(), nullable=True)))
ignore_duplicate(lambda: op.add_column('peer', sa.Column('keep_alive', sa.Integer(), nullable=True)))
ignore_duplicate(lambda: op.add_column('peer', sa.Column('read_only', sa.Integer(), nullable=True)))
ignore_duplicate(lambda: op.add_column('peer', sa.Column('server_id', sa.Integer(), nullable=True)))
ignore_duplicate(lambda: op.add_column('peer', sa.Column('shared_key', sa.Text(), nullable=True)))
ignore_duplicate(lambda: op.add_column('peer', sa.Column('v6_address', sa.String(), nullable=True)))
#op.drop_constraint(None, 'peer', type_='foreignkey')
#
#op.drop_column('peer', 'server')
try:
with op.batch_alter_table('peer', schema=None) as batch_op:
batch_op.drop_column("server")
except KeyError:
pass
ignore_duplicate(lambda: op.add_column('server', sa.Column('allowed_ips', sa.String(), nullable=True)))
ignore_duplicate(lambda: op.add_column('server', sa.Column('configuration', sa.Text(), nullable=True)))
ignore_duplicate(lambda: op.add_column('server', sa.Column('dns', sa.String(), nullable=True)))
ignore_duplicate(lambda: op.add_column('server', sa.Column('keep_alive', sa.Integer(), nullable=True)))
ignore_duplicate(lambda: op.add_column('server', sa.Column('read_only', sa.Integer(), nullable=True)))
ignore_duplicate(lambda: op.add_column('server', sa.Column('subnet', sa.Integer(), nullable=False)))
ignore_duplicate(lambda: op.add_column('server', sa.Column('v6_address', sa.String(), nullable=True)))
ignore_duplicate(lambda: op.add_column('server', sa.Column('v6_subnet', sa.Integer(), nullable=False)))
#op.create_unique_constraint(None, 'server', ['v6_address'])
try:
with op.batch_alter_table('server', schema=None) as batch_op:
batch_op.drop_column("shared_key")
except KeyError:
pass
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('server', sa.Column('shared_key', sa.VARCHAR(), nullable=True))
op.drop_constraint(None, 'server', type_='unique')
op.drop_column('server', 'v6_subnet')
op.drop_column('server', 'v6_address')
op.drop_column('server', 'subnet')
op.drop_column('server', 'read_only')
op.drop_column('server', 'keep_alive')
op.drop_column('server', 'dns')
op.drop_column('server', 'configuration')
op.drop_column('server', 'allowed_ips')
op.add_column('peer', sa.Column('server', sa.INTEGER(), nullable=True))
op.drop_constraint('fk_wg_peer_server_id', 'peer', type_='foreignkey')
op.create_foreign_key(None, 'peer', 'server', ['server'], ['interface'])
op.drop_column('peer', 'v6_address')
op.drop_column('peer', 'shared_key')
op.drop_column('peer', 'server_id')
op.drop_column('peer', 'read_only')
op.drop_column('peer', 'keep_alive')
op.drop_column('peer', 'configuration')
op.drop_table('api_keys')
# ### end Alembic commands ###

3
wg_dashboard_backend/requirements.txt → wg-manager-backend/requirements.txt

@ -13,6 +13,9 @@ sqlalchemy_utils
sqlalchemy-migrate
requests
uvicorn
uvicorn-loguru-integration
uvloop
httptools
qrcode[pil]
alembic
loguru

0
wg_dashboard_backend/migrations/versions/__init__.py → wg-manager-backend/routers/__init__.py

0
wg_dashboard_backend/routers/__init__.py → wg-manager-backend/routers/v1/__init__.py

3
wg_dashboard_backend/routers/v1/peer.py → wg-manager-backend/routers/v1/peer.py

@ -4,8 +4,7 @@ from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from starlette.responses import PlainTextResponse
import const
import models
from database import models
import schemas
import middleware
import db.wireguard

6
wg_dashboard_backend/routers/v1/server.py → wg-manager-backend/routers/v1/server.py

@ -1,12 +1,8 @@
import tempfile
from os.path import exists
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from starlette.responses import JSONResponse
import const
import models
from database import models
import schemas
import middleware
import db.wireguard

4
wg_dashboard_backend/routers/v1/user.py → wg-manager-backend/routers/v1/user.py

@ -2,7 +2,7 @@ import os
from datetime import timedelta
from fastapi import APIRouter, HTTPException, Depends, Form, Body
from fastapi.responses import PlainTextResponse, JSONResponse
from fastapi.responses import JSONResponse
import typing
from sqlalchemy.orm import Session
from starlette import status
@ -10,7 +10,7 @@ from binascii import hexlify
import const
import db.user
import middleware
import models
from database import models
import schemas
router = APIRouter()

0
wg_dashboard_backend/routers/v1/wg.py → wg-manager-backend/routers/v1/wg.py

7
wg_dashboard_backend/schemas.py → wg-manager-backend/schemas.py

@ -5,7 +5,7 @@ from pydantic import BaseModel, typing
from sqlalchemy.orm import Session, Query
from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound
import logging
import models
from database import models
_LOGGER = logging.getLogger(__name__)
@ -60,7 +60,7 @@ class GenericModel(BaseModel):
if n_results == 0:
# Insert, does not exists at all.
# Convert from schema to model
dbm = self.Meta.model(**self.dict())
dbm = self.Meta.model(**self.dict(exclude=self.Meta.excludes)) # TODO. added exclude here. this might mess stuff?
sess.add(dbm)
else:
self.filter_query(sess).update(self.dict(include=self.columns()))
@ -179,7 +179,7 @@ class WGServer(GenericModel):
class Meta:
model = models.WGServer
key = "interface"
excludes = {"id", "peers"}
excludes = {"id", "peers", "v6_support"}
def convert(self):
self.peers = [] if not self.peers else self.peers
@ -190,6 +190,7 @@ class WGServerAdd(WGServer):
address: str
interface: str
listen_port: int
v6_support: bool
class WGPeerConfigAdd(GenericModel):

0
wg_dashboard_backend/routers/v1/__init__.py → wg-manager-backend/script/__init__.py

0
wg_dashboard_backend/script/obfuscate/__init__.py → wg-manager-backend/script/obfuscate/__init__.py

0
wg_dashboard_backend/script/obfuscate/obfs4.py → wg-manager-backend/script/obfuscate/obfs4.py

0
wg_dashboard_backend/script/obfuscate/shapeshifter.py → wg-manager-backend/script/obfuscate/shapeshifter.py

0
wg_dashboard_backend/script/obfuscate/tor.py → wg-manager-backend/script/obfuscate/tor.py

7
wg_dashboard_backend/script/wireguard.py → wg-manager-backend/script/wireguard.py

@ -9,13 +9,13 @@ import configparser
from sqlalchemy.orm import Session
import const
import models
import schemas
import os
import re
import ipaddress
import util
from database import SessionLocal
from database import models
from database.database import SessionLocal
_LOGGER = logging.getLogger(__name__)
@ -390,7 +390,6 @@ def load_environment_clients(sess: Session):
i += 1
if __name__ == "__main__":
os.environ["CLIENT_1_NAME"] = "client-1"
os.environ["CLIENT_1_SERVER_INTERFACE"] = "wg0"
@ -403,3 +402,5 @@ if __name__ == "__main__":
sess: Session = SessionLocal()
load_environment_clients(sess)
sess.close()

34
wg-manager-backend/script/wireguard_startup.py

@ -0,0 +1,34 @@
import os
import typing
from sqlalchemy.orm import Session
import const
from database import models
from database.database import SessionLocal
from db.api_key import add_initial_api_key_for_admin
from db.wireguard import server_add_on_init
from script.wireguard import is_installed, start_interface, is_running, load_environment_clients
def setup_on_start():
_db: Session = SessionLocal()
servers: typing.List[models.WGServer] = _db.query(models.WGServer).all()
for s in servers:
try:
last_state = s.is_running
if is_installed() and last_state and is_running(s):
start_interface(s)
except Exception as e:
print(e)
if const.CLIENT:
load_environment_clients(_db)
if const.SERVER_INIT_INTERFACE is not None:
server_add_on_init(_db)
if const.SERVER_STARTUP_API_KEY is not None:
ADMIN_USERNAME = os.getenv("ADMIN_USERNAME")
add_initial_api_key_for_admin(_db, const.SERVER_STARTUP_API_KEY, ADMIN_USERNAME)
_db.close()

0
wg_dashboard_backend/templates/peer.j2 → wg-manager-backend/templates/peer.j2

0
wg_dashboard_backend/templates/server.j2 → wg-manager-backend/templates/server.j2

0
wg_dashboard_backend/script/__init__.py → wg-manager-backend/tests/__init__.py

0
wg_dashboard_backend/tests/database.db → wg-manager-backend/tests/database.db

0
wg_dashboard_backend/tests/test_pytest.py → wg-manager-backend/tests/test_pytest.py

14
wg-manager-backend/util.py

@ -0,0 +1,14 @@
from loguru import logger
from fastapi import HTTPException
import os
from jinja2 import Environment, FileSystemLoader
templates_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
jinja_env = Environment(loader=FileSystemLoader(templates_path))
class WGMHTTPException(HTTPException):
def __init__(self, status_code: int, detail: str = None):
HTTPException.__init__(self, status_code, detail)
logger.opt(depth=1).error(detail)

0
wg_dashboard_frontend/.editorconfig → wg-manager-frontend/.editorconfig

51
wg-manager-frontend/.eslintrc.json

@ -0,0 +1,51 @@
{
"root": true,
"ignorePatterns": [
"projects/**/*"
],
"overrides": [
{
"files": [
"*.ts"
],
"parserOptions": {
"project": [
"tsconfig.json",
"e2e/tsconfig.json"
],
"createDefaultProgram": true
},
"extends": [
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@angular-eslint/component-selector": [
"error",
{
"prefix": "app",
"style": "kebab-case",
"type": "element"
}
],
"@angular-eslint/directive-selector": [
"error",
{
"prefix": "app",
"style": "camelCase",
"type": "attribute"
}
]
}
},
{
"files": [
"*.html"
],
"extends": [
"plugin:@angular-eslint/template/recommended"
],
"rules": {}
}
]
}

0
wg_dashboard_frontend/.github/CONTRIBUTING.md → wg-manager-frontend/.github/CONTRIBUTING.md

0
wg_dashboard_frontend/.github/ISSUE_TEMPLATE.md → wg-manager-frontend/.github/ISSUE_TEMPLATE.md

0
wg_dashboard_frontend/.github/PULL_REQUEST_TEMPLATE.md → wg-manager-frontend/.github/PULL_REQUEST_TEMPLATE.md

0
wg_dashboard_frontend/.stylelintrc → wg-manager-frontend/.stylelintrc

0
wg_dashboard_frontend/LICENSE → wg-manager-frontend/LICENSE

16
wg_dashboard_frontend/angular.json → wg-manager-frontend/angular.json

@ -24,8 +24,7 @@
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"src/theme/styles.scss"
],
"scripts": [
]
"scripts": []
},
"configurations": {
"production": {
@ -71,13 +70,11 @@
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"builder": "@angular-eslint/builder:lint",
"options": {
"tsConfig": [
"src/tsconfig.app.json"
],
"exclude": [
"**/node_modules/**"
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
}
}
@ -91,7 +88,8 @@
},
"defaultProject": "wg-manager",
"cli": {
"packageManager": "yarn"
"packageManager": "yarn",
"defaultCollection": "@angular-eslint/schematics"
},
"schematics": {
"@schematics/angular:component": {

90
wg_dashboard_frontend/package.json → wg-manager-frontend/package.json

@ -1,6 +1,6 @@
{
"name": "wg_dashboard_frontend",
"version": "1.0.0",
"name": "wg-manager",
"version": "1.1.0",
"description": "WG Dashboard",
"keywords": [
"dashboard"
@ -11,7 +11,7 @@
"md-doc": "npm install widdershins && wget http://127.0.0.1:8000/openapi.json -O /tmp/wg-openapi.json && widdershins /tmp/wg-openapi.json --environment widdershins.json --resolve=true --omitHeader=true --language_tabs 'python:Python' -o ../docs/api.md",
"start": "ng serve --host 0.0.0.0 --disable-host-check",
"build": "ng build",
"buildwatch": "ng build --watch --aot --outputPath=../wg_dashboard_backend/build/ --host 0.0.0.0 --disable-host-check",
"buildwatch": "ng build --watch --aot --outputPath=../wg-manager-backend/build/ --host 0.0.0.0 --disable-host-check",
"tlint": "ng lint",
"tlint:fix": "ng lint --fix",
"slint": "stylelint --syntax scss ./**/*.scss",
@ -30,58 +30,62 @@
},
"homepage": "https://github.com/perara/wg-manager",
"dependencies": {
"@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/animations": "11.2.10",
"@angular/cdk": "11.2.9",
"@angular/common": "11.2.10",
"@angular/compiler": "11.2.10",
"@angular/core": "11.2.10",
"@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/forms": "11.2.10",
"@angular/localize": "11.2.10",
"@angular/material": "11.2.9",
"@angular/platform-browser": "11.2.10",
"@angular/platform-browser-dynamic": "11.2.10",
"@angular/router": "11.2.10",
"ngx-cookie-service": "11.0.2",
"angularx-qrcode": "11.0.0",
"angular-material-dynamic-themes": "1.0.4",
"angular-notifier": "6.0.1",
"angularx-qrcode": "10.0.11",
"angular-notifier": "9.0.1",
"classlist.js": "1.1.20150312",
"core-js": "3.6.4",
"core-js": "3.10.2",
"tslib": "2.2.0",
"web-animations-js": "2.3.2",
"widdershins": "4.0.1",
"zone.js": "0.11.4",
"material-icons": "0.6.1",
"@jedmao/ini-parser": "0.2.4",
"file-saver": "2.0.5",
"hammerjs": "2.0.8",
"install": "0.13.0",
"ip-address": "^7.1.0",
"ip-cidr": "2.1.1",
"ip-cidr": "2.1.4",
"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": "2.0.3",
"web-animations-js": "2.3.2",
"widdershins": "4.0.1",
"zone.js": "0.10.3"
"jszip": "3.6.0",
"rxjs": "6.6.7"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.1102.9",
"@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": "^6.0.0",
"sass": "1.32.0",
"@angular-eslint/builder": "4.0.0",
"@angular-eslint/eslint-plugin": "4.0.0",
"@angular-eslint/eslint-plugin-template": "4.0.0",
"@angular-eslint/schematics": "4.0.0",
"@angular-eslint/template-parser": "4.0.0",
"@angular/cli": "11.2.9",
"@angular/compiler-cli": "11.2.10",
"@angular/language-service": "11.2.10",
"@types/node": "^14.14.41",
"@typescript-eslint/eslint-plugin": "4.16.1",
"@typescript-eslint/parser": "4.16.1",
"eslint": "^7.6.0",
"pre-commit": "1.2.2",
"stylelint": "13.3.0",
"sass": "1.32.11",
"stylelint": "13.12.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.0",
"tslint-angular": "3.0.2",
"stylelint-config-standard": "21.0.0",
"stylelint-scss": "3.19.0",
"ts-node": "9.1.1",
"tslint-angular": "3.0.3",
"tslint-config-airbnb": "5.11.2",
"typescript": "4.0.5"
}

0
wg_dashboard_frontend/proxy.conf.json → wg-manager-frontend/proxy.conf.json

0
wg_dashboard_frontend/src/app/app-routing.module.ts → wg-manager-frontend/src/app/app-routing.module.ts

0
wg_dashboard_frontend/src/app/app.component.ts → wg-manager-frontend/src/app/app.component.ts

0
wg_dashboard_frontend/src/app/app.module.ts → wg-manager-frontend/src/app/app.module.ts

0
wg_dashboard_frontend/src/app/directives/var.directive.ts → wg-manager-frontend/src/app/directives/var.directive.ts

0
wg_dashboard_frontend/src/app/index.ts → wg-manager-frontend/src/app/index.ts

0
wg_dashboard_frontend/src/app/interfaces/peer.ts → wg-manager-frontend/src/app/interfaces/peer.ts

0
wg_dashboard_frontend/src/app/interfaces/server.ts → wg-manager-frontend/src/app/interfaces/server.ts

0
wg_dashboard_frontend/src/app/interfaces/user.ts → wg-manager-frontend/src/app/interfaces/user.ts

0
wg_dashboard_frontend/src/app/layout/layout.module.ts → wg-manager-frontend/src/app/layout/layout.module.ts

0
wg_dashboard_frontend/src/app/layout/layout/layout.component.html → wg-manager-frontend/src/app/layout/layout/layout.component.html

0
wg_dashboard_frontend/src/app/layout/layout/layout.component.scss → wg-manager-frontend/src/app/layout/layout/layout.component.scss

0
wg_dashboard_frontend/src/app/layout/layout/layout.component.spec.ts → wg-manager-frontend/src/app/layout/layout/layout.component.spec.ts

0
wg_dashboard_frontend/src/app/layout/layout/layout.component.ts → wg-manager-frontend/src/app/layout/layout/layout.component.ts

0
wg_dashboard_frontend/src/app/page/components/components.component.html → wg-manager-frontend/src/app/page/components/components.component.html

0
wg_dashboard_frontend/src/app/page/components/components.component.scss → wg-manager-frontend/src/app/page/components/components.component.scss

0
wg_dashboard_frontend/src/app/page/components/components.component.ts → wg-manager-frontend/src/app/page/components/components.component.ts

0
wg_dashboard_frontend/src/app/page/components/components.module.ts → wg-manager-frontend/src/app/page/components/components.module.ts

0
wg_dashboard_frontend/src/app/page/components/index.ts → wg-manager-frontend/src/app/page/components/index.ts

0
wg_dashboard_frontend/src/app/page/components/modal-confirm/index.ts → wg-manager-frontend/src/app/page/components/modal-confirm/index.ts

0
wg_dashboard_frontend/src/app/page/components/modal-confirm/modal-confirm.component.html → wg-manager-frontend/src/app/page/components/modal-confirm/modal-confirm.component.html

0
wg_dashboard_frontend/src/app/page/components/modal-confirm/modal-confirm.component.scss → wg-manager-frontend/src/app/page/components/modal-confirm/modal-confirm.component.scss

0
wg_dashboard_frontend/src/app/page/components/modal-confirm/modal-confirm.component.ts → wg-manager-frontend/src/app/page/components/modal-confirm/modal-confirm.component.ts

206
wg-manager-frontend/src/app/page/dashboard/add-server/add-server.component.html

@ -0,0 +1,206 @@
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
<b>New WireGuard Server</b>
</mat-panel-title>
<mat-panel-description>
Expand this to open configuration of a new wireguard server
</mat-panel-description>
</mat-expansion-panel-header>
<form [formGroup]="serverForm" class="add-server-form">
<p><b>Network Configuration</b></p>
<table class="add-server-full-width" cellspacing="0"><tr>
<td>
<mat-form-field class="add-server-full-width">
<mat-label>Interface</mat-label>
<input formControlName="interface" matInput [placeholder]="defaultInterface">
</mat-form-field>
</td>
<td>
<mat-form-field class="add-server-full-width">
<mat-label>Endpoint</mat-label>
<input formControlName="endpoint" matInput [placeholder]="defaultEndpoint">
</mat-form-field>
</td>
<td>
<mat-form-field class="add-server-full-width">
<mat-label>Port</mat-label>
<input formControlName="listen_port" matInput [placeholder]="defaultListenPort">
</mat-form-field>
</td>
</tr>
<tr>
<td>
<mat-form-field class="add-server-full-width">
<mat-label>Default DNS</mat-label>
<input formControlName="dns" matInput [placeholder]="defaultIPv4Address">
</mat-form-field>
</td>
<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>
<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>IPv4 Configuration</b></p>
<table class="add-server-full-width" cellspacing="0"><tr>
<td>
<mat-form-field class="add-server-full-width">
<mat-label>IPv4 Address</mat-label>
<input formControlName="address" matInput [placeholder]="defaultIPv4Address">
</mat-form-field>
</td>
<td>
<mat-form-field matLine class="add-server-full-width">
<mat-label>Subnet</mat-label>
<select matNativeControl formControlName="subnet">
<option *ngFor="let v4Subnet of v4Subnets" [value]="v4Subnet">/{{v4Subnet}}</option>
</select>
</mat-form-field>
</td>
</tr></table>
<p><b>IPv6 Configuration</b></p>
<table class="add-server-full-width" cellspacing="0"><tr>
<td>
<mat-checkbox [checked]="defaultHasIPV6Support" [value]="defaultHasIPV6Support" (change)="ipv6SupportChanged($event)">IPv6 Support</mat-checkbox>
</td>
</tr></table>
<table class="add-server-full-width" cellspacing="0"><tr>
<td>
<mat-form-field class="add-server-full-width">
<mat-label>IPv6 Address</mat-label>
<input formControlName="v6_address" matInput [placeholder]="defaultIPv6Address">
</mat-form-field>
</td>
<td>
<mat-form-field matLine class="add-server-full-width">
<mat-label>Subnet</mat-label>
<select matNativeControl formControlName="v6_subnet">
<option *ngFor="let v6Subnet of v6Subnets" [value]="v6Subnet">/{{v6Subnet}}</option>
</select>
</mat-form-field>
</td>
</tr></table>
<p><b>Key-pairs</b></p>
<div class="button-row">
<button type="button" [disabled]="!isEdit" (click)="getKeyPair()" mat-raised-button color="primary">
<i class="material-icons">vpn_key</i>
Generate KeyPair
</button>
</div>
<table class="add-server-full-width" cellspacing="0">
<tr>
<td>
<mat-form-field class="add-server-full-width">
<mat-label>Private-Key</mat-label>
<input formControlName="private_key" matInput>
</mat-form-field>
</td>
</tr>
<tr>
<td>
<mat-form-field class="add-server-full-width">
<mat-label>Public-Key</mat-label>
<input formControlName="public_key" matInput>
</mat-form-field>
</td>
</tr>
</table>
<p><b>Scripts</b></p>
<table class="add-server-full-width" cellspacing="0">
<tr>
<td>
<mat-form-field class="add-server-full-width">
<mat-label>Post-Up</mat-label>
<textarea formControlName="post_up" matInput rows="4"></textarea>
</mat-form-field>
</td>
</tr>
<tr>
<td>
<mat-form-field class="add-server-full-width">
<mat-label>Post-Down</mat-label>
<textarea formControlName="post_down" matInput rows="4"></textarea>
</mat-form-field>
</td>
</tr>
</table>
<div class="button-row">
<button mat-raised-button color="primary"
type="submit"
[disabled]="!serverForm.valid"
(click)="serverForm.valid && add(serverForm.value)"
(keydown.enter)="serverForm.valid && add(serverForm.value)"
>
<ng-container *ngIf="!isEdit">Add Server</ng-container>
<ng-container *ngIf="isEdit">Edit Server</ng-container>
</button>
<button mat-raised-button color="warn" (click)="resetForm()">
Reset
</button>
<input #confInput hidden="true" type="file" multiple onclick="this.value=null" (change)="parseFiles($event)" accept=".conf"/>
<button
mat-raised-button
color="primary"
(click)="confInput.click()"
matTooltip="Import existing wireguard configuration. You can select both server and peer configuration. The number of imported peers are described near the submit button."
>Import Configuration</button>
<div *ngIf="this.serverForm.value['peers'] && this.serverForm.value['peers'].length > 0">
Importing <b>{{this.serverForm.value['peers'].length}}</b> peers.
</div>
</div>
</form>
</mat-expansion-panel>

0
wg_dashboard_frontend/src/app/page/dashboard/add-server/add-server.component.scss → wg-manager-frontend/src/app/page/dashboard/add-server/add-server.component.scss

9
wg_dashboard_frontend/src/app/page/dashboard/add-server/add-server.component.ts → wg-manager-frontend/src/app/page/dashboard/add-server/add-server.component.ts

@ -38,8 +38,10 @@ export class AddServerComponent implements OnInit {
v4Subnets = [];
v6Subnets = [];
defaultEndpoint = "replace-me.com"
defaultListenPort = "51820"
defaultInterface = "wg0"
defaultHasIPV6Support = false;
defaultIPv4Subnet = 24;
defaultIPv6Subnet = 64;
defaultIPv4Address = "10.0.200.1"
@ -55,13 +57,14 @@ export class AddServerComponent implements OnInit {
initForm(){
this.serverForm = new FormGroup({
v6_address: new FormControl({value: this.defaultIPv6Address, disabled: !this.defaultHasIPV6Support}, [Validators.required, IPValidator.isIPAddress]),
v6_subnet: new FormControl({value: this.defaultIPv6Subnet, disabled: !this.defaultHasIPV6Support}, [Validators.required, Validators.min(1), Validators.max(64)]),
v6_support: new FormControl(this.defaultHasIPV6Support, [Validators.required]),
address: new FormControl(this.defaultIPv4Address, [Validators.required, IPValidator.isIPAddress]),
v6_address: new FormControl(this.defaultIPv6Address, [Validators.required, IPValidator.isIPAddress]),
subnet: new FormControl(this.defaultIPv4Subnet, [Validators.required, Validators.min(1), Validators.max(32)]),
v6_subnet: new FormControl(this.defaultIPv6Subnet, [Validators.required, Validators.min(1), Validators.max(64)]),
interface: new FormControl(this.defaultInterface, [Validators.required, Validators.minLength(3)]),
listen_port: new FormControl(this.defaultListenPort, [Validators.required, NumberValidator.stringIsNumber]),
endpoint: new FormControl('', Validators.required),
endpoint: new FormControl(this.defaultEndpoint, Validators.required),
dns: new FormControl(this.defaultDNS),
allowed_ips: new FormControl(this.defaultAllowedIPs),
keep_alive: new FormControl(this.defaultPersistentKeepalive),

0
wg_dashboard_frontend/src/app/page/dashboard/dashboard.component.css → wg-manager-frontend/src/app/page/dashboard/dashboard.component.css

16
wg_dashboard_frontend/src/app/page/dashboard/dashboard.component.html → wg-manager-frontend/src/app/page/dashboard/dashboard.component.html

@ -1,17 +1,19 @@
<div
fxFlexFill
fxLayout="row"
fxLayout="column"
fxLayout.lt-lg="column"
style="padding: 10px;"
fxLayoutGap="20px">
style="padding: 10px;" fxLayoutGap="20px">
<div fxFlex="65">
<app-server [(server)]="servers[idx]" [(servers)]="servers" *ngFor="let server of servers; let idx = index"></app-server>
<div fxFlex="100">
<app-add-server [(servers)]="servers"></app-add-server>
</div>
<div fxFlex="35">
<app-add-server [(servers)]="servers"></app-add-server>
<div fxFlex="100">
<app-server [(server)]="servers[idx]" [(servers)]="servers" *ngFor="let server of servers; let idx = index"></app-server>
</div>
</div>

0
wg_dashboard_frontend/src/app/page/dashboard/dashboard.component.ts → wg-manager-frontend/src/app/page/dashboard/dashboard.component.ts

0
wg_dashboard_frontend/src/app/page/dashboard/dashboard.module.ts → wg-manager-frontend/src/app/page/dashboard/dashboard.module.ts

0
wg_dashboard_frontend/src/app/page/dashboard/peer/peer.component.html → wg-manager-frontend/src/app/page/dashboard/peer/peer.component.html

0
wg_dashboard_frontend/src/app/page/dashboard/peer/peer.component.scss → wg-manager-frontend/src/app/page/dashboard/peer/peer.component.scss

0
wg_dashboard_frontend/src/app/page/dashboard/peer/peer.component.ts → wg-manager-frontend/src/app/page/dashboard/peer/peer.component.ts

0
wg_dashboard_frontend/src/app/page/dashboard/server/server.component.html → wg-manager-frontend/src/app/page/dashboard/server/server.component.html

0
wg_dashboard_frontend/src/app/page/dashboard/server/server.component.scss → wg-manager-frontend/src/app/page/dashboard/server/server.component.scss

0
wg_dashboard_frontend/src/app/page/dashboard/server/server.component.ts → wg-manager-frontend/src/app/page/dashboard/server/server.component.ts

0
wg_dashboard_frontend/src/app/page/error/error.component.css → wg-manager-frontend/src/app/page/error/error.component.css

0
wg_dashboard_frontend/src/app/page/error/error.component.html → wg-manager-frontend/src/app/page/error/error.component.html

0
wg_dashboard_frontend/src/app/page/error/error.component.ts → wg-manager-frontend/src/app/page/error/error.component.ts

0
wg_dashboard_frontend/src/app/page/error/index.ts → wg-manager-frontend/src/app/page/error/index.ts

0
wg_dashboard_frontend/src/app/page/page-routing.module.ts → wg-manager-frontend/src/app/page/page-routing.module.ts

0
wg_dashboard_frontend/src/app/page/page.module.ts → wg-manager-frontend/src/app/page/page.module.ts

0
wg_dashboard_frontend/src/app/page/user/edit/api-key/api-key.component.html → wg-manager-frontend/src/app/page/user/edit/api-key/api-key.component.html

0
wg_dashboard_frontend/src/app/page/user/edit/api-key/api-key.component.scss → wg-manager-frontend/src/app/page/user/edit/api-key/api-key.component.scss

0
wg_dashboard_frontend/src/app/page/user/edit/api-key/api-key.component.spec.ts → wg-manager-frontend/src/app/page/user/edit/api-key/api-key.component.spec.ts

0
wg_dashboard_frontend/src/app/page/user/edit/api-key/api-key.component.ts → wg-manager-frontend/src/app/page/user/edit/api-key/api-key.component.ts

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save