#6 Added /del endpoint

master
wgapi Cloud9 2021-10-18 14:39:29 -06:00
parent 62179c8833
commit 41dbde0a5a
5 changed files with 135 additions and 17 deletions

View File

@ -1,5 +1,5 @@
'use strict'
/* srv-add.js
/* admin/add.js
* routes for intra-server peer sharing
*/

View File

@ -1,12 +1,32 @@
'use strict'
/* srv-del.js
/* admin/del.js
* routes for intra-server peer sharing
*/
const env = require('../env/env.json')
const env = require(process.argv[2]||'../env/env.json')
const fs = require('fs').promises
module.exports = async (req, res) => {
console.log(`Received delete from ${req.requester}`)
res.send(req.body)
console.log(`Received delete from ${req.requester} for ${req.body}`)
let config
try {
const config_file = await fs.readFile(env.WG_CONFIG_FILE)
config = config_file.toString()
} catch (err) {
console.error(`Failed to load config from ${env.WG_CONFIG_FILE}:\n`,err)
res.sendStatus(500)
}
const peer = config.split('\n\n')
.filter( (paragraph) => {
return paragraph.includes('[Peer]')
}).filter( (peer) => {
return peer.includes(`PublicKey = ${req.body}`)
})
try {
await fs.writeFile(env.WG_CONFIG_FILE, config.replace(`\n\n${peer}`,''))
} catch (err) {
console.error(`Failed to delete peer config from ${env.WG_CONFIG_FILE}:\n`,err)
res.sendStatus(500)
}
res.sendStatus(200)
}

View File

@ -22,7 +22,7 @@ module.exports = async (req, res) => {
const hostname = req.query['name']
if (!hostname) {
console.log(`New peer request from ${req.requester} didn't provide a hostname`)
res.sendStatus(500); return
res.sendStatus(400); return
}
console.log(`New peer request from ${req.requester} for ${hostname}`)
@ -50,7 +50,7 @@ module.exports = async (req, res) => {
// Check if host exists
if (line.includes(`# ${hostname}.`)) {
console.log(`Host already exists for ${hostname}`)
res.sendStatus(500); return
res.sendStatus(409); return
}
found_usernames.push(line.split('.').slice(-2,-1)[0])
}
@ -75,7 +75,7 @@ module.exports = async (req, res) => {
// Should never get here because this req.requester can't access this IP!
} else if (found_usernames.length ===0) {
console.log(`Received request from ${req.requester} not in wg.conf!`)
res.sendStatus(500); return
res.sendStatus(403); return
// Check that all usernames are correct or error out
// https://stackoverflow.com/a/35568895
} else if (!found_usernames.every( (v,i,r) => v === r[0] )) {
@ -131,7 +131,8 @@ PresharedKey = ${psk}
AllowedIPs = ${ipv4_addr}/32, ${ipv6_addr}/128`
if (server.host===env.LOCAL_SERVER) {
// Add server_config to wg0.conf
fs.appendFile(env.WG_CONFIG_FILE, server_config)
try { await fs.appendFile(env.WG_CONFIG_FILE, server_config) }
catch (err) { console.error(err); return}
} else {
// Send config to other server
console.log(`Sending config to ${server.host}.gf4`)

View File

@ -4,13 +4,101 @@
*/
const fs = require('fs').promises
const env = require('../env/env.json')
const env = require(process.argv[2]||'../env/env.json')
const wg = require('../includes/wireguard')
const https = require('https')
// Construct axios in IIFE for async/await
let axios; (async()=>{
try {
axios = require('axios').create({
httpsAgent: new https.Agent({
ca: await fs.readFile(env.CA_CERT_FILE),
}),
})
} catch (err) { console.log(err) }
})()
module.exports = async (req, res) => {
const privkey = req.query['del']
console.log(`Received request from ${req.requester} to delete ${JSON.stringify(req.query)}`)
// Load wg.conf and search for peers
let config_file
let peer_pubkey
try { config_file = await fs.readFile(env.WG_CONFIG_FILE) }
catch (err) { console.error(err); res.sendStatus(500); return }
const config = config_file.toString()
const peer = config.split('\n\n')
.filter( (paragraph) => {
return paragraph.includes('[Peer]')
}).filter( (peer) => {
// .filter() doesn't support async so use then/catch in this block
if (req.query['name']) {
return peer.includes(`[Peer] # ${req.query['name']}.`)
} else if (req.query['pubkey']) {
peer_pubkey = req.query['pubkey']
return peer.includes(`PublicKey = ${req.query['pubkey']}`)
} else if (req.query['psk']) {
return peer.includes(`PresharedKey = ${req.query['psk']}`)
} else if (req.query['ip']) {
return peer.split('\n').some( (line) => (
line.includes('AllowedIPs') &&
line.includes(` ${req.query['ip']}/`)
) )
} else if (req.query['privkey']) {
wg.getPubkeyFromPrivkey(req.query['privkey'])
.then((pubkey) => {
peer_pubkey = pubkey
return peer.includes(`PublicKey = ${pubkey}`)
})
.catch((err) => {
console.error(`Failed to generate public key from private key during delete request\n`,err)
res.sendStatus(500); return
})
} else {
console.error(`${req.requester} sent delete request without specifying a peer`)
res.sendStatus(400); return
}
})[0]
if (peer===undefined) {
console.log(`No peer found for delete request from ${req.requester}`)
res.sendStatus(404); return
}
console.log(`Received request from ${req.requester} to delete ${privkey}`)
res.setHeader('content-type', 'text/plain')
res.send(`Delete ${privkey}`)
// Parse peer
const peer_lines = peer.split('\n')
const peer_name = peer_lines
.filter( (line) => line.includes('[Peer] # ') )[0]
.split(' # ')[1]
if (peer_pubkey===undefined) {
peer_pubkey = peer_lines
.filter( (line) => line.includes('PublicKey = ') )[0]
.split(' = ')[1]
}
// Delete from config
console.log(`Deleting ${peer_name}`); try {
await fs.writeFile(env.WG_CONFIG_FILE, config.replace(`\n\n${peer}`,''))
} catch (err) {
console.error(`Failed to delete ${peer_name}:\n`,err)
res.sendStatus(500); return
}
// Inform other servers
for (const server of env.SERVERS) {
if (server.host!==env.LOCAL_SERVER) {
try {
console.log(`Informing ${server.host} to delete ${peer_name}`)
await axios.post(`${server.admin_endpoint}/del`, peer_pubkey, {
headers: {'Content-Type': 'text/plain'},
})
} catch (err) {
console.error(`Failed to inform ${server.host} to delete ${peer_name}:\n\n`,err)
res.sendStatus(500); return
}
}
}
// Inform user that delete was successful
res.sendStatus(200)
}

View File

@ -162,23 +162,32 @@ const keyToBase64 = (key) => {
}
module.exports = {
generateKeypair: async () => {
let privateKey, publicKey
try {
privateKey = await generatePrivateKey()
} catch (err) { console.log(err) }
} catch (err) { console.error(err) }
try {
publicKey = await generatePublicKey(privateKey)
} catch (err) { console.log(err) }
} catch (err) { console.error(err) }
return [
keyToBase64(publicKey),
keyToBase64(privateKey),
]
},
generatePSK: async () => {
try {
return keyToBase64(await generatePresharedKey())
} catch (err) { console.log(err) }
} catch (err) { console.error(err); return }
},
getPubkeyFromPrivkey: async (privKey) => {
try {
return await generatePublicKey(privKey)
} catch (err) { console.error(err); return }
},
}