lamassu-server/bin/lamassu-admin-server
2016-12-20 14:23:00 +02:00

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')
})
}