-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
102 lines (93 loc) · 3.18 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
const { send, json } = require('micro')
const axios = require('axios')
const util = require('util')
const JWT = require('jsonwebtoken')
const { URL } = require('url')
const verifyAsync = util.promisify(JWT.verify)
const grafana = axios.create({ baseURL: process.env.GRAFANA_URL })
const backend = axios.create({ baseURL: process.env.BACKEND_URL })
const JWT_ALGORITHM = process.env.JWT_ALGORITHM
const JWT_PUBLIC = process.env.JWT_PUBLIC
const JWT_SECRET = process.env.JWT_SECRET
const ALLOWED_ORIGINS = process.env.ALLOWED_ORIGINS
module.exports = async (req, res) => {
const { origin } = req.headers
const { pathname, searchParams } = new URL(req.url, 'http://localhost')
const allowed = ALLOWED_ORIGINS.toLowerCase().split(' ')
if (origin && allowed.includes(origin.toLowerCase())) {
res.setHeader('access-control-allow-origin', origin)
res.setHeader('access-control-allow-methods', 'POST, GET')
res.setHeader('access-control-allow-headers', 'Content-Type, *')
res.setHeader('access-control-allow-credentials', 'true')
}
req.query = searchParams
if (pathname.match('/healthz')) return { healthy: true }
if (pathname.match('/find')) return find(req, res)
if (pathname.match('/render$')) return render(req, res)
send(res, 404, { error: 'Not found' })
}
async function auth(req) {
if (!req.headers.authorization) return false
const [type, value] = req.headers.authorization.split(' ') || []
if (!type || !value) return false
if (type !== 'Bearer') return false
const data = await verifyAsync(value, JWT_PUBLIC || JWT_SECRET, { algorithm: JWT_ALGORITHM })
if (!data.scope || !data.scope.includes('read:stats')) {
throw new Error('Unauthorized')
}
return data
}
async function find (req, res) {
const { query: params } = req
let query = params.get('query')
if (query === '*' || query === 'screeps') {
return metricMap(['screeps'], '')
}
const orgs = await getOrgs(req)
let [, user = ''] = query.split('.')
query = query.replace(user, user.toLowerCase())
user = user.toLowerCase()
let valid = orgs.includes(user)
if (user === '*') {
const acl = `{${orgs.join(',')}}`
query = query.replace('screeps.*', `screeps.${acl}`)
valid = true
}
if (valid) {
const resp = await backend.get('/metrics/find', { params: { query } })
return resp.data
} else {
send(res, 403, { error: 'Forbidden' })
}
}
async function render (req, res) {
let orgs = await getOrgs(req)
let acl = `{${orgs.join(',')}}`
let body = await json(req)
body.target = body.target.map(target => {
let [section, user] = target.split('.')
let valid = section === 'screeps' && orgs.includes(user)
if (user === '*') {
target = target.replace('screeps.*', `screeps.${acl}`)
valid = true
}
return valid ? target : null
}).filter(a => a)
let resp = await backend.post('/render', body)
return resp.data
}
async function getOrgs (req) {
const user = auth(req)
if (!user) return []
// TODO: Get this list dynamically
return [user.username || user.nickname]
}
function metricMap (list, base) {
return list.map(item => ({
id: base ? `${base}.${item}` : item,
allowChildren: 1,
expandable: 1,
leaf: 0,
text: item
}))
}