V2 alpha - initial version (#172)

Initial alpha codebase for version 2 of WireGuard Portal.
This version is considered unstable and incomplete (for example, no public REST API)! 
Use with care!


Fixes/Implements the following issues:
 - OAuth support #154, #1 
 - New Web UI with internationalisation support #98, #107, #89, #62
 - Postgres Support #49 
 - Improved Email handling #47, #119 
 - DNS Search Domain support #46 
 - Bugfixes #94, #48 

---------

Co-authored-by: Fabian Wechselberger <wechselbergerf@hotmail.com>
This commit is contained in:
h44z
2023-08-04 13:34:18 +02:00
committed by GitHub
parent b3a5f2ac60
commit 8b820a5adf
788 changed files with 46139 additions and 11281 deletions

View File

@@ -0,0 +1,7 @@
export function base64_url_encode(input) {
let output = btoa(input)
output = output.replace('+', '.')
output = output.replace('/', '_')
output = output.replace('=', '-')
return output
}

View File

@@ -0,0 +1,95 @@
import { authStore } from '@/stores/auth';
import { securityStore } from '@/stores/security';
export const fetchWrapper = {
url: apiUrl(),
get: request('GET'),
post: request('POST'),
put: request('PUT'),
delete: request('DELETE')
};
export const apiWrapper = {
url: apiUrl(),
get: apiRequest('GET'),
post: apiRequest('POST'),
put: apiRequest('PUT'),
delete: apiRequest('DELETE')
};
// request can be used to query arbitrary URLs
function request(method) {
return (url, body = undefined) => {
const requestOptions = {
method,
headers: getHeaders(url)
};
if (body) {
requestOptions.headers['Content-Type'] = 'application/json';
requestOptions.body = JSON.stringify(body);
}
return fetch(url, requestOptions).then(handleResponse);
}
}
// apiRequest uses WGPORTAL_BACKEND_BASE_URL as base URL
function apiRequest(method) {
return (path, body = undefined) => {
const url = WGPORTAL_BACKEND_BASE_URL + path
const requestOptions = {
method,
headers: getHeaders(method, url)
};
if (body) {
requestOptions.headers['Content-Type'] = 'application/json';
requestOptions.body = JSON.stringify(body);
}
return fetch(url, requestOptions).then(handleResponse);
}
}
// apiUrl uses WGPORTAL_BACKEND_BASE_URL as base URL
function apiUrl() {
return (path) => {
return WGPORTAL_BACKEND_BASE_URL + path
}
}
// helper functions
function getHeaders(method, url) {
// return auth header with jwt if user is logged in and request is to the api url
const auth = authStore();
const sec = securityStore();
const isApiUrl = url.startsWith(WGPORTAL_BACKEND_BASE_URL);
let headers = {};
if (isApiUrl && ['POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) {
headers["X-CSRF-TOKEN"] = sec.CsrfToken;
}
if (isApiUrl && auth.IsAuthenticated) {
headers["X-FRONTEND-UID"] = auth.UserIdentifier;
}
return headers;
}
function handleResponse(response) {
return response.text().then(text => {
const data = text && JSON.parse(text);
if (!response.ok) {
const auth = authStore();
if ([401, 403].includes(response.status) && auth.IsAuthenticated) {
console.log("automatic logout initiated...");
// auto logout if 401 Unauthorized or 403 Forbidden response returned from api
auth.Logout();
}
const error = (data && data.Message) || response.statusText;
return Promise.reject(error);
}
return data;
});
}

View File

@@ -0,0 +1,164 @@
export function freshInterface() {
return {
Disabled: false,
DisplayName: "",
Identifier: "",
Mode: "server",
PublicKey: "",
PrivateKey: "",
ListenPort: 51820,
Addresses: [],
DnsStr: [],
DnsSearch: [],
Mtu: 0,
FirewallMark: 0,
RoutingTable: "",
PreUp: "",
PostUp: "",
PreDown: "",
PostDown: "",
SaveConfig: false,
// Peer defaults
PeerDefNetwork: [],
PeerDefDns: [],
PeerDefDnsSearch: [],
PeerDefEndpoint: "",
PeerDefAllowedIPs: [],
PeerDefMtu: 0,
PeerDefPersistentKeepalive: 0,
PeerDefFirewallMark: 0,
PeerDefRoutingTable: "",
PeerDefPreUp: "",
PeerDefPostUp: "",
PeerDefPreDown: "",
PeerDefPostDown: "",
TotalPeers: 0,
EnabledPeers: 0
}
}
export function freshPeer() {
return {
Identifier: "",
DisplayName: "",
UserIdentifier: "",
InterfaceIdentifier: "",
Disabled: false,
ExpiresAt: null,
Notes: "",
Endpoint: {
Value: "",
Overridable: true,
},
EndpointPublicKey: {
Value: "",
Overridable: true,
},
AllowedIPs: {
Value: [],
Overridable: true,
},
ExtraAllowedIPs: [],
PresharedKey: "",
PersistentKeepalive: {
Value: 0,
Overridable: true,
},
PrivateKey: "",
PublicKey: "",
Mode: "client",
Addresses: [],
CheckAliveAddress: "",
Dns: {
Value: [],
Overridable: true,
},
DnsSearch: {
Value: [],
Overridable: true,
},
Mtu: {
Value: 0,
Overridable: true,
},
FirewallMark: {
Value: 0,
Overridable: true,
},
RoutingTable: {
Value: "",
Overridable: true,
},
PreUp: {
Value: "",
Overridable: true,
},
PostUp: {
Value: "",
Overridable: true,
},
PreDown: {
Value: "",
Overridable: true,
},
PostDown: {
Value: "",
Overridable: true,
},
// Internal value
IgnoreGlobalSettings: false
}
}
export function freshUser() {
return {
Identifier: "",
Email: "",
Source: "db",
IsAdmin: false,
Firstname: "",
Lastname: "",
Phone: "",
Department: "",
Notes: "",
Password: "",
Disabled: false,
DisabledReason: "",
Locked: false,
LockedReason: "",
PeerCount: 0
}
}
export function freshStats() {
return {
IsConnected: false,
IsPingable: false,
LastHandshake: null,
LastPing: null,
LastSessionStart: null,
BytesTransmitted: 0,
BytesReceived: 0,
EndpointAddress: ""
}
}

View File

@@ -0,0 +1,14 @@
import isCidr from "is-cidr";
import {isIP} from 'is-ip';
export function validateCIDR(value) {
return isCidr(value) !== 0
}
export function validateIP(value) {
return isIP(value)
}
export function validateDomain(value) {
return true
}