#15 Set domains in nameserver
parent
6cc02cc860
commit
6e088a08d3
|
@ -1,4 +1,5 @@
|
||||||
FROM node:16-bullseye
|
FROM node:16-bullseye
|
||||||
|
RUN apt install -y dnsutils
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
RUN npm install
|
RUN npm install
|
||||||
|
|
19
app/add.js
19
app/add.js
|
@ -16,8 +16,9 @@ let axios; (async()=>{
|
||||||
ca: await fs.readFile(env.CA_CERT_FILE),
|
ca: await fs.readFile(env.CA_CERT_FILE),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
} catch (err) { console.log(err) }
|
} catch (err) { console.error(err) }
|
||||||
})()
|
})()
|
||||||
|
const dns_key = `hmac-sha512:wgapi-${env.LOCAL_SERVER}:${env.DNS_KEY}`
|
||||||
|
|
||||||
module.exports = async (req, res) => {
|
module.exports = async (req, res) => {
|
||||||
const new_hostname = req.query['name']
|
const new_hostname = req.query['name']
|
||||||
|
@ -116,7 +117,19 @@ AllowedIPs = ${ipv4_addr}/32, ${ipv6_addr}/128`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Nameserver config
|
// Update nameserver
|
||||||
|
const domain = `${new_hostname}.${user.name}.${env.TLD}.`
|
||||||
|
try {
|
||||||
|
await helper.nsUpdate(dns_key, env.DNS_MASTER,
|
||||||
|
`update add ${domain} ${env.DNS_TTL} A ${ipv4_addr}
|
||||||
|
update add ${domain} ${env.DNS_TTL} AAAA ${ipv6_addr}
|
||||||
|
update add *.${domain} ${env.DNS_TTL} CNAME ${domain}`)
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.error(`Failed to add ns record:\n${err}`)
|
||||||
|
return res.sendStatus(500)
|
||||||
|
}
|
||||||
|
finally { console.log(`Updated nameserver to add ${domain}.`) }
|
||||||
|
|
||||||
// Generate user config
|
// Generate user config
|
||||||
const listen_port = Math.floor(50000 + Math.random() * 10000)
|
const listen_port = Math.floor(50000 + Math.random() * 10000)
|
||||||
|
@ -130,6 +143,6 @@ ${client_peers.join('\n')}`
|
||||||
|
|
||||||
// Send config to user
|
// Send config to user
|
||||||
res.setHeader('content-type', 'text/plain')
|
res.setHeader('content-type', 'text/plain')
|
||||||
res.send(config)
|
return res.send(config)
|
||||||
|
|
||||||
}
|
}
|
202
app/del.js
202
app/del.js
|
@ -18,6 +18,7 @@ let axios; (async()=>{
|
||||||
})
|
})
|
||||||
} catch (err) { console.log(err) }
|
} catch (err) { console.log(err) }
|
||||||
})()
|
})()
|
||||||
|
const dns_key = `hmac-sha512:wgapi-${env.LOCAL_SERVER}:${env.DNS_KEY}`
|
||||||
|
|
||||||
module.exports = async (req, res) => {
|
module.exports = async (req, res) => {
|
||||||
console.log(`Received request from ${req.requester} to delete ${JSON.stringify(req.query)}`)
|
console.log(`Received request from ${req.requester} to delete ${JSON.stringify(req.query)}`)
|
||||||
|
@ -27,95 +28,118 @@ module.exports = async (req, res) => {
|
||||||
catch (err) {
|
catch (err) {
|
||||||
console.error(`Failed to get user from ${req.requester}`)
|
console.error(`Failed to get user from ${req.requester}`)
|
||||||
return res.sendStatus(err)
|
return res.sendStatus(err)
|
||||||
} console.log(`${req.requester} must be ${user.name}`)
|
} finally {
|
||||||
|
console.log(`${req.requester} must be ${user.name}`)
|
||||||
// Check user token
|
|
||||||
if (req.query['token']!==helper.getToken(req.requester)) {
|
// Check user token
|
||||||
console.log(`Invalid token from ${req.requester}: ${req.query['token']}`)
|
if (req.query['token']!==helper.getToken(req.requester)) {
|
||||||
return res.sendStatus(403)
|
console.log(`Invalid token from ${req.requester}: ${req.query['token']}`)
|
||||||
}
|
return res.sendStatus(403)
|
||||||
|
|
||||||
// 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); return res.sendStatus(500) }
|
|
||||||
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)
|
|
||||||
return res.sendStatus(500)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
console.error(`${req.requester} sent delete request without specifying a peer`)
|
|
||||||
return res.sendStatus(400)
|
|
||||||
}
|
|
||||||
})[0]
|
|
||||||
if (peer===undefined) {
|
|
||||||
console.log(`No peer found for delete request from ${req.requester}`)
|
|
||||||
return res.sendStatus(404)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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}`,'')
|
|
||||||
.replace('\n\n\n','\n\n')
|
|
||||||
)
|
|
||||||
} catch (err) {
|
|
||||||
console.error(`Failed to delete ${peer_name}:\n`,err)
|
|
||||||
return res.sendStatus(500)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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?secret=${server.secret}`, peer_pubkey, {
|
|
||||||
headers: {'Content-Type': 'text/plain'},
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
console.error(`Failed to inform ${server.host} to delete ${peer_name}:\n\n`,err)
|
|
||||||
return res.sendStatus(500)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load wg.conf
|
||||||
|
let config_file
|
||||||
|
try { config_file = await fs.readFile(env.WG_CONFIG_FILE) }
|
||||||
|
catch (err) { console.error(err); return res.sendStatus(500) }
|
||||||
|
finally {
|
||||||
|
|
||||||
|
// Search for peer
|
||||||
|
let peer_pubkey
|
||||||
|
const config = config_file.toString()
|
||||||
|
const peer = config.split('\n\n')
|
||||||
|
.filter( (paragraph) => {
|
||||||
|
return paragraph.includes('[Peer]')
|
||||||
|
}).filter( (peer) => {
|
||||||
|
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']) {
|
||||||
|
// .filter() doesn't support async so use then/catch in this block
|
||||||
|
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)
|
||||||
|
return res.sendStatus(500)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.error(`${req.requester} sent delete request without specifying a peer`)
|
||||||
|
return res.sendStatus(400)
|
||||||
|
}
|
||||||
|
})[0]
|
||||||
|
if (peer===undefined) {
|
||||||
|
console.log(`No peer found for delete request from ${req.requester}`)
|
||||||
|
return res.sendStatus(404)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 local wg config
|
||||||
|
console.log(`Deleting ${peer_name}`); try {
|
||||||
|
await fs.writeFile(env.WG_CONFIG_FILE,
|
||||||
|
config.replace(`\n\n${peer}`,'')
|
||||||
|
.replace('\n\n\n','\n\n')
|
||||||
|
)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Failed to delete ${peer_name}:\n`,err)
|
||||||
|
return res.sendStatus(500)
|
||||||
|
} finally {
|
||||||
|
|
||||||
|
// 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?secret=${server.secret}`, peer_pubkey, {
|
||||||
|
headers: {'Content-Type': 'text/plain'},
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Failed to inform ${server.host} to delete ${peer_name}:\n\n`,err)
|
||||||
|
return res.sendStatus(500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete domains from nameserver
|
||||||
|
try {
|
||||||
|
await helper.nsUpdate(dns_key, env.DNS_MASTER,
|
||||||
|
`update delete ${peer_name}. A
|
||||||
|
update delete ${peer_name}. AAAA
|
||||||
|
update delete *.${peer_name}. CNAME`)
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.error(`Failed to delete ns record:\n${err}`)
|
||||||
|
return res.sendStatus(500)
|
||||||
|
}
|
||||||
|
finally { console.log(`Updated nameserver to delete ${peer_name}.`) }
|
||||||
|
|
||||||
|
// Inform user that delete was successful
|
||||||
|
res.sendStatus(200)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inform user that delete was successful
|
|
||||||
res.sendStatus(200)
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -2,80 +2,115 @@
|
||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
const env = require(process.argv[2]||'../env/env.json')
|
const env = require(process.argv[2]||'../env/env.json')
|
||||||
const fs = require('fs').promises
|
const fs = require('fs').promises
|
||||||
|
const spawn = require('child_process').spawn
|
||||||
|
|
||||||
let tokens = {}
|
let tokens = {}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
getUserFromIp: async (ip) => new Promise( async (resolve, reject) => {
|
getUserFromIp: (ip) =>
|
||||||
|
new Promise( async (resolve, reject) => {
|
||||||
|
|
||||||
// Get subnet (number)
|
// Get subnet (number)
|
||||||
let subnet
|
let subnet
|
||||||
if (ip.includes(env.IPV4_NET)) subnet = ip.split('.').slice(-2,-1)[0]
|
if (ip.includes(env.IPV4_NET)) subnet = ip.split('.').slice(-2,-1)[0]
|
||||||
else if (ip.includes(env.IPV6_NET)) subnet = ip.split(':').slice(-2,-1)[0]
|
else if (ip.includes(env.IPV6_NET)) subnet = ip.split(':').slice(-2,-1)[0]
|
||||||
else console.log(`Received request from ${ip}, which does not appear to be from the network.`)
|
else console.log(`Received request from ${ip}, which does not appear to be from the network.`)
|
||||||
|
|
||||||
// Read wg.conf file for this user's other devices
|
// Read wg.conf file for this user's other devices
|
||||||
let userpeers; try {
|
let userpeers; try {
|
||||||
userpeers = (await fs.readFile(env.WG_CONFIG_FILE)).toString()
|
userpeers = (await fs.readFile(env.WG_CONFIG_FILE)).toString()
|
||||||
.split('\n\n').filter( (paragraph) => {
|
.split('\n\n').filter( (paragraph) => {
|
||||||
return paragraph.includes('[Peer]')
|
return paragraph.includes('[Peer]')
|
||||||
}).filter( (peer) => {
|
}).filter( (peer) => {
|
||||||
return peer.includes(`${env.IPV4_NET}.${subnet}`) || peer.includes(`${env.IPV6_NET}:${subnet}`)
|
return peer.includes(`${env.IPV4_NET}.${subnet}`) || peer.includes(`${env.IPV6_NET}:${subnet}`)
|
||||||
})
|
})
|
||||||
} catch (err) { console.log(err) }
|
} catch (err) { console.log(err) }
|
||||||
let found_usernames = []
|
let found_usernames = []
|
||||||
let found_hosts = []
|
let found_hosts = []
|
||||||
for (const userpeer of userpeers) {
|
for (const userpeer of userpeers) {
|
||||||
let userpeer_obj = {}
|
let userpeer_obj = {}
|
||||||
for (const line of userpeer.split('\n')) {
|
for (const line of userpeer.split('\n')) {
|
||||||
if (line.includes('[Peer] # ')) {
|
if (line.includes('[Peer] # ')) {
|
||||||
const domain = line.split(' # ')[1].split('.')
|
const domain = line.split(' # ')[1].split('.')
|
||||||
userpeer_obj.name = domain[0]
|
userpeer_obj.name = domain[0]
|
||||||
found_usernames.push(domain[1])
|
found_usernames.push(domain[1])
|
||||||
}
|
}
|
||||||
else if (line.includes('AllowedIPs = ')) {
|
else if (line.includes('AllowedIPs = ')) {
|
||||||
const ips = line.split('=')[1].split(', ')
|
const ips = line.split('=')[1].split(', ')
|
||||||
userpeer_obj.ipv4 = ips.filter( (ip) => ip.includes(env.IPV4_NET) )[0].trim()
|
userpeer_obj.ipv4 = ips.filter( (ip) => ip.includes(env.IPV4_NET) )[0].trim()
|
||||||
userpeer_obj.ipv6 = ips.filter( (ip) => ip.includes(env.IPV6_NET) )[0].trim()
|
userpeer_obj.ipv6 = ips.filter( (ip) => ip.includes(env.IPV6_NET) )[0].trim()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
found_hosts.push(userpeer_obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that all IP addresses are in correct subnet or error out
|
||||||
|
if (!found_hosts.every((host) =>
|
||||||
|
host.ipv4.includes(`${env.IPV4_NET}.${subnet}.`) &&
|
||||||
|
host.ipv6.includes(`${env.IPV6_NET}:${subnet}:`)
|
||||||
|
)) {
|
||||||
|
console.error(
|
||||||
|
`Found unmatching IP address subnets for ${ip}: \
|
||||||
|
${found_hosts.map( (host) => [host.ipv4,host.ipv6] )}`
|
||||||
|
); reject(500)
|
||||||
|
// Check that the ip is "on the list"
|
||||||
|
// Should never get here because this ip can't access this IP!
|
||||||
|
} else if (found_usernames.length ===0) {
|
||||||
|
console.error(`Received request from ${ip} not in wg.conf!`)
|
||||||
|
reject(403)
|
||||||
|
// Check that all usernames are the same correct or error out
|
||||||
|
// https://stackoverflow.com/a/35568895
|
||||||
|
} else if (!found_usernames.every( (v,i,r) => v === r[0] )) {
|
||||||
|
console.error(`Found unmatching usernames for ${ip}: ${found_usernames.toString()}`)
|
||||||
|
reject(500)
|
||||||
|
} else {
|
||||||
|
resolve({
|
||||||
|
name: found_usernames[0],
|
||||||
|
subnet: subnet,
|
||||||
|
peers: found_hosts,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
found_hosts.push(userpeer_obj)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that all IP addresses are in correct subnet or error out
|
|
||||||
if (!found_hosts.every((host) =>
|
|
||||||
host.ipv4.includes(`${env.IPV4_NET}.${subnet}.`) &&
|
|
||||||
host.ipv6.includes(`${env.IPV6_NET}:${subnet}:`)
|
|
||||||
)) {
|
|
||||||
console.error(
|
|
||||||
`Found unmatching IP address subnets for ${ip}: \
|
|
||||||
${found_hosts.map( (host) => [host.ipv4,host.ipv6] )}`
|
|
||||||
); reject(500)
|
|
||||||
// Check that the ip is "on the list"
|
|
||||||
// Should never get here because this ip can't access this IP!
|
|
||||||
} else if (found_usernames.length ===0) {
|
|
||||||
console.error(`Received request from ${ip} not in wg.conf!`)
|
|
||||||
reject(403)
|
|
||||||
// Check that all usernames are the same correct or error out
|
|
||||||
// https://stackoverflow.com/a/35568895
|
|
||||||
} else if (!found_usernames.every( (v,i,r) => v === r[0] )) {
|
|
||||||
console.error(`Found unmatching usernames for ${ip}: ${found_usernames.toString()}`)
|
|
||||||
reject(500)
|
|
||||||
} else {
|
|
||||||
resolve({
|
|
||||||
name: found_usernames[0],
|
|
||||||
subnet: subnet,
|
|
||||||
peers: found_hosts,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
setToken: async (ip) => new Promise ( async (resolve, reject) => {
|
|
||||||
try {
|
|
||||||
tokens[ip] = await crypto.randomBytes(40).toString('hex')
|
|
||||||
} catch (err) { reject(err) }
|
|
||||||
resolve(tokens[ip])
|
|
||||||
}),
|
|
||||||
getToken: (ip) => tokens[ip],
|
getToken: (ip) => tokens[ip],
|
||||||
|
setToken: (ip) =>
|
||||||
|
new Promise ( async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
tokens[ip] = await crypto.randomBytes(40).toString('hex')
|
||||||
|
} catch (err) { reject(err) }
|
||||||
|
resolve(tokens[ip])
|
||||||
|
}),
|
||||||
|
|
||||||
|
nsUpdate: (key, server, payload) =>
|
||||||
|
new Promise( (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
|
||||||
|
let nsupdate = spawn('nsupdate', ['-y', key])
|
||||||
|
|
||||||
|
// Collect output
|
||||||
|
let errors = ''
|
||||||
|
nsupdate.stdout.on('data', (data) => {
|
||||||
|
console.log(`nsupdate stdout: ${data}`)
|
||||||
|
})
|
||||||
|
nsupdate.stderr.on('data', (data) => {
|
||||||
|
console.error(`nsupdate stderr: ${data}`)
|
||||||
|
errors += data
|
||||||
|
})
|
||||||
|
|
||||||
|
// Send data
|
||||||
|
nsupdate.stdin.write(`server ${server}\n${payload}\nsend\nquit`)
|
||||||
|
nsupdate.stdin.end()
|
||||||
|
|
||||||
|
// Handle exit
|
||||||
|
nsupdate.on('error', (err) => { reject(err) })
|
||||||
|
nsupdate.on('exit', (status) => {
|
||||||
|
if (status===0) reject(errors)
|
||||||
|
else resolve()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Something went wrong with the spawn?
|
||||||
|
} catch (err) { reject(err) }
|
||||||
|
}),
|
||||||
|
|
||||||
}
|
}
|
6
index.js
6
index.js
|
@ -8,6 +8,8 @@ const mw = require('./includes/middleware.js')
|
||||||
const express = require('express')
|
const express = require('express')
|
||||||
const app = express()
|
const app = express()
|
||||||
const admin = express()
|
const admin = express()
|
||||||
|
const helper = require('./includes/helpers')
|
||||||
|
const dns_key = `hmac-sha512:wgapi-${env.LOCAL_SERVER}:${env.DNS_KEY}`
|
||||||
|
|
||||||
app
|
app
|
||||||
.use(mw.getRequester)
|
.use(mw.getRequester)
|
||||||
|
@ -16,6 +18,7 @@ app
|
||||||
.get('/add', mw.getDnsServers, require('./app/add.js'))
|
.get('/add', mw.getDnsServers, require('./app/add.js'))
|
||||||
.get('/del', require('./app/del.js'))
|
.get('/del', require('./app/del.js'))
|
||||||
.listen(env.PORT)
|
.listen(env.PORT)
|
||||||
|
|
||||||
admin
|
admin
|
||||||
.use(mw.getAdminRequester)
|
.use(mw.getAdminRequester)
|
||||||
.use(mw.allowServers)
|
.use(mw.allowServers)
|
||||||
|
@ -23,4 +26,5 @@ admin
|
||||||
.post('/add', require('./admin/add.js'))
|
.post('/add', require('./admin/add.js'))
|
||||||
.post('/del', require('./admin/del.js'))
|
.post('/del', require('./admin/del.js'))
|
||||||
.listen(env.ADMIN_PORT)
|
.listen(env.ADMIN_PORT)
|
||||||
console.log('Server started')
|
|
||||||
|
console.log('Server started')
|
Loading…
Reference in New Issue