fst – Rev 1

Subversion Repositories:
Rev:
#!/usr/bin/env node

const MetricsData = require('./MetricsData.js')
const SyncData = require('./SyncData.js')
const symmetric = require('./symmetric.js')
const fs = require('fs')
const path = require('path')
const YAML = require('yamljs')
const { createLogger, format, transports } = require('winston')
const net = require('net')
const express = require('express')
const whois = require('whois')
const marked = require('marked')
const passport = require('passport')
const Strategy = require('passport-local').Strategy

// Set options for marked.js
marked.setOptions({
    renderer: new marked.Renderer(),
    highlight: function (code) {
        return require('highlight.js').highlightAuto(code).value
    },
    pedantic: false,
    gfm: true,
    tables: true,
    breaks: true,
    sanitize: false,
    smartLists: true,
    smartypants: false,
    xhtml: false
})

// Load configuration file.
const config = YAML.load(
    path.join(
        path.dirname(
            require.main.filename
        ),
        'config.yml'
    )
)

// Set up logger.
const logger = createLogger({
    format: format.combine(
        format.splat(),
        format.simple()
    ),
    transports: [
        new transports.Console(),
        new transports.File({ filename: config.log })
    ]
})

// Initialize the metrics object.
var metrics
try {
    const store = fs.readFileSync(config.metrics.store)
    metrics = MetricsData.fromJSON(store)
    logger.log('info', 'metrics store has been loaded %s', config.metrics.store)
} catch (error) {
    logger.info('store file not found, starting fresh')
    metrics = new MetricsData()
}

// Create socket server to listen for payloads.
var server = net.createServer({ host: config.metrics.host, port: config.metrics.port }, function (stream) {
    stream.on('data', processPayload)
}).on('listening', function () {
    logger.info('metrics server running, waiting for payloads')
}).on('error', function (error) {
    logger.log('error', 'metrics server could not listen on configured host %s and port %s',
        config.metrics.host,
        config.metrics.port
    )
})

// Listen on the configured socket.
server.listen(config.metrics.port, config.metrics.host)

// Initialize passport authentication.
passport.use(new Strategy(passportStrategy))
passport.serializeUser(passportSerializeUser)
passport.deserializeUser(passportDeserializeUser)

// Set up web server.
const app = express()

// Configure view engine to render EJS templates.
app.set('views', config.metrics.wwwroot)
app.set('view engine', 'ejs')

// Static files
app.use(express.static(config.metrics.wwwroot))

// Use application-level middleware for common functionality, including
// logging, parsing, and session handling.
app.use(require('cookie-parser')())
app.use(require('body-parser').urlencoded({ extended: true }))
app.use(require('express-session')({ secret: 'shazam', resave: false, saveUninitialized: false }))

// Initialize Passport and restore authentication state, if any, from the
// session.
app.use(passport.initialize())
app.use(passport.session())

app.listen(config.metrics.wwwport, () => {
    logger.log('info', 'web interface listening on port %s', config.metrics.wwwport)
})

// Login, logout and user processing.
app.get('/',
    (req, res) => {
        res.render('login', { user: req.user })
    })

app.get('/login',
    (req, res) => {
        res.render('login')
    })

app.post('/login',
    passport.authenticate('local', { failureRedirect: '/unauthorized' }),
    (req, res) => {
        res.render('index')
    })

app.get('/logout',
    (req, res) => {
        req.logout()
        res.redirect('/')
    })

app.get('/unauthorized',
    (req, res) => {
        res.render('unauthorized')
    })

// All views.
// All EJS: fs.readdirSync(config.metrics.wwwroot).filter((view) => /\.ejs$/.test(view)).map((view) => `/${view.replace(/\.ejs$/gm, '')}`)
app.get('/index',
    require('connect-ensure-login').ensureLoggedIn(),
    (req, res) => {
        const view = req.originalUrl.replace(/^\//gm, '')
        res.render(view, { user: req.user, view: view })
    })

// Send metrics.
app.get('/metrics',
    require('connect-ensure-login').ensureLoggedIn(),
    (req, res) =>
        res.send(JSON.stringify(metrics)))

// Process whois requests.
app.get('/whois/:host',
    require('connect-ensure-login').ensureLoggedIn(),
    (req, res) => {
        whois.lookup(req.params.host, (err, data) => {
            if (err) {
                res.send('Failed to retireve WHOIS information. Please try again later...')
                return
            }
            res.send(marked(data))
        })
    })

// Retrieve a list of peers.
app.get('/peers',
    require('connect-ensure-login').ensureLoggedIn(),
    (req, res) => {
        res.send(JSON.stringify(metrics.peers))
    })

function passportSerializeUser(user, cb) {
    cb(null, user.id)
}

function passportDeserializeUser(id, cb) {
    var user = config.metrics.users.filter((user) => {
        return user.id === id
    }).shift()

    if (typeof user === 'undefined' || user === null)
        return cb(err)

    return cb(null, user)
}

function passportStrategy(username, password, cb) {
    var user = config.metrics.users.filter((user) => {
        return user.username === username && user.password === password
    }).shift()

    if (typeof user === 'undefined' || user === null)
        return cb(null, false)

    return cb(null, user)
}

function processPayload(message) {
    // Decrypt the payload.
    var decrypted = ""
    try {
        decrypted = symmetric.decrypt(message, config.secret)
    }
    catch (error) {
        logger.log('warn', 'decrypting payload %s failed with error %s', message, error)
        return
    }

    // Deserialize the payload.
    var syncMessage
    try {
        syncMessage = SyncData.fromJSON(decrypted)
    } catch (error) {
        // Not a sync message so ignore it.
        return
    }

    metrics.update(syncMessage)

    var json = JSON.stringify(metrics)

    logger.log('info', 'metrics updated %s', json)

    fs.writeFile(config.metrics.store, json, function (error) {
        if (error) {
            logger.log('error', 'could not write metrics file %s', config.metrics.store)
        }
    })

}

Generated by GNU Enscript 1.6.5.90.