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())