diff --git a/docker-compose.yml b/docker-compose.yml
index 891e6ab..fb38e25 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,5 +1,6 @@
version: '3'
services:
+
dashboard-backend:
build:
context: back
@@ -12,3 +13,13 @@ services:
- '/etc/ssl/private:/etc/ssl/private'
- '/etc/wgapi:/etc/wgapi:ro'
- '/var/log/wgapi:/var/log/wgapi'
+
+ dashboard-frontend:
+ build:
+ context: front
+ dockerfile: Dockerfile.dashboard
+ container_name: wgapi-dashboard-frontend
+ volumes:
+ - '/var/log/wgapi:/var/log/wgapi'
+ ports:
+ - '8081:80'
diff --git a/front/Dockerfile.dashboard b/front/Dockerfile.dashboard
new file mode 100644
index 0000000..3fd0c42
--- /dev/null
+++ b/front/Dockerfile.dashboard
@@ -0,0 +1,3 @@
+FROM httpd:2.4
+COPY ./dashboard.html /usr/local/apache2/htdocs/index.html
+COPY dashboard.js /usr/local/apache2/htdocs/dashboard.js
diff --git a/front/admin/index.html b/front/admin/index.html
deleted file mode 100644
index c2a11b2..0000000
--- a/front/admin/index.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- Wireguard Dashboard
-
-
-
-
+
+
+
diff --git a/front/dashboard.js b/front/dashboard.js
new file mode 100644
index 0000000..57eb3c7
--- /dev/null
+++ b/front/dashboard.js
@@ -0,0 +1,145 @@
+const API_URL = 'http://ksn.gf4:8080'
+
+function Peer(data) {
+ this.name = ko.observable(data.name)
+ this.ipv4 = ko.observable(data.ipv4)
+ this.ipv6 = ko.observable(`:${data.ipv6.split(':').slice(-2).join(':')}`)
+ this.isDeleting = ko.observable(false)
+ this.deleteText = ko.computed(() => this.isDeleting()?'Deleting...':'Delete')
+}
+
+function PeerList() {
+ let self = this
+ self.peers = ko.observableArray([])
+ self.newPeerName = ko.observable('')
+ self.newConfigText = ko.observable('')
+ self.isAdding = ko.observable(false)
+ self.addText = ko.computed(() => self.isAdding()?'Adding...':'Add')
+
+ // Initial loading
+ self.getUser = async () => {
+ let res; try {
+ res = await fetch(`${API_URL}/`)
+ } catch (err) {
+ console.error(`Failed to GET ${API_URL}/`)
+ if (err) console.error(err)
+ }
+ if (!res.ok) {
+ console.log(`Got ${res.status} from GET ${API_URL}/`)
+ alert('Failed to contact API and load peers list. Check your wireguard connection. ')
+ } else {
+ let user; try {
+ user = await res.json()
+ } catch (err) {
+ console.error('Failed to parse JSON!')
+ if (err) console.error(err)
+ }
+ self.peers(
+ user.peers.sort(
+ (a,b) => a.ipv4.split('.')[3] - b.ipv4.split('.')[3])
+ .map( (i)=>new Peer(i))
+ )
+ self.token = user.token
+ }
+ }
+
+ self.addPeer = async () => {
+ self.isAdding(true)
+ const validName = self.newPeerName().trim().toLowerCase()
+ if (validName.length === 0) {
+ alert('Please enter a hostname.')
+ self.isAdding(false)
+ } else if (!/^([\-\_a-z0-9]{3,12})$/.test(validName)) {
+ alert('Name must be 3-12 alphanumeric chars.')
+ self.isAdding(false)
+ } else if (self.peers().map((peer)=>peer.name()).includes(validName)) {
+ alert(`You already have a peer named ${validName}!`)
+ self.isAdding(false)
+ } else {
+ const url = `${API_URL}/?token=${self.token}`
+ let res; try {
+ res = await fetch(url, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ name: validName,
+ }),
+ })
+ } catch (err) {
+ alert('Failed to contact server. Are you online?')
+ if (err) console.error(err)
+ self.isAdding(false)
+ }
+ let parsedRes; try {
+ parsedRes = await res.text()
+ } catch (err) {
+ if (err) console.error(err)
+ } finally { self.isAdding(false) }
+ if (!res.ok) {
+ alert(parsedRes)
+ } else {
+ self.newPeerName('')
+ self.newConfigText(parsedRes)
+ let interfaceLines = parsedRes.split('\n\n').filter(
+ (paragraph) => paragraph.includes('[Interface]')
+ )[0].split('\n')
+ let addresses = interfaceLines.filter(
+ (line) => line.includes('Address = ')
+ )[0].split('=')[1].trim().split(', ')
+ self.peers.push(new Peer({
+ name: interfaceLines[0]
+ .split('#')[1].trim().split('.')[0],
+ ipv4: addresses.filter(
+ (addr) => addr.includes('10.4.')
+ )[0].split('/')[0],
+ ipv6: addresses.filter(
+ (addr) => addr.includes('fd69:1337:0:420:f4:f4:')
+ )[0].split('/')[0],
+ }))
+ }
+ }
+ }
+
+ // Listen for user hitting enter key
+ self.addKeyPress = (d,e) => {
+ if (e.keyCode === 13) self.addPeer()
+ return true
+ }
+
+ self.delPeer = async (peer) => {
+ const name = peer.name()
+ if (confirm(`Are you sure you want to delete ${name}?`)) {
+ peer.isDeleting(true)
+ const url = `${API_URL}/?token=${self.token}`
+ try {
+ const res = await fetch(url, {
+ method: 'DELETE',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ name: name,
+ }),
+ })
+ if (res.ok) self.peers.remove(peer)
+ else {
+ if (res.status===404) self.peers.remove(peer)
+ try {
+ alert(await res.text())
+ } catch (err) {
+ console.error(`Failed to parse DELETE response into text`)
+ if (err) console.error(err)
+ } finally { peer.isDeleting(false) }
+ }
+ } catch (err) {
+ alert(`Failed to contact the server. Are you online?`)
+ } finally { peer.isDeleting(false) }
+ }
+ }
+
+ self.getUser()
+}
+
+ko.applyBindings(new PeerList())
diff --git a/front/dashboard/index.html b/front/dashboard/index.html
deleted file mode 100644
index c2a11b2..0000000
--- a/front/dashboard/index.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- Wireguard Dashboard
-
-
-
-