mirror of
https://github.com/h44z/wg-portal.git
synced 2025-08-10 23:42:24 +00:00
peer config and qr code
This commit is contained in:
parent
4a53a5207a
commit
9fdb8d8633
@ -36,7 +36,7 @@ const title = computed(() => {
|
|||||||
watch(() => props.visible, async (newValue, oldValue) => {
|
watch(() => props.visible, async (newValue, oldValue) => {
|
||||||
if (oldValue === false && newValue === true) { // if modal is shown
|
if (oldValue === false && newValue === true) { // if modal is shown
|
||||||
console.log(selectedInterface.value)
|
console.log(selectedInterface.value)
|
||||||
await interfaces.InterfaceConfig(selectedInterface.value.Identifier)
|
await interfaces.LoadInterfaceConfig(selectedInterface.value.Identifier)
|
||||||
configString.value = interfaces.configuration
|
configString.value = interfaces.configuration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import Vue3TagsInput from "vue3-tags-input";
|
|||||||
import { validateCIDR, validateIP, validateDomain } from '@/helpers/validators';
|
import { validateCIDR, validateIP, validateDomain } from '@/helpers/validators';
|
||||||
import isCidr from "is-cidr";
|
import isCidr from "is-cidr";
|
||||||
import {isIP} from 'is-ip';
|
import {isIP} from 'is-ip';
|
||||||
import { freshPeer } from '@/helpers/models';
|
import { freshPeer, freshInterface } from '@/helpers/models';
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
@ -31,10 +31,7 @@ const selectedInterface = computed(() => {
|
|||||||
let i = interfaces.GetSelected;
|
let i = interfaces.GetSelected;
|
||||||
|
|
||||||
if (!i) {
|
if (!i) {
|
||||||
i = { // dummy interface to avoid 'undefined' exceptions
|
i = freshInterface() // dummy interface to avoid 'undefined' exceptions
|
||||||
Identifier: "none",
|
|
||||||
Mode: "server"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return i
|
return i
|
||||||
|
@ -2,7 +2,12 @@
|
|||||||
import Modal from "./Modal.vue";
|
import Modal from "./Modal.vue";
|
||||||
import {peerStore} from "@/stores/peers";
|
import {peerStore} from "@/stores/peers";
|
||||||
import {interfaceStore} from "@/stores/interfaces";
|
import {interfaceStore} from "@/stores/interfaces";
|
||||||
import {computed} from "vue";
|
import {computed, ref, watch} from "vue";
|
||||||
|
import {useI18n} from "vue-i18n";
|
||||||
|
import { freshInterface, freshPeer } from '@/helpers/models';
|
||||||
|
import Prism from "vue-prism-component";
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
const peers = peerStore()
|
const peers = peerStore()
|
||||||
const interfaces = interfaceStore()
|
const interfaces = interfaceStore()
|
||||||
@ -18,30 +23,49 @@ function close() {
|
|||||||
emit('close')
|
emit('close')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const configString = ref("")
|
||||||
|
|
||||||
const selectedPeer = computed(() => {
|
const selectedPeer = computed(() => {
|
||||||
return peers.Find(props.peerId)
|
let p = peers.Find(props.peerId)
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
p = freshPeer() // dummy peer to avoid 'undefined' exceptions
|
||||||
|
}
|
||||||
|
|
||||||
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
const selectedInterface = computed(() => {
|
const selectedInterface = computed(() => {
|
||||||
let i = interfaces.GetSelected;
|
let i = interfaces.GetSelected;
|
||||||
|
|
||||||
if (!i) {
|
if (!i) {
|
||||||
i = { // dummy interface to avoid 'undefined' exceptions
|
i = freshInterface() // dummy interface to avoid 'undefined' exceptions
|
||||||
Identifier: "none",
|
|
||||||
Mode: "server"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return i
|
return i
|
||||||
})
|
})
|
||||||
|
|
||||||
const title = computed(() => {
|
const title = computed(() => {
|
||||||
if (selectedPeer.value) {
|
if (!props.visible) {
|
||||||
return "Peer: " + selectedPeer.value.Name
|
return "" // otherwise interfaces.GetSelected will die...
|
||||||
|
}
|
||||||
|
if (selectedInterface.value.Mode === "server") {
|
||||||
|
return t("interfaces.peer.view") + ": " + selectedPeer.value.DisplayName
|
||||||
|
} else {
|
||||||
|
return t("interfaces.endpoint.view") + ": " + selectedPeer.value.DisplayName
|
||||||
}
|
}
|
||||||
return ""
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(() => props.visible, async (newValue, oldValue) => {
|
||||||
|
if (oldValue === false && newValue === true) { // if modal is shown
|
||||||
|
console.log(selectedInterface.value)
|
||||||
|
console.log(selectedPeer.value)
|
||||||
|
await peers.LoadPeerConfig(selectedPeer.value.Identifier)
|
||||||
|
configString.value = peers.configuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -60,16 +84,16 @@ const title = computed(() => {
|
|||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<h4>Details</h4>
|
<h4>Details</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Firstname: Some</li>
|
<li>Identifier: {{ selectedPeer.PublicKey }}</li>
|
||||||
<li>Lastname: Username</li>
|
<li>IP Addresses: <span v-for="ip in selectedPeer.Addresses" :key="ip" class="badge rounded-pill bg-light">{{ ip }}</span></li>
|
||||||
<li>Phone: 123456789</li>
|
<li>Linked User: {{ selectedPeer.UserIdentifier }}</li>
|
||||||
<li>Mail: x@y.de</li>
|
<li>Notes: {{ selectedPeer.Notes }}</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h4>Traffic</h4>
|
<h4>Traffic</h4>
|
||||||
<p><i class="fas fa-long-arrow-alt-down"></i> 1.5 MB / <i class="fas fa-long-arrow-alt-up"></i> 3.9 MB</p>
|
<p><i class="fas fa-long-arrow-alt-down"></i> 1.5 MB / <i class="fas fa-long-arrow-alt-up"></i> 3.9 MB</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<img class="config-qr-img" src="https://hexdocs.pm/qr_code/docs/qrcode.svg">
|
<img class="config-qr-img" :src="peers.ConfigQrUrl(props.peerId)" loading="lazy" alt="Configuration QR Code">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -83,28 +107,7 @@ const title = computed(() => {
|
|||||||
</h2>
|
</h2>
|
||||||
<div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="headingTwo" data-bs-parent="#accordionExample" style="">
|
<div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="headingTwo" data-bs-parent="#accordionExample" style="">
|
||||||
<div class="accordion-body">
|
<div class="accordion-body">
|
||||||
<pre>
|
<Prism language="ini" :code="configString"></Prism>
|
||||||
# AUTOGENERATED FILE - PROVIDED BY WIREGUARD PORTAL
|
|
||||||
# WireGuard configuration: Some username (Home)
|
|
||||||
# -WGP- PublicKey: xyz123
|
|
||||||
|
|
||||||
[Interface]
|
|
||||||
|
|
||||||
# Core settings
|
|
||||||
PrivateKey = abcd2131234
|
|
||||||
Address = 10.6.6.3/32, fd9f:6666::3/128
|
|
||||||
|
|
||||||
# Misc. settings (optional)
|
|
||||||
DNS = 10.10.1.20, fd9f:6666::10:6:6:1
|
|
||||||
MTU = 1380
|
|
||||||
|
|
||||||
[Peer]
|
|
||||||
PublicKey = oidjsfgsp9oih23
|
|
||||||
Endpoint = vpn.server.de:51820
|
|
||||||
AllowedIPs = 10.6.6.0/24, 10.10.0.0/16, 10.12.0.0/16, fd9f:6666::/64
|
|
||||||
PresharedKey = +1FPHPdsfjkln23
|
|
||||||
PersistentKeepalive = 16
|
|
||||||
</pre>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
7
frontend/src/helpers/encoding.js
Normal file
7
frontend/src/helpers/encoding.js
Normal 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
|
||||||
|
}
|
@ -2,6 +2,7 @@ import { authStore } from '../stores/auth';
|
|||||||
import { securityStore } from '../stores/security';
|
import { securityStore } from '../stores/security';
|
||||||
|
|
||||||
export const fetchWrapper = {
|
export const fetchWrapper = {
|
||||||
|
url: apiUrl(),
|
||||||
get: request('GET'),
|
get: request('GET'),
|
||||||
post: request('POST'),
|
post: request('POST'),
|
||||||
put: request('PUT'),
|
put: request('PUT'),
|
||||||
@ -9,6 +10,7 @@ export const fetchWrapper = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const apiWrapper = {
|
export const apiWrapper = {
|
||||||
|
url: apiUrl(),
|
||||||
get: apiRequest('GET'),
|
get: apiRequest('GET'),
|
||||||
post: apiRequest('POST'),
|
post: apiRequest('POST'),
|
||||||
put: apiRequest('PUT'),
|
put: apiRequest('PUT'),
|
||||||
@ -46,6 +48,13 @@ function apiRequest(method) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// apiUrl uses WGPORTAL_BACKEND_BASE_URL as base URL
|
||||||
|
function apiUrl() {
|
||||||
|
return (path) => {
|
||||||
|
return WGPORTAL_BACKEND_BASE_URL + path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// helper functions
|
// helper functions
|
||||||
|
|
||||||
function getHeaders(method, url) {
|
function getHeaders(method, url) {
|
||||||
|
@ -54,9 +54,8 @@
|
|||||||
"h2-client": "Aktuelle Endpunkte",
|
"h2-client": "Aktuelle Endpunkte",
|
||||||
"tableHeadings": [
|
"tableHeadings": [
|
||||||
"Name",
|
"Name",
|
||||||
"Kennung",
|
|
||||||
"Benutzer",
|
"Benutzer",
|
||||||
"IPs",
|
"IP's",
|
||||||
"Endpunkt",
|
"Endpunkt",
|
||||||
"Handschlag"
|
"Handschlag"
|
||||||
],
|
],
|
||||||
|
@ -51,9 +51,8 @@
|
|||||||
"h2-client": "Current Endpoints",
|
"h2-client": "Current Endpoints",
|
||||||
"tableHeadings": [
|
"tableHeadings": [
|
||||||
"Name",
|
"Name",
|
||||||
"Identifier",
|
|
||||||
"User",
|
"User",
|
||||||
"IPs",
|
"IP's",
|
||||||
"Endpoint",
|
"Endpoint",
|
||||||
"Handshake"
|
"Handshake"
|
||||||
],
|
],
|
||||||
|
@ -3,6 +3,7 @@ import { defineStore } from 'pinia'
|
|||||||
import {apiWrapper} from '@/helpers/fetch-wrapper'
|
import {apiWrapper} from '@/helpers/fetch-wrapper'
|
||||||
import {notify} from "@kyvg/vue3-notification";
|
import {notify} from "@kyvg/vue3-notification";
|
||||||
import { freshInterface } from '@/helpers/models';
|
import { freshInterface } from '@/helpers/models';
|
||||||
|
import { base64_url_encode } from '@/helpers/encoding';
|
||||||
|
|
||||||
const baseUrl = `/interface`
|
const baseUrl = `/interface`
|
||||||
|
|
||||||
@ -66,11 +67,11 @@ export const interfaceStore = defineStore({
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
async InterfaceConfig(id) {
|
async LoadInterfaceConfig(id) {
|
||||||
return apiWrapper.get(`${baseUrl}/config/${encodeURIComponent(id)}`)
|
return apiWrapper.get(`${baseUrl}/config/${base64_url_encode(id)}`)
|
||||||
.then(this.setInterfaceConfig)
|
.then(this.setInterfaceConfig)
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
this.prepared = {}
|
this.configuration = ""
|
||||||
console.log("Failed to load interface configuration: ", error)
|
console.log("Failed to load interface configuration: ", error)
|
||||||
notify({
|
notify({
|
||||||
title: "Backend Connection Failure",
|
title: "Backend Connection Failure",
|
||||||
@ -80,7 +81,7 @@ export const interfaceStore = defineStore({
|
|||||||
},
|
},
|
||||||
async DeleteInterface(id) {
|
async DeleteInterface(id) {
|
||||||
this.fetching = true
|
this.fetching = true
|
||||||
return apiWrapper.delete(`${baseUrl}/${encodeURIComponent(id)}`)
|
return apiWrapper.delete(`${baseUrl}/${base64_url_encode(id)}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.interfaces = this.interfaces.filter(i => i.Identifier !== id)
|
this.interfaces = this.interfaces.filter(i => i.Identifier !== id)
|
||||||
if (this.interfaces.length > 0) {
|
if (this.interfaces.length > 0) {
|
||||||
@ -98,7 +99,7 @@ export const interfaceStore = defineStore({
|
|||||||
},
|
},
|
||||||
async UpdateInterface(id, formData) {
|
async UpdateInterface(id, formData) {
|
||||||
this.fetching = true
|
this.fetching = true
|
||||||
return apiWrapper.put(`${baseUrl}/${encodeURIComponent(id)}`, formData)
|
return apiWrapper.put(`${baseUrl}/${base64_url_encode(id)}`, formData)
|
||||||
.then(iface => {
|
.then(iface => {
|
||||||
let idx = this.interfaces.findIndex((i) => i.Identifier === id)
|
let idx = this.interfaces.findIndex((i) => i.Identifier === id)
|
||||||
this.interfaces[idx] = iface
|
this.interfaces[idx] = iface
|
||||||
|
@ -3,6 +3,7 @@ import {apiWrapper} from "../helpers/fetch-wrapper";
|
|||||||
import {notify} from "@kyvg/vue3-notification";
|
import {notify} from "@kyvg/vue3-notification";
|
||||||
import {interfaceStore} from "./interfaces";
|
import {interfaceStore} from "./interfaces";
|
||||||
import { freshPeer } from '@/helpers/models';
|
import { freshPeer } from '@/helpers/models';
|
||||||
|
import { base64_url_encode } from '@/helpers/encoding';
|
||||||
|
|
||||||
const baseUrl = `/peer`
|
const baseUrl = `/peer`
|
||||||
|
|
||||||
@ -12,6 +13,7 @@ export const peerStore = defineStore({
|
|||||||
peers: [],
|
peers: [],
|
||||||
peer: freshPeer(),
|
peer: freshPeer(),
|
||||||
prepared: freshPeer(),
|
prepared: freshPeer(),
|
||||||
|
configuration: "",
|
||||||
filter: "",
|
filter: "",
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
pageOffset: 0,
|
pageOffset: 0,
|
||||||
@ -37,6 +39,9 @@ export const peerStore = defineStore({
|
|||||||
FilteredAndPaged: (state) => {
|
FilteredAndPaged: (state) => {
|
||||||
return state.Filtered.slice(state.pageOffset, state.pageOffset + state.pageSize)
|
return state.Filtered.slice(state.pageOffset, state.pageOffset + state.pageSize)
|
||||||
},
|
},
|
||||||
|
ConfigQrUrl: (state) => {
|
||||||
|
return (id) => apiWrapper.url(`${baseUrl}/config-qr/${base64_url_encode(id)}`)
|
||||||
|
},
|
||||||
isFetching: (state) => state.fetching,
|
isFetching: (state) => state.fetching,
|
||||||
hasNextPage: (state) => state.pageOffset < (state.FilteredCount - state.pageSize),
|
hasNextPage: (state) => state.pageOffset < (state.FilteredCount - state.pageSize),
|
||||||
hasPrevPage: (state) => state.pageOffset > 0,
|
hasPrevPage: (state) => state.pageOffset > 0,
|
||||||
@ -82,8 +87,11 @@ export const peerStore = defineStore({
|
|||||||
setPreparedPeer(peer) {
|
setPreparedPeer(peer) {
|
||||||
this.prepared = peer;
|
this.prepared = peer;
|
||||||
},
|
},
|
||||||
|
setPeerConfig(config) {
|
||||||
|
this.configuration = config;
|
||||||
|
},
|
||||||
async PreparePeer(interfaceId) {
|
async PreparePeer(interfaceId) {
|
||||||
return apiWrapper.get(`${baseUrl}/iface/${encodeURIComponent(interfaceId)}/prepare`)
|
return apiWrapper.get(`${baseUrl}/iface/${base64_url_encode(interfaceId)}/prepare`)
|
||||||
.then(this.setPreparedPeer)
|
.then(this.setPreparedPeer)
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
this.prepared = freshPeer()
|
this.prepared = freshPeer()
|
||||||
@ -94,9 +102,21 @@ export const peerStore = defineStore({
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
async LoadPeerConfig(id) {
|
||||||
|
return apiWrapper.get(`${baseUrl}/config/${base64_url_encode(id)}`)
|
||||||
|
.then(this.setPeerConfig)
|
||||||
|
.catch(error => {
|
||||||
|
this.configuration = ""
|
||||||
|
console.log("Failed to load peer configuration: ", error)
|
||||||
|
notify({
|
||||||
|
title: "Backend Connection Failure",
|
||||||
|
text: "Failed to load peer configuration!",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
async LoadPeer(id) {
|
async LoadPeer(id) {
|
||||||
this.fetching = true
|
this.fetching = true
|
||||||
return apiWrapper.get(`${baseUrl}/${encodeURIComponent(id)}`)
|
return apiWrapper.get(`${baseUrl}/${base64_url_encode(id)}`)
|
||||||
.then(this.setPeer)
|
.then(this.setPeer)
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
this.setPeers([])
|
this.setPeers([])
|
||||||
@ -109,7 +129,7 @@ export const peerStore = defineStore({
|
|||||||
},
|
},
|
||||||
async DeletePeer(id) {
|
async DeletePeer(id) {
|
||||||
this.fetching = true
|
this.fetching = true
|
||||||
return apiWrapper.delete(`${baseUrl}/${encodeURIComponent(id)}`)
|
return apiWrapper.delete(`${baseUrl}/${base64_url_encode(id)}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.peers = this.peers.filter(p => p.Identifier !== id)
|
this.peers = this.peers.filter(p => p.Identifier !== id)
|
||||||
this.fetching = false
|
this.fetching = false
|
||||||
@ -122,7 +142,7 @@ export const peerStore = defineStore({
|
|||||||
},
|
},
|
||||||
async UpdatePeer(id, formData) {
|
async UpdatePeer(id, formData) {
|
||||||
this.fetching = true
|
this.fetching = true
|
||||||
return apiWrapper.put(`${baseUrl}/${encodeURIComponent(id)}`, formData)
|
return apiWrapper.put(`${baseUrl}/${base64_url_encode(id)}`, formData)
|
||||||
.then(peer => {
|
.then(peer => {
|
||||||
let idx = this.peers.findIndex((p) => p.Identifier === id)
|
let idx = this.peers.findIndex((p) => p.Identifier === id)
|
||||||
this.peers[idx] = peer
|
this.peers[idx] = peer
|
||||||
@ -136,7 +156,7 @@ export const peerStore = defineStore({
|
|||||||
},
|
},
|
||||||
async CreatePeer(interfaceId, formData) {
|
async CreatePeer(interfaceId, formData) {
|
||||||
this.fetching = true
|
this.fetching = true
|
||||||
return apiWrapper.post(`${baseUrl}/iface/${encodeURIComponent(interfaceId)}/new`, formData)
|
return apiWrapper.post(`${baseUrl}/iface/${base64_url_encode(interfaceId)}/new`, formData)
|
||||||
.then(peer => {
|
.then(peer => {
|
||||||
this.peers.push(peer)
|
this.peers.push(peer)
|
||||||
this.fetching = false
|
this.fetching = false
|
||||||
@ -157,7 +177,7 @@ export const peerStore = defineStore({
|
|||||||
}
|
}
|
||||||
this.fetching = true
|
this.fetching = true
|
||||||
|
|
||||||
return apiWrapper.get(`${baseUrl}/iface/${encodeURIComponent(interfaceId)}/all`)
|
return apiWrapper.get(`${baseUrl}/iface/${base64_url_encode(interfaceId)}/all`)
|
||||||
.then(this.setPeers)
|
.then(this.setPeers)
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
this.setPeers([])
|
this.setPeers([])
|
||||||
|
@ -2,6 +2,7 @@ import { defineStore } from 'pinia'
|
|||||||
import {apiWrapper} from "@/helpers/fetch-wrapper";
|
import {apiWrapper} from "@/helpers/fetch-wrapper";
|
||||||
import {notify} from "@kyvg/vue3-notification";
|
import {notify} from "@kyvg/vue3-notification";
|
||||||
import {authStore} from "@/stores/auth";
|
import {authStore} from "@/stores/auth";
|
||||||
|
import { base64_url_encode } from '@/helpers/encoding';
|
||||||
|
|
||||||
|
|
||||||
const baseUrl = `/user`
|
const baseUrl = `/user`
|
||||||
@ -79,7 +80,7 @@ export const profileStore = defineStore({
|
|||||||
async LoadPeers() {
|
async LoadPeers() {
|
||||||
this.fetching = true
|
this.fetching = true
|
||||||
let currentUser = authStore().user.Identifier
|
let currentUser = authStore().user.Identifier
|
||||||
return apiWrapper.get(`${baseUrl}/${encodeURIComponent(currentUser)}/peers`)
|
return apiWrapper.get(`${baseUrl}/${base64_url_encode(currentUser)}/peers`)
|
||||||
.then(this.setPeers)
|
.then(this.setPeers)
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
this.setPeers([])
|
this.setPeers([])
|
||||||
@ -93,7 +94,7 @@ export const profileStore = defineStore({
|
|||||||
async LoadUser() {
|
async LoadUser() {
|
||||||
this.fetching = true
|
this.fetching = true
|
||||||
let currentUser = authStore().user.Identifier
|
let currentUser = authStore().user.Identifier
|
||||||
return apiWrapper.get(`${baseUrl}/${encodeURIComponent(currentUser)}`)
|
return apiWrapper.get(`${baseUrl}/${base64_url_encode(currentUser)}`)
|
||||||
.then(this.setUser)
|
.then(this.setUser)
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
this.setUser({})
|
this.setUser({})
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import {apiWrapper} from "@/helpers/fetch-wrapper";
|
import {apiWrapper} from "@/helpers/fetch-wrapper";
|
||||||
import {notify} from "@kyvg/vue3-notification";
|
import {notify} from "@kyvg/vue3-notification";
|
||||||
|
import { base64_url_encode } from '@/helpers/encoding';
|
||||||
|
|
||||||
const baseUrl = `/user`
|
const baseUrl = `/user`
|
||||||
|
|
||||||
@ -91,7 +92,7 @@ export const userStore = defineStore({
|
|||||||
},
|
},
|
||||||
async DeleteUser(id) {
|
async DeleteUser(id) {
|
||||||
this.fetching = true
|
this.fetching = true
|
||||||
return apiWrapper.delete(`${baseUrl}/${encodeURIComponent(id)}`)
|
return apiWrapper.delete(`${baseUrl}/${base64_url_encode(id)}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.users = this.users.filter(u => u.Identifier !== id)
|
this.users = this.users.filter(u => u.Identifier !== id)
|
||||||
this.fetching = false
|
this.fetching = false
|
||||||
@ -104,7 +105,7 @@ export const userStore = defineStore({
|
|||||||
},
|
},
|
||||||
async UpdateUser(id, formData) {
|
async UpdateUser(id, formData) {
|
||||||
this.fetching = true
|
this.fetching = true
|
||||||
return apiWrapper.put(`${baseUrl}/${encodeURIComponent(id)}`, formData)
|
return apiWrapper.put(`${baseUrl}/${base64_url_encode(id)}`, formData)
|
||||||
.then(user => {
|
.then(user => {
|
||||||
let idx = this.users.findIndex((u) => u.Identifier === id)
|
let idx = this.users.findIndex((u) => u.Identifier === id)
|
||||||
this.users[idx] = user
|
this.users[idx] = user
|
||||||
@ -131,7 +132,7 @@ export const userStore = defineStore({
|
|||||||
},
|
},
|
||||||
async LoadUserPeers(id) {
|
async LoadUserPeers(id) {
|
||||||
this.fetching = true
|
this.fetching = true
|
||||||
return apiWrapper.get(`${baseUrl}/${encodeURIComponent(id)}/peers`)
|
return apiWrapper.get(`${baseUrl}/${base64_url_encode(id)}/peers`)
|
||||||
.then(this.setUserPeers)
|
.then(this.setUserPeers)
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
this.setUserPeers([])
|
this.setUserPeers([])
|
||||||
|
@ -272,9 +272,8 @@ onMounted(async () => {
|
|||||||
<th scope="col">{{ $t('interfaces.tableHeadings[0]') }}</th>
|
<th scope="col">{{ $t('interfaces.tableHeadings[0]') }}</th>
|
||||||
<th scope="col">{{ $t('interfaces.tableHeadings[1]') }}</th>
|
<th scope="col">{{ $t('interfaces.tableHeadings[1]') }}</th>
|
||||||
<th scope="col">{{ $t('interfaces.tableHeadings[2]') }}</th>
|
<th scope="col">{{ $t('interfaces.tableHeadings[2]') }}</th>
|
||||||
<th scope="col">{{ $t('interfaces.tableHeadings[3]') }}</th>
|
<th v-if="interfaces.GetSelected.Mode==='client'" scope="col">{{ $t('interfaces.tableHeadings[3]') }}</th>
|
||||||
<th v-if="interfaces.GetSelected.Mode==='client'" scope="col">{{ $t('interfaces.tableHeadings[4]') }}</th>
|
<th scope="col">{{ $t('interfaces.tableHeadings[4]') }}</th>
|
||||||
<th scope="col">{{ $t('interfaces.tableHeadings[5]') }}</th>
|
|
||||||
<th scope="col"></th><!-- Actions -->
|
<th scope="col"></th><!-- Actions -->
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -284,10 +283,9 @@ onMounted(async () => {
|
|||||||
<input id="flexCheckDefault" class="form-check-input" type="checkbox" value="">
|
<input id="flexCheckDefault" class="form-check-input" type="checkbox" value="">
|
||||||
</th>
|
</th>
|
||||||
<td>{{peer.DisplayName}}</td>
|
<td>{{peer.DisplayName}}</td>
|
||||||
<td>{{peer.Identifier}}</td>
|
|
||||||
<td>{{peer.UserIdentifier}}</td>
|
<td>{{peer.UserIdentifier}}</td>
|
||||||
<td>
|
<td>
|
||||||
<span v-for="ip in peer.Addresses" :key="ip" class="badge rounded-pill bg-light">{{ ip }}</span>
|
<span v-for="ip in peer.Addresses" :key="ip" class="badge bg-light me-1">{{ ip }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td v-if="interfaces.GetSelected.Mode==='client'">{{peer.Endpoint.Value}}</td>
|
<td v-if="interfaces.GetSelected.Mode==='client'">{{peer.Endpoint.Value}}</td>
|
||||||
<td>{{peer.LastConnected}}</td>
|
<td>{{peer.LastConnected}}</td>
|
||||||
|
7
go.mod
7
go.mod
@ -19,6 +19,8 @@ require (
|
|||||||
github.com/vardius/message-bus v1.1.5
|
github.com/vardius/message-bus v1.1.5
|
||||||
github.com/vishvananda/netlink v1.1.0
|
github.com/vishvananda/netlink v1.1.0
|
||||||
github.com/xhit/go-simple-mail/v2 v2.13.0
|
github.com/xhit/go-simple-mail/v2 v2.13.0
|
||||||
|
github.com/yeqown/go-qrcode/v2 v2.2.1
|
||||||
|
github.com/yeqown/go-qrcode/writer/standard v1.2.1
|
||||||
golang.org/x/crypto v0.10.0
|
golang.org/x/crypto v0.10.0
|
||||||
golang.org/x/oauth2 v0.9.0
|
golang.org/x/oauth2 v0.9.0
|
||||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||||
@ -37,6 +39,7 @@ require (
|
|||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/dchest/uniuri v1.2.0 // indirect
|
github.com/dchest/uniuri v1.2.0 // indirect
|
||||||
|
github.com/fogleman/gg v1.3.0 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
||||||
@ -53,6 +56,7 @@ require (
|
|||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
@ -79,6 +83,7 @@ require (
|
|||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b // indirect
|
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b // indirect
|
||||||
github.com/stretchr/objx v0.5.0 // indirect
|
github.com/stretchr/objx v0.5.0 // indirect
|
||||||
@ -86,7 +91,9 @@ require (
|
|||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||||
github.com/vishvananda/netns v0.0.4 // indirect
|
github.com/vishvananda/netns v0.0.4 // indirect
|
||||||
|
github.com/yeqown/reedsolomon v1.0.0 // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
|
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 // indirect
|
||||||
golang.org/x/net v0.11.0 // indirect
|
golang.org/x/net v0.11.0 // indirect
|
||||||
golang.org/x/sync v0.3.0 // indirect
|
golang.org/x/sync v0.3.0 // indirect
|
||||||
golang.org/x/sys v0.9.0 // indirect
|
golang.org/x/sys v0.9.0 // indirect
|
||||||
|
14
go.sum
14
go.sum
@ -28,6 +28,8 @@ github.com/dchest/uniuri v1.2.0 h1:koIcOUdrTIivZgSLhHQvKgqdWZq5d7KdMEWF1Ud6+5g=
|
|||||||
github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY=
|
github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY=
|
||||||
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
|
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
|
||||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||||
|
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
|
||||||
|
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||||
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||||
@ -89,6 +91,8 @@ github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0kt
|
|||||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
||||||
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
@ -190,6 +194,8 @@ github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZ
|
|||||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
||||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus-community/pro-bing v0.2.0 h1:hyK7yPFndU3LCDwEQJwPQUCjNkp1DGP/VxyzrWfXZUU=
|
github.com/prometheus-community/pro-bing v0.2.0 h1:hyK7yPFndU3LCDwEQJwPQUCjNkp1DGP/VxyzrWfXZUU=
|
||||||
@ -242,6 +248,12 @@ github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1Y
|
|||||||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||||
github.com/xhit/go-simple-mail/v2 v2.13.0 h1:OANWU9jHZrVfBkNkvLf8Ww0fexwpQVF/v/5f96fFTLI=
|
github.com/xhit/go-simple-mail/v2 v2.13.0 h1:OANWU9jHZrVfBkNkvLf8Ww0fexwpQVF/v/5f96fFTLI=
|
||||||
github.com/xhit/go-simple-mail/v2 v2.13.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98=
|
github.com/xhit/go-simple-mail/v2 v2.13.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98=
|
||||||
|
github.com/yeqown/go-qrcode/v2 v2.2.1 h1:Jc1Q916fwC05R8C7mpWDbrT9tyLPaLLKDABoC5XBCe8=
|
||||||
|
github.com/yeqown/go-qrcode/v2 v2.2.1/go.mod h1:2Qsk2APUCPne0TsRo40DIkI5MYnbzYKCnKGEFWrxd24=
|
||||||
|
github.com/yeqown/go-qrcode/writer/standard v1.2.1 h1:FMRZiur5yApUIe4fqtqmcdl/XQTZAZWt2DhkPx4VIW0=
|
||||||
|
github.com/yeqown/go-qrcode/writer/standard v1.2.1/go.mod h1:ZelyDFiVymrauRjUn454iF7bjsabmB1vixkDA5kq2bw=
|
||||||
|
github.com/yeqown/reedsolomon v1.0.0 h1:x1h/Ej/uJnNu8jaX7GLHBWmZKCAWjEJTetkqaabr4B0=
|
||||||
|
github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw/Iy6g1WiiM=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||||
@ -255,6 +267,8 @@ golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU
|
|||||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||||
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
||||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||||
|
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
|
||||||
|
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||||
|
@ -380,7 +380,7 @@ func (r *SqlRepo) GetPeer(ctx context.Context, id domain.PeerIdentifier) (*domai
|
|||||||
func (r *SqlRepo) GetInterfacePeers(ctx context.Context, id domain.InterfaceIdentifier) ([]domain.Peer, error) {
|
func (r *SqlRepo) GetInterfacePeers(ctx context.Context, id domain.InterfaceIdentifier) ([]domain.Peer, error) {
|
||||||
var peers []domain.Peer
|
var peers []domain.Peer
|
||||||
|
|
||||||
err := r.db.WithContext(ctx).Where("interface_identifier = ?", id).Find(&peers).Error
|
err := r.db.WithContext(ctx).Preload("Addresses").Where("interface_identifier = ?", id).Find(&peers).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -11,7 +11,7 @@
|
|||||||
let WGPORTAL_BACKEND_BASE_URL="http://localhost:5000/api/v0";
|
let WGPORTAL_BACKEND_BASE_URL="http://localhost:5000/api/v0";
|
||||||
</script>
|
</script>
|
||||||
<script src="/api/v0/config/frontend.js"></script>
|
<script src="/api/v0/config/frontend.js"></script>
|
||||||
<script type="module" crossorigin src="/app/assets/index-2321088d.js"></script>
|
<script type="module" crossorigin src="/app/assets/index-8f53e6dd.js"></script>
|
||||||
<link rel="stylesheet" href="/app/assets/index-a233ff7e.css">
|
<link rel="stylesheet" href="/app/assets/index-a233ff7e.css">
|
||||||
</head>
|
</head>
|
||||||
<body class="d-flex flex-column min-vh-100">
|
<body class="d-flex flex-column min-vh-100">
|
||||||
|
15
internal/app/api/v0/handlers/encoding.go
Normal file
15
internal/app/api/v0/handlers/encoding.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Base64UrlDecode(in string) string {
|
||||||
|
in = strings.ReplaceAll(in, "-", "=")
|
||||||
|
in = strings.ReplaceAll(in, "_", "/")
|
||||||
|
in = strings.ReplaceAll(in, ".", "+")
|
||||||
|
|
||||||
|
output, _ := base64.StdEncoding.DecodeString(in)
|
||||||
|
return string(output)
|
||||||
|
}
|
@ -90,7 +90,7 @@ func (e interfaceEndpoint) handleAllGet() gin.HandlerFunc {
|
|||||||
// @Router /interface/get/{id} [get]
|
// @Router /interface/get/{id} [get]
|
||||||
func (e interfaceEndpoint) handleSingleGet() gin.HandlerFunc {
|
func (e interfaceEndpoint) handleSingleGet() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
id := c.Param("id")
|
id := Base64UrlDecode(c.Param("id"))
|
||||||
if id == "" {
|
if id == "" {
|
||||||
c.JSON(http.StatusBadRequest, model.Error{
|
c.JSON(http.StatusBadRequest, model.Error{
|
||||||
Code: http.StatusInternalServerError, Message: "missing id parameter",
|
Code: http.StatusInternalServerError, Message: "missing id parameter",
|
||||||
@ -122,7 +122,7 @@ func (e interfaceEndpoint) handleSingleGet() gin.HandlerFunc {
|
|||||||
// @Router /interface/config/{id} [get]
|
// @Router /interface/config/{id} [get]
|
||||||
func (e interfaceEndpoint) handleConfigGet() gin.HandlerFunc {
|
func (e interfaceEndpoint) handleConfigGet() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
id := c.Param("id")
|
id := Base64UrlDecode(c.Param("id"))
|
||||||
if id == "" {
|
if id == "" {
|
||||||
c.JSON(http.StatusBadRequest, model.Error{
|
c.JSON(http.StatusBadRequest, model.Error{
|
||||||
Code: http.StatusInternalServerError, Message: "missing id parameter",
|
Code: http.StatusInternalServerError, Message: "missing id parameter",
|
||||||
@ -166,7 +166,7 @@ func (e interfaceEndpoint) handleUpdatePut() gin.HandlerFunc {
|
|||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
ctx := domain.SetUserInfoFromGin(c)
|
ctx := domain.SetUserInfoFromGin(c)
|
||||||
|
|
||||||
id := c.Param("id")
|
id := Base64UrlDecode(c.Param("id"))
|
||||||
if id == "" {
|
if id == "" {
|
||||||
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing interface id"})
|
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing interface id"})
|
||||||
return
|
return
|
||||||
@ -241,7 +241,9 @@ func (e interfaceEndpoint) handleCreatePost() gin.HandlerFunc {
|
|||||||
// @Router /interface/peers/{id} [get]
|
// @Router /interface/peers/{id} [get]
|
||||||
func (e interfaceEndpoint) handlePeersGet() gin.HandlerFunc {
|
func (e interfaceEndpoint) handlePeersGet() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
id := c.Param("id")
|
ctx := domain.SetUserInfoFromGin(c)
|
||||||
|
|
||||||
|
id := Base64UrlDecode(c.Param("id"))
|
||||||
if id == "" {
|
if id == "" {
|
||||||
c.JSON(http.StatusBadRequest, model.Error{
|
c.JSON(http.StatusBadRequest, model.Error{
|
||||||
Code: http.StatusInternalServerError, Message: "missing id parameter",
|
Code: http.StatusInternalServerError, Message: "missing id parameter",
|
||||||
@ -249,7 +251,7 @@ func (e interfaceEndpoint) handlePeersGet() gin.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, peers, err := e.app.GetInterfaceAndPeers(c.Request.Context(), domain.InterfaceIdentifier(id))
|
_, peers, err := e.app.GetInterfaceAndPeers(ctx, domain.InterfaceIdentifier(id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, model.Error{
|
c.JSON(http.StatusInternalServerError, model.Error{
|
||||||
Code: http.StatusInternalServerError, Message: err.Error(),
|
Code: http.StatusInternalServerError, Message: err.Error(),
|
||||||
@ -276,7 +278,7 @@ func (e interfaceEndpoint) handleDelete() gin.HandlerFunc {
|
|||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
ctx := domain.SetUserInfoFromGin(c)
|
ctx := domain.SetUserInfoFromGin(c)
|
||||||
|
|
||||||
id := c.Param("id")
|
id := Base64UrlDecode(c.Param("id"))
|
||||||
if id == "" {
|
if id == "" {
|
||||||
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing interface id"})
|
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing interface id"})
|
||||||
return
|
return
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/h44z/wg-portal/internal/app"
|
"github.com/h44z/wg-portal/internal/app"
|
||||||
"github.com/h44z/wg-portal/internal/app/api/v0/model"
|
"github.com/h44z/wg-portal/internal/app/api/v0/model"
|
||||||
"github.com/h44z/wg-portal/internal/domain"
|
"github.com/h44z/wg-portal/internal/domain"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,6 +24,8 @@ func (e peerEndpoint) RegisterRoutes(g *gin.RouterGroup, authenticator *authenti
|
|||||||
apiGroup.GET("/iface/:iface/all", e.handleAllGet())
|
apiGroup.GET("/iface/:iface/all", e.handleAllGet())
|
||||||
apiGroup.GET("/iface/:iface/prepare", e.handlePrepareGet())
|
apiGroup.GET("/iface/:iface/prepare", e.handlePrepareGet())
|
||||||
apiGroup.POST("/iface/:iface/new", e.handleCreatePost())
|
apiGroup.POST("/iface/:iface/new", e.handleCreatePost())
|
||||||
|
apiGroup.GET("/config-qr/:id", e.handleQrCodeGet())
|
||||||
|
apiGroup.GET("/config/:id", e.handleConfigGet())
|
||||||
apiGroup.GET("/:id", e.handleSingleGet())
|
apiGroup.GET("/:id", e.handleSingleGet())
|
||||||
apiGroup.PUT("/:id", e.handleUpdatePut())
|
apiGroup.PUT("/:id", e.handleUpdatePut())
|
||||||
apiGroup.DELETE("/:id", e.handleDelete())
|
apiGroup.DELETE("/:id", e.handleDelete())
|
||||||
@ -43,7 +46,7 @@ func (e peerEndpoint) handleAllGet() gin.HandlerFunc {
|
|||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
ctx := domain.SetUserInfoFromGin(c)
|
ctx := domain.SetUserInfoFromGin(c)
|
||||||
|
|
||||||
interfaceId := c.Param("iface")
|
interfaceId := Base64UrlDecode(c.Param("iface"))
|
||||||
if interfaceId == "" {
|
if interfaceId == "" {
|
||||||
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing iface parameter"})
|
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing iface parameter"})
|
||||||
return
|
return
|
||||||
@ -74,7 +77,7 @@ func (e peerEndpoint) handleSingleGet() gin.HandlerFunc {
|
|||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
ctx := domain.SetUserInfoFromGin(c)
|
ctx := domain.SetUserInfoFromGin(c)
|
||||||
|
|
||||||
peerId := c.Param("id")
|
peerId := Base64UrlDecode(c.Param("id"))
|
||||||
if peerId == "" {
|
if peerId == "" {
|
||||||
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing id parameter"})
|
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing id parameter"})
|
||||||
return
|
return
|
||||||
@ -105,7 +108,7 @@ func (e peerEndpoint) handlePrepareGet() gin.HandlerFunc {
|
|||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
ctx := domain.SetUserInfoFromGin(c)
|
ctx := domain.SetUserInfoFromGin(c)
|
||||||
|
|
||||||
interfaceId := c.Param("iface")
|
interfaceId := Base64UrlDecode(c.Param("iface"))
|
||||||
if interfaceId == "" {
|
if interfaceId == "" {
|
||||||
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing iface parameter"})
|
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing iface parameter"})
|
||||||
return
|
return
|
||||||
@ -137,7 +140,7 @@ func (e peerEndpoint) handleCreatePost() gin.HandlerFunc {
|
|||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
ctx := domain.SetUserInfoFromGin(c)
|
ctx := domain.SetUserInfoFromGin(c)
|
||||||
|
|
||||||
interfaceId := c.Param("iface")
|
interfaceId := Base64UrlDecode(c.Param("iface"))
|
||||||
if interfaceId == "" {
|
if interfaceId == "" {
|
||||||
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing iface parameter"})
|
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing iface parameter"})
|
||||||
return
|
return
|
||||||
@ -176,12 +179,12 @@ func (e peerEndpoint) handleCreatePost() gin.HandlerFunc {
|
|||||||
// @Success 200 {object} model.Peer
|
// @Success 200 {object} model.Peer
|
||||||
// @Failure 400 {object} model.Error
|
// @Failure 400 {object} model.Error
|
||||||
// @Failure 500 {object} model.Error
|
// @Failure 500 {object} model.Error
|
||||||
// @Router /peer/{id} [post]
|
// @Router /peer/{id} [put]
|
||||||
func (e peerEndpoint) handleUpdatePut() gin.HandlerFunc {
|
func (e peerEndpoint) handleUpdatePut() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
ctx := domain.SetUserInfoFromGin(c)
|
ctx := domain.SetUserInfoFromGin(c)
|
||||||
|
|
||||||
peerId := c.Param("id")
|
peerId := Base64UrlDecode(c.Param("id"))
|
||||||
if peerId == "" {
|
if peerId == "" {
|
||||||
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing id parameter"})
|
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing id parameter"})
|
||||||
return
|
return
|
||||||
@ -224,7 +227,7 @@ func (e peerEndpoint) handleDelete() gin.HandlerFunc {
|
|||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
ctx := domain.SetUserInfoFromGin(c)
|
ctx := domain.SetUserInfoFromGin(c)
|
||||||
|
|
||||||
id := c.Param("id")
|
id := Base64UrlDecode(c.Param("id"))
|
||||||
if id == "" {
|
if id == "" {
|
||||||
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing peer id"})
|
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing peer id"})
|
||||||
return
|
return
|
||||||
@ -239,3 +242,83 @@ func (e peerEndpoint) handleDelete() gin.HandlerFunc {
|
|||||||
c.Status(http.StatusNoContent)
|
c.Status(http.StatusNoContent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleConfigGet returns a gorm handler function.
|
||||||
|
//
|
||||||
|
// @ID peers_handleConfigGet
|
||||||
|
// @Tags Peer
|
||||||
|
// @Summary Get peer configuration as string.
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} string
|
||||||
|
// @Failure 400 {object} model.Error
|
||||||
|
// @Failure 500 {object} model.Error
|
||||||
|
// @Router /peer/config/{id} [get]
|
||||||
|
func (e peerEndpoint) handleConfigGet() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
id := Base64UrlDecode(c.Param("id"))
|
||||||
|
if id == "" {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error{
|
||||||
|
Code: http.StatusInternalServerError, Message: "missing id parameter",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config, err := e.app.GetPeerConfig(c.Request.Context(), domain.PeerIdentifier(id))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, model.Error{
|
||||||
|
Code: http.StatusInternalServerError, Message: err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
configString, err := io.ReadAll(config)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, model.Error{
|
||||||
|
Code: http.StatusInternalServerError, Message: err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, string(configString))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleQrCodeGet returns a gorm handler function.
|
||||||
|
//
|
||||||
|
// @ID peers_handleQrCodeGet
|
||||||
|
// @Tags Peer
|
||||||
|
// @Summary Get peer configuration as qr code.
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} string
|
||||||
|
// @Failure 400 {object} model.Error
|
||||||
|
// @Failure 500 {object} model.Error
|
||||||
|
// @Router /peer/config-qr/{id} [get]
|
||||||
|
func (e peerEndpoint) handleQrCodeGet() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
id := Base64UrlDecode(c.Param("id"))
|
||||||
|
if id == "" {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error{
|
||||||
|
Code: http.StatusInternalServerError, Message: "missing id parameter",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config, err := e.app.GetPeerConfigQrCode(c.Request.Context(), domain.PeerIdentifier(id))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, model.Error{
|
||||||
|
Code: http.StatusInternalServerError, Message: err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
configData, err := io.ReadAll(config)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, model.Error{
|
||||||
|
Code: http.StatusInternalServerError, Message: err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data(http.StatusOK, "image/png", configData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -39,7 +39,9 @@ func (e userEndpoint) RegisterRoutes(g *gin.RouterGroup, authenticator *authenti
|
|||||||
// @Router /user/all [get]
|
// @Router /user/all [get]
|
||||||
func (e userEndpoint) handleAllGet() gin.HandlerFunc {
|
func (e userEndpoint) handleAllGet() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
users, err := e.app.GetAllUsers(c.Request.Context())
|
ctx := domain.SetUserInfoFromGin(c)
|
||||||
|
|
||||||
|
users, err := e.app.GetAllUsers(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, model.Error{Code: http.StatusInternalServerError, Message: err.Error()})
|
c.JSON(http.StatusInternalServerError, model.Error{Code: http.StatusInternalServerError, Message: err.Error()})
|
||||||
return
|
return
|
||||||
@ -63,7 +65,7 @@ func (e userEndpoint) handleSingleGet() gin.HandlerFunc {
|
|||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
ctx := domain.SetUserInfoFromGin(c)
|
ctx := domain.SetUserInfoFromGin(c)
|
||||||
|
|
||||||
id := c.Param("id")
|
id := Base64UrlDecode(c.Param("id"))
|
||||||
if id == "" {
|
if id == "" {
|
||||||
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing user id"})
|
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing user id"})
|
||||||
return
|
return
|
||||||
@ -95,7 +97,7 @@ func (e userEndpoint) handleUpdatePut() gin.HandlerFunc {
|
|||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
ctx := domain.SetUserInfoFromGin(c)
|
ctx := domain.SetUserInfoFromGin(c)
|
||||||
|
|
||||||
id := c.Param("id")
|
id := Base64UrlDecode(c.Param("id"))
|
||||||
if id == "" {
|
if id == "" {
|
||||||
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing user id"})
|
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing user id"})
|
||||||
return
|
return
|
||||||
@ -166,13 +168,15 @@ func (e userEndpoint) handleCreatePost() gin.HandlerFunc {
|
|||||||
// @Router /user/{id}/peers [get]
|
// @Router /user/{id}/peers [get]
|
||||||
func (e userEndpoint) handlePeersGet() gin.HandlerFunc {
|
func (e userEndpoint) handlePeersGet() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
interfaceId := c.Param("id")
|
ctx := domain.SetUserInfoFromGin(c)
|
||||||
|
|
||||||
|
interfaceId := Base64UrlDecode(c.Param("id"))
|
||||||
if interfaceId == "" {
|
if interfaceId == "" {
|
||||||
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusInternalServerError, Message: "missing id parameter"})
|
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusInternalServerError, Message: "missing id parameter"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
peers, err := e.app.GetUserPeers(c.Request.Context(), domain.UserIdentifier(interfaceId))
|
peers, err := e.app.GetUserPeers(ctx, domain.UserIdentifier(interfaceId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, model.Error{Code: http.StatusInternalServerError, Message: err.Error()})
|
c.JSON(http.StatusInternalServerError, model.Error{Code: http.StatusInternalServerError, Message: err.Error()})
|
||||||
return
|
return
|
||||||
@ -197,7 +201,7 @@ func (e userEndpoint) handleDelete() gin.HandlerFunc {
|
|||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
ctx := domain.SetUserInfoFromGin(c)
|
ctx := domain.SetUserInfoFromGin(c)
|
||||||
|
|
||||||
id := c.Param("id")
|
id := Base64UrlDecode(c.Param("id"))
|
||||||
if id == "" {
|
if id == "" {
|
||||||
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing user id"})
|
c.JSON(http.StatusBadRequest, model.Error{Code: http.StatusBadRequest, Message: "missing user id"})
|
||||||
return
|
return
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package filetemplate
|
package filetemplate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/h44z/wg-portal/internal/config"
|
"github.com/h44z/wg-portal/internal/config"
|
||||||
"github.com/h44z/wg-portal/internal/domain"
|
"github.com/h44z/wg-portal/internal/domain"
|
||||||
|
"github.com/yeqown/go-qrcode/v2"
|
||||||
|
"github.com/yeqown/go-qrcode/writer/standard"
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,3 +53,41 @@ func (m Manager) GetPeerConfig(ctx context.Context, id domain.PeerIdentifier) (i
|
|||||||
|
|
||||||
return m.tplHandler.GetPeerConfig(peer)
|
return m.tplHandler.GetPeerConfig(peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m Manager) GetPeerConfigQrCode(ctx context.Context, id domain.PeerIdentifier) (io.Reader, error) {
|
||||||
|
peer, err := m.wg.GetPeer(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch peer %s: %w", id, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfgData, err := m.tplHandler.GetPeerConfig(peer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get peer config for %s: %w", id, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
configBytes, err := io.ReadAll(cfgData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read peer config for %s: %w", id, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
code, err := qrcode.New(string(configBytes))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to initializeqr code for %s: %w", id, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
wr := nopCloser{Writer: buf}
|
||||||
|
qrWriter := standard.NewWithWriter(wr, standard.WithQRWidth(40), standard.WithBuiltinImageEncoder(standard.PNG_FORMAT))
|
||||||
|
err = code.Save(qrWriter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to write code for %s: %w", id, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type nopCloser struct {
|
||||||
|
io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nopCloser) Close() error { return nil }
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
# AUTOGENERATED FILE - DO NOT EDIT
|
# AUTOGENERATED FILE - DO NOT EDIT
|
||||||
# This file uses wg-quick format. See https://man7.org/linux/man-pages/man8/wg-quick.8.html#CONFIGURATION
|
# This file uses wg-quick format.
|
||||||
|
# See https://man7.org/linux/man-pages/man8/wg-quick.8.html#CONFIGURATION
|
||||||
|
# Lines starting with the -WGP- tag are used by
|
||||||
|
# the WireGuard Portal configuration parser.
|
||||||
|
|
||||||
# -WGP- WIREGUARD PORTAL CONFIGURATION FILE, version {{ .Portal.Version }}
|
# -WGP- WIREGUARD PORTAL CONFIGURATION FILE
|
||||||
# Lines starting with the -WGP- tag are used by the WireGuard Portal configuration parser.
|
# -WGP- version {{ .Portal.Version }}
|
||||||
|
|
||||||
[Interface]
|
[Interface]
|
||||||
# -WGP- Interface: {{ .Interface.Identifier }} | Updated: {{ .Interface.UpdatedAt }} | Created: {{ .Interface.CreatedAt }}
|
# -WGP- Interface: {{ .Interface.Identifier }}
|
||||||
|
# -WGP- Created: {{ .Interface.CreatedAt }}
|
||||||
|
# -WGP- Updated: {{ .Interface.UpdatedAt }}
|
||||||
# -WGP- Display name: {{ .Interface.DisplayName }}
|
# -WGP- Display name: {{ .Interface.DisplayName }}
|
||||||
# -WGP- Interface mode: {{ .Interface.Type }}
|
# -WGP- Interface mode: {{ .Interface.Type }}
|
||||||
# -WGP- PublicKey = {{ .Interface.KeyPair.PublicKey }}
|
# -WGP- PublicKey = {{ .Interface.KeyPair.PublicKey }}
|
||||||
@ -53,30 +58,32 @@ PostDown = {{ .Interface.PostDown }}
|
|||||||
#
|
#
|
||||||
|
|
||||||
{{range .Peers}}
|
{{range .Peers}}
|
||||||
{{- if not .DisabledAt}}
|
{{- if not .IsDisabled}}
|
||||||
[Peer]
|
[Peer]
|
||||||
# -WGP- Peer: {{.Uid}} | Updated: {{.UpdatedAt}} | Created: {{.CreatedAt}}
|
# -WGP- Peer: {{.Identifier}}
|
||||||
# -WGP- Display name: {{ .Identifier }}
|
# -WGP- Created: {{.CreatedAt}}
|
||||||
{{- if .KeyPair.PrivateKey}}
|
# -WGP- Updated: {{.UpdatedAt}}
|
||||||
# -WGP- PrivateKey: {{.KeyPair.PrivateKey}}
|
# -WGP- Display name: {{ .DisplayName }}
|
||||||
|
{{- if .Interface.KeyPair.PrivateKey}}
|
||||||
|
# -WGP- PrivateKey: {{.Interface.KeyPair.PrivateKey}}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
PublicKey = {{ .KeyPair.PublicKey }}
|
PublicKey = {{ .Interface.KeyPair.PublicKey }}
|
||||||
{{- if .PresharedKey}}
|
{{- if .PresharedKey}}
|
||||||
PresharedKey = {{ .PresharedKey }}
|
PresharedKey = {{ .PresharedKey }}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
{{- if eq $.Interface.Type "server"}}
|
{{- if eq $.Interface.Type "server"}}
|
||||||
AllowedIPs = {{ .AddressStr }}{{if ne .ExtraAllowedIPsStr ""}}, {{ .ExtraAllowedIPsStr }}{{end}}
|
AllowedIPs = {{ CidrsToString .Interface.Addresses }}{{if ne .ExtraAllowedIPsStr ""}}, {{ .ExtraAllowedIPsStr }}{{end}}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
{{- if eq $.Interface.Type "client"}}
|
{{- if eq $.Interface.Type "client"}}
|
||||||
{{- if .AllowedIPsStr}}
|
{{- if .AllowedIPsStr.GetValue}}
|
||||||
AllowedIPs = {{ .AllowedIPsStr }}
|
AllowedIPs = {{ .AllowedIPsStr.GetValue }}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
{{- if and (ne .Endpoint "") (eq $.Interface.Type "client")}}
|
{{- if and (ne .Endpoint.GetValue "") (eq $.Interface.Type "client")}}
|
||||||
Endpoint = {{ .Endpoint }}
|
Endpoint = {{ .Endpoint.GetValue }}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
{{- if ne .PersistentKeepalive 0}}
|
{{- if and (ne .PersistentKeepalive.GetValue 0) (eq $.Interface.Type "client")}}
|
||||||
PersistentKeepalive = {{ .PersistentKeepalive }}
|
PersistentKeepalive = {{ .PersistentKeepalive.GetValue }}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
{{end}}
|
{{end}}
|
@ -1,22 +1,27 @@
|
|||||||
# AUTOGENERATED FILE - DO NOT EDIT
|
# AUTOGENERATED FILE - DO NOT EDIT
|
||||||
# This file uses wg-quick format. See https://man7.org/linux/man-pages/man8/wg-quick.8.html#CONFIGURATION
|
# This file uses wg-quick format.
|
||||||
|
# See https://man7.org/linux/man-pages/man8/wg-quick.8.html#CONFIGURATION
|
||||||
|
# Lines starting with the -WGP- tag are used by
|
||||||
|
# the WireGuard Portal configuration parser.
|
||||||
|
|
||||||
# -WGP- WIREGUARD PORTAL CONFIGURATION FILE, version {{ .Portal.Version }}
|
# -WGP- WIREGUARD PORTAL CONFIGURATION FILE
|
||||||
# Lines starting with the -WGP- tag are used by the WireGuard Portal configuration parser.
|
# -WGP- version {{ .Portal.Version }}
|
||||||
|
|
||||||
[Interface]
|
[Interface]
|
||||||
# -WGP- Peer: {{.Peer.Identifier}} | Updated: {{.Peer.UpdatedAt}} | Created: {{.Peer.CreatedAt}}
|
# -WGP- Peer: {{.Peer.Identifier}}
|
||||||
|
# -WGP- Created: {{.Peer.CreatedAt}}
|
||||||
|
# -WGP- Updated: {{.Peer.UpdatedAt}}
|
||||||
# -WGP- Display name: {{ .Peer.DisplayName }}
|
# -WGP- Display name: {{ .Peer.DisplayName }}
|
||||||
# -WGP- PublicKey: {{ .Peer.KeyPair.PublicKey }}
|
# -WGP- PublicKey: {{ .Peer.Interface.KeyPair.PublicKey }}
|
||||||
{{- if eq .Peer.Interface.Type "server"}}
|
{{- if eq .Peer.Interface.Type "server"}}
|
||||||
# -WGP- Peer type: client
|
|
||||||
{{else}}
|
|
||||||
# -WGP- Peer type: server
|
# -WGP- Peer type: server
|
||||||
|
{{else}}
|
||||||
|
# -WGP- Peer type: client
|
||||||
{{- end}}
|
{{- end}}
|
||||||
|
|
||||||
# Core settings
|
# Core settings
|
||||||
PrivateKey = {{ .Peer.KeyPair.PrivateKey }}
|
PrivateKey = {{ .Peer.Interface.KeyPair.PrivateKey }}
|
||||||
Address = {{ .Peer.Interface.AddressStr }}
|
Address = {{ CidrsToString .Peer.Interface.Addresses }}
|
||||||
|
|
||||||
# Misc. settings (optional)
|
# Misc. settings (optional)
|
||||||
{{- if .Peer.Interface.DnsStr.GetValue}}
|
{{- if .Peer.Interface.DnsStr.GetValue}}
|
||||||
@ -47,7 +52,7 @@ PostDown = {{ .Peer.Interface.PostDown.GetValue }}
|
|||||||
{{- end}}
|
{{- end}}
|
||||||
|
|
||||||
[Peer]
|
[Peer]
|
||||||
PublicKey = {{ .Peer.Interface.PublicKey }}
|
PublicKey = {{ .Peer.EndpointPublicKey.GetValue }}
|
||||||
Endpoint = {{ .Peer.Endpoint.GetValue }}
|
Endpoint = {{ .Peer.Endpoint.GetValue }}
|
||||||
{{- if .Peer.AllowedIPsStr.GetValue}}
|
{{- if .Peer.AllowedIPsStr.GetValue}}
|
||||||
AllowedIPs = {{ .Peer.AllowedIPsStr.GetValue }}
|
AllowedIPs = {{ .Peer.AllowedIPsStr.GetValue }}
|
||||||
@ -55,6 +60,6 @@ AllowedIPs = {{ .Peer.AllowedIPsStr.GetValue }}
|
|||||||
{{- if .Peer.PresharedKey}}
|
{{- if .Peer.PresharedKey}}
|
||||||
PresharedKey = {{ .Peer.PresharedKey }}
|
PresharedKey = {{ .Peer.PresharedKey }}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
{{- if ne .Peer.PersistentKeepalive.GetValue 0}}
|
{{- if and (ne .Peer.PersistentKeepalive.GetValue 0) (eq .Peer.Interface.Type "client")}}
|
||||||
PersistentKeepalive = {{ .Peer.PersistentKeepalive.GetValue }}
|
PersistentKeepalive = {{ .Peer.PersistentKeepalive.GetValue }}
|
||||||
{{- end}}
|
{{- end}}
|
@ -51,4 +51,5 @@ type StatisticsCollector interface {
|
|||||||
type TemplateManager interface {
|
type TemplateManager interface {
|
||||||
GetInterfaceConfig(ctx context.Context, id domain.InterfaceIdentifier) (io.Reader, error)
|
GetInterfaceConfig(ctx context.Context, id domain.InterfaceIdentifier) (io.Reader, error)
|
||||||
GetPeerConfig(ctx context.Context, id domain.PeerIdentifier) (io.Reader, error)
|
GetPeerConfig(ctx context.Context, id domain.PeerIdentifier) (io.Reader, error)
|
||||||
|
GetPeerConfigQrCode(ctx context.Context, id domain.PeerIdentifier) (io.Reader, error)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user