192 lines
4.8 KiB
JavaScript
Executable file
192 lines
4.8 KiB
JavaScript
Executable file
#!/usr/bin/env node
|
|
|
|
const os = require('os')
|
|
const fs = require('fs')
|
|
const path = require('path')
|
|
const express = require('express')
|
|
const app = express()
|
|
const https = require('https')
|
|
const http = require('http')
|
|
const bodyParser = require('body-parser')
|
|
const serveStatic = require('serve-static')
|
|
const cookieParser = require('cookie-parser')
|
|
const argv = require('minimist')(process.argv.slice(2))
|
|
const got = require('got')
|
|
const morgan = require('morgan')
|
|
|
|
const accounts = require('../lib/admin/accounts')
|
|
const machines = require('../lib/admin/machines')
|
|
const config = require('../lib/admin/config')
|
|
const login = require('../lib/admin/login')
|
|
const pairing = require('../lib/admin/pairing')
|
|
const server = require('../lib/admin/server')
|
|
const transactions = require('../lib/admin/transactions')
|
|
const T = require('../lib/time')
|
|
|
|
const NEVER = new Date(Date.now() + 100 * T.years)
|
|
|
|
const devMode = argv.dev
|
|
|
|
let serverConfig
|
|
|
|
try {
|
|
const homeConfigPath = path.resolve(os.homedir(), '.lamassu', 'lamassu.json')
|
|
serverConfig = JSON.parse(fs.readFileSync(homeConfigPath))
|
|
} catch (_) {
|
|
try {
|
|
const globalConfigPath = path.resolve('/etc', 'lamassu', 'lamassu.json')
|
|
serverConfig = JSON.parse(fs.readFileSync(globalConfigPath))
|
|
} catch (_) {
|
|
console.error("Couldn't open config file.")
|
|
process.exit(1)
|
|
}
|
|
}
|
|
|
|
const hostname = serverConfig.hostname
|
|
if (!hostname) {
|
|
console.error('Error: no hostname specified.')
|
|
process.exit(1)
|
|
}
|
|
|
|
function dbNotify () {
|
|
return got.post('http://localhost:3030/dbChange')
|
|
.catch(e => console.error('Error: lamassu-server not responding'))
|
|
}
|
|
|
|
const skip = (req, res) => req.path === '/api/status/' && res.statusCode === 200
|
|
|
|
app.use(morgan('dev', {skip}))
|
|
app.use(cookieParser())
|
|
app.use(register)
|
|
if (!devMode) app.use(authenticate)
|
|
|
|
app.use(bodyParser.json())
|
|
|
|
app.get('/api/totem', (req, res) => {
|
|
const name = req.query.name
|
|
|
|
if (!name) return res.status(400).send('Name is required')
|
|
|
|
return pairing.totem(hostname, name)
|
|
.then(totem => res.send(totem))
|
|
})
|
|
|
|
app.get('/api/accounts', (req, res) => {
|
|
accounts.selectedAccounts()
|
|
.then(accounts => res.json({accounts: accounts}))
|
|
})
|
|
|
|
app.get('/api/account/:account', (req, res) => {
|
|
accounts.getAccount(req.params.account)
|
|
.then(account => res.json(account))
|
|
})
|
|
|
|
app.post('/api/account', (req, res) => {
|
|
return accounts.updateAccount(req.body)
|
|
.then(account => res.json(account))
|
|
.then(() => dbNotify())
|
|
})
|
|
|
|
app.get('/api/config/:config', (req, res) =>
|
|
config.fetchConfigGroup(req.params.config).then(c => res.json(c)))
|
|
|
|
app.post('/api/config', (req, res, next) => {
|
|
config.saveConfigGroup(req.body)
|
|
.then(c => res.json(c))
|
|
.then(() => dbNotify())
|
|
.catch(next)
|
|
})
|
|
|
|
app.get('/api/accounts/account/:account', (req, res) => {
|
|
accounts.getAccount(req.params.account)
|
|
.then(r => res.send(r))
|
|
})
|
|
|
|
app.get('/api/machines', (req, res) => {
|
|
machines.getMachines()
|
|
.then(r => res.send({machines: r}))
|
|
})
|
|
|
|
app.post('/api/machines', (req, res) => {
|
|
machines.setMachine(req.body)
|
|
.then(() => machines.getMachines())
|
|
.then(r => res.send({machines: r}))
|
|
.then(() => dbNotify())
|
|
})
|
|
|
|
app.get('/api/status', (req, res, next) => {
|
|
return Promise.all([server.status(), config.validateCurrentConfig()])
|
|
.then(([serverStatus, invalidConfigGroups]) => res.send({
|
|
server: serverStatus,
|
|
invalidConfigGroups
|
|
}))
|
|
.catch(next)
|
|
})
|
|
|
|
app.get('/api/transactions', (req, res, next) => {
|
|
return transactions.batch()
|
|
.then(r => res.send({transactions: r}))
|
|
.catch(next)
|
|
})
|
|
|
|
app.use((err, req, res, next) => {
|
|
console.error(err)
|
|
|
|
return res.status(500).send(err.message)
|
|
})
|
|
|
|
const options = {
|
|
key: fs.readFileSync(serverConfig.keyPath),
|
|
cert: fs.readFileSync(serverConfig.certPath)
|
|
}
|
|
|
|
app.use(serveStatic(path.resolve(__dirname, '..', 'public')))
|
|
|
|
function register (req, res, next) {
|
|
const otp = req.query.otp
|
|
|
|
if (!otp) return next()
|
|
|
|
return login.register(otp)
|
|
.then(r => {
|
|
if (r.expired) return res.status(401).send('OTP expired, generate new registration link')
|
|
if (!r.success) return res.status(401).send('Registration failed')
|
|
|
|
const cookieOpts = {
|
|
httpOnly: true,
|
|
secure: true,
|
|
domain: hostname,
|
|
expires: NEVER
|
|
}
|
|
|
|
const token = r.token
|
|
req.token = token
|
|
res.cookie('token', token, cookieOpts)
|
|
next()
|
|
})
|
|
}
|
|
|
|
function authenticate (req, res, next) {
|
|
const token = req.token || req.cookies.token
|
|
|
|
return login.authenticate(token)
|
|
.then(success => {
|
|
if (!success) return res.status(401).send('Authentication failed')
|
|
next()
|
|
})
|
|
}
|
|
|
|
process.on('unhandledRejection', err => {
|
|
console.error(err.stack)
|
|
process.exit(1)
|
|
})
|
|
|
|
if (devMode) {
|
|
http.createServer(app).listen(8070, () => {
|
|
console.log('lamassu-admin-server listening on port 8070')
|
|
})
|
|
} else {
|
|
https.createServer(options, app).listen(443, () => {
|
|
console.log('lamassu-admin-server listening on port 443')
|
|
})
|
|
}
|