fst – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 #!/usr/bin/env node
2  
3 const MetricsData = require('./MetricsData.js')
4 const SyncData = require('./SyncData.js')
5 const symmetric = require('./symmetric.js')
6 const fs = require('fs')
7 const path = require('path')
8 const YAML = require('yamljs')
9 const { createLogger, format, transports } = require('winston')
10 const net = require('net')
11 const express = require('express')
12 const whois = require('whois')
13 const marked = require('marked')
14 const passport = require('passport')
15 const Strategy = require('passport-local').Strategy
16  
17 // Set options for marked.js
18 marked.setOptions({
19 renderer: new marked.Renderer(),
20 highlight: function (code) {
21 return require('highlight.js').highlightAuto(code).value
22 },
23 pedantic: false,
24 gfm: true,
25 tables: true,
26 breaks: true,
27 sanitize: false,
28 smartLists: true,
29 smartypants: false,
30 xhtml: false
31 })
32  
33 // Load configuration file.
34 const config = YAML.load(
35 path.join(
36 path.dirname(
37 require.main.filename
38 ),
39 'config.yml'
40 )
41 )
42  
43 // Set up logger.
44 const logger = createLogger({
45 format: format.combine(
46 format.splat(),
47 format.simple()
48 ),
49 transports: [
50 new transports.Console(),
51 new transports.File({ filename: config.log })
52 ]
53 })
54  
55 // Initialize the metrics object.
56 var metrics
57 try {
58 const store = fs.readFileSync(config.metrics.store)
59 metrics = MetricsData.fromJSON(store)
60 logger.log('info', 'metrics store has been loaded %s', config.metrics.store)
61 } catch (error) {
62 logger.info('store file not found, starting fresh')
63 metrics = new MetricsData()
64 }
65  
66 // Create socket server to listen for payloads.
67 var server = net.createServer({ host: config.metrics.host, port: config.metrics.port }, function (stream) {
68 stream.on('data', processPayload)
69 }).on('listening', function () {
70 logger.info('metrics server running, waiting for payloads')
71 }).on('error', function (error) {
72 logger.log('error', 'metrics server could not listen on configured host %s and port %s',
73 config.metrics.host,
74 config.metrics.port
75 )
76 })
77  
78 // Listen on the configured socket.
79 server.listen(config.metrics.port, config.metrics.host)
80  
81 // Initialize passport authentication.
82 passport.use(new Strategy(passportStrategy))
83 passport.serializeUser(passportSerializeUser)
84 passport.deserializeUser(passportDeserializeUser)
85  
86 // Set up web server.
87 const app = express()
88  
89 // Configure view engine to render EJS templates.
90 app.set('views', config.metrics.wwwroot)
91 app.set('view engine', 'ejs')
92  
93 // Static files
94 app.use(express.static(config.metrics.wwwroot))
95  
96 // Use application-level middleware for common functionality, including
97 // logging, parsing, and session handling.
98 app.use(require('cookie-parser')())
99 app.use(require('body-parser').urlencoded({ extended: true }))
100 app.use(require('express-session')({ secret: 'shazam', resave: false, saveUninitialized: false }))
101  
102 // Initialize Passport and restore authentication state, if any, from the
103 // session.
104 app.use(passport.initialize())
105 app.use(passport.session())
106  
107 app.listen(config.metrics.wwwport, () => {
108 logger.log('info', 'web interface listening on port %s', config.metrics.wwwport)
109 })
110  
111 // Login, logout and user processing.
112 app.get('/',
113 (req, res) => {
114 res.render('login', { user: req.user })
115 })
116  
117 app.get('/login',
118 (req, res) => {
119 res.render('login')
120 })
121  
122 app.post('/login',
123 passport.authenticate('local', { failureRedirect: '/unauthorized' }),
124 (req, res) => {
125 res.render('index')
126 })
127  
128 app.get('/logout',
129 (req, res) => {
130 req.logout()
131 res.redirect('/')
132 })
133  
134 app.get('/unauthorized',
135 (req, res) => {
136 res.render('unauthorized')
137 })
138  
139 // All views.
140 // All EJS: fs.readdirSync(config.metrics.wwwroot).filter((view) => /\.ejs$/.test(view)).map((view) => `/${view.replace(/\.ejs$/gm, '')}`)
141 app.get('/index',
142 require('connect-ensure-login').ensureLoggedIn(),
143 (req, res) => {
144 const view = req.originalUrl.replace(/^\//gm, '')
145 res.render(view, { user: req.user, view: view })
146 })
147  
148 // Send metrics.
149 app.get('/metrics',
150 require('connect-ensure-login').ensureLoggedIn(),
151 (req, res) =>
152 res.send(JSON.stringify(metrics)))
153  
154 // Process whois requests.
155 app.get('/whois/:host',
156 require('connect-ensure-login').ensureLoggedIn(),
157 (req, res) => {
158 whois.lookup(req.params.host, (err, data) => {
159 if (err) {
160 res.send('Failed to retireve WHOIS information. Please try again later...')
161 return
162 }
163 res.send(marked(data))
164 })
165 })
166  
167 // Retrieve a list of peers.
168 app.get('/peers',
169 require('connect-ensure-login').ensureLoggedIn(),
170 (req, res) => {
171 res.send(JSON.stringify(metrics.peers))
172 })
173  
174 function passportSerializeUser(user, cb) {
175 cb(null, user.id)
176 }
177  
178 function passportDeserializeUser(id, cb) {
179 var user = config.metrics.users.filter((user) => {
180 return user.id === id
181 }).shift()
182  
183 if (typeof user === 'undefined' || user === null)
184 return cb(err)
185  
186 return cb(null, user)
187 }
188  
189 function passportStrategy(username, password, cb) {
190 var user = config.metrics.users.filter((user) => {
191 return user.username === username && user.password === password
192 }).shift()
193  
194 if (typeof user === 'undefined' || user === null)
195 return cb(null, false)
196  
197 return cb(null, user)
198 }
199  
200 function processPayload(message) {
201 // Decrypt the payload.
202 var decrypted = ""
203 try {
204 decrypted = symmetric.decrypt(message, config.secret)
205 }
206 catch (error) {
207 logger.log('warn', 'decrypting payload %s failed with error %s', message, error)
208 return
209 }
210  
211 // Deserialize the payload.
212 var syncMessage
213 try {
214 syncMessage = SyncData.fromJSON(decrypted)
215 } catch (error) {
216 // Not a sync message so ignore it.
217 return
218 }
219  
220 metrics.update(syncMessage)
221  
222 var json = JSON.stringify(metrics)
223  
224 logger.log('info', 'metrics updated %s', json)
225  
226 fs.writeFile(config.metrics.store, json, function (error) {
227 if (error) {
228 logger.log('error', 'could not write metrics file %s', config.metrics.store)
229 }
230 })
231  
232 }