198 lines
5.1 KiB
TypeScript
198 lines
5.1 KiB
TypeScript
import { Router } from 'express'
|
|
import expressBasicAuth from 'express-basic-auth'
|
|
import { body, header, validationResult } from 'express-validator'
|
|
import register from './register'
|
|
import { CreateKillRecord, CheckServerToken } from '../db/db'
|
|
|
|
const router = Router()
|
|
|
|
router.use('/', register)
|
|
|
|
//auth middleware
|
|
router.post(
|
|
'/servers/:serverId/kill',
|
|
header('authorization')
|
|
.exists({ checkFalsy: true })
|
|
.withMessage('Missing Authorization Header')
|
|
.bail()
|
|
.contains('Basic')
|
|
.withMessage('Authorization Token is not Basic'),
|
|
(req, res, next) => {
|
|
const errors = validationResult(req)
|
|
if (!errors.isEmpty()) {
|
|
console.log(JSON.stringify(errors))
|
|
return res.status(403).json({ errors: errors.array() })
|
|
}
|
|
next()
|
|
},
|
|
//Huge mess to retrieve server id from expressBasicAuth. We probably should fix it.
|
|
(req, res, next) => {
|
|
if (!req) res.send(500)
|
|
return expressBasicAuth({
|
|
authorizeAsync: true,
|
|
authorizer: CheckServerToken.bind(req),
|
|
unauthorizedResponse: { error: 'invalid credentials' }
|
|
})(req as any, res, next)
|
|
}
|
|
)
|
|
|
|
const serversCount: { [id: string]: number } = {}
|
|
const serversTimeout: { [id: string]: NodeJS.Timeout } = {}
|
|
|
|
//same rate limiting code as register. max 10 kills per server every 1 sec. should be enough.
|
|
router.post('/servers/:serverId/kill', (req, res, next) => {
|
|
let serverId = req.body.serverId || 'undefined'
|
|
if (serversCount[serverId] > 2) {
|
|
return res.status(429).json({
|
|
error: 'too many requests. Are players really making that much kills ?'
|
|
})
|
|
}
|
|
clearTimeout(serversTimeout[serverId])
|
|
serversCount[serverId] =
|
|
serversCount[serverId] ?? (serversCount[serverId] + 1) | 1
|
|
serversTimeout[serverId] = setTimeout(() => {
|
|
serversCount[serverId] = 0
|
|
}, 1000)
|
|
next()
|
|
})
|
|
|
|
router.post(
|
|
'/servers/:serverId/kill',
|
|
body([
|
|
'attacker_current_weapon_mods',
|
|
'attacker_weapon_1_mods',
|
|
'attacker_weapon_2_mods',
|
|
'attacker_weapon_3_mods',
|
|
'attacker_offhand_weapon_1',
|
|
'attacker_offhand_weapon_2',
|
|
'distance',
|
|
'player_count',
|
|
'victim_current_weapon_mods',
|
|
'victim_weapon_1_mods',
|
|
'victim_weapon_2_mods',
|
|
'victim_weapon_3_mods',
|
|
'victim_offhand_weapon_1',
|
|
'victim_offhand_weapon_2'
|
|
])
|
|
.toInt()
|
|
.isInt()
|
|
.withMessage('must be a valid int'),
|
|
body(['distance', 'game_time'])
|
|
.toFloat()
|
|
.isFloat()
|
|
.withMessage('must be a valid float'),
|
|
body(
|
|
[
|
|
'attacker_id',
|
|
'victim_id',
|
|
'killstat_version',
|
|
'match_id',
|
|
'game_mode',
|
|
'map',
|
|
'attacker_name',
|
|
'attacker_current_weapon',
|
|
'attacker_weapon_1',
|
|
'attacker_weapon_2',
|
|
'attacker_weapon_3',
|
|
'victim_name',
|
|
'victim_current_weapon',
|
|
'victim_weapon_1',
|
|
'victim_weapon_2',
|
|
'victim_weapon_3',
|
|
'cause_of_death'
|
|
],
|
|
'must be composed of a maximum of 50 valid ascii characters'
|
|
)
|
|
.isString()
|
|
.isLength({ max: 50 })
|
|
.isAscii(),
|
|
body(['distance', 'game_time'], 'must be postitive floats').isFloat({
|
|
min: 0
|
|
}),
|
|
body(['cause_of_death', 'victim_id'], 'mandatory').exists().notEmpty(),
|
|
(req, res) => {
|
|
const errors = validationResult(req)
|
|
if (!errors.isEmpty()) {
|
|
console.log(JSON.stringify(errors))
|
|
return res.status(400).json({ errors: errors.array() })
|
|
}
|
|
const server = 1 // set server ID here
|
|
const {
|
|
killstat_version,
|
|
match_id,
|
|
game_mode,
|
|
map,
|
|
game_time,
|
|
player_count,
|
|
attacker_name,
|
|
attacker_id,
|
|
attacker_current_weapon,
|
|
attacker_current_weapon_mods,
|
|
attacker_weapon_1,
|
|
attacker_weapon_1_mods,
|
|
attacker_weapon_2,
|
|
attacker_weapon_2_mods,
|
|
attacker_weapon_3,
|
|
attacker_weapon_3_mods,
|
|
attacker_offhand_weapon_1,
|
|
attacker_offhand_weapon_2,
|
|
victim_name,
|
|
victim_id,
|
|
victim_current_weapon,
|
|
victim_current_weapon_mods,
|
|
victim_weapon_1,
|
|
victim_weapon_1_mods,
|
|
victim_weapon_2,
|
|
victim_weapon_2_mods,
|
|
victim_weapon_3,
|
|
victim_weapon_3_mods,
|
|
victim_offhand_weapon_1,
|
|
victim_offhand_weapon_2,
|
|
cause_of_death,
|
|
distance
|
|
} = req.body
|
|
CreateKillRecord({
|
|
killstat_version,
|
|
server,
|
|
match_id,
|
|
game_mode,
|
|
map,
|
|
game_time,
|
|
player_count,
|
|
attacker_name,
|
|
attacker_id,
|
|
attacker_current_weapon,
|
|
attacker_current_weapon_mods,
|
|
attacker_weapon_1,
|
|
attacker_weapon_1_mods,
|
|
attacker_weapon_2,
|
|
attacker_weapon_2_mods,
|
|
attacker_weapon_3,
|
|
attacker_weapon_3_mods,
|
|
attacker_offhand_weapon_1,
|
|
attacker_offhand_weapon_2,
|
|
victim_name,
|
|
victim_id,
|
|
victim_current_weapon,
|
|
victim_current_weapon_mods,
|
|
victim_weapon_1,
|
|
victim_weapon_1_mods,
|
|
victim_weapon_2,
|
|
victim_weapon_2_mods,
|
|
victim_weapon_3,
|
|
victim_weapon_3_mods,
|
|
victim_offhand_weapon_1,
|
|
victim_offhand_weapon_2,
|
|
cause_of_death,
|
|
distance
|
|
})
|
|
.then((e) => {
|
|
res.send(201)
|
|
})
|
|
.catch((e) => {
|
|
res.send(500)
|
|
})
|
|
}
|
|
)
|
|
export default router
|