diff --git a/server/index.js b/server/index.js index 3bf23ec..70790a0 100644 --- a/server/index.js +++ b/server/index.js @@ -70,11 +70,20 @@ app.use(bodyParser.raw(parserLimits)); // eslint-disable-next-line no-unused-vars app.use((err, req, res, next) => { - console.error(err.message, err.stack); - if (err instanceof AccessDeniedError) { - return res.status(403) - .send({ error: err.message }); + + console.error(err.message, err.type, err.stack); + + if ((err instanceof AccessDeniedError) || (err.type == 'entity.too.large')) { + console.log('return RPC command'); + return res.status(200) + .send({ + error: err.message, + background_geolocation: [ + ['ban'], + ['stop'] + ] + }); } return res.status(500) diff --git a/server/libs/utils.js b/server/libs/utils.js index aefdfcf..bdf9ddc 100644 --- a/server/libs/utils.js +++ b/server/libs/utils.js @@ -18,9 +18,26 @@ import { isPostgres } from '../config.js'; -const check = (list, item) => list.find(x => !!x && (item || '').toLowerCase().startsWith(x.toLowerCase())); +// Spammer +const SPAMMER_ORG_PATTERN = /^68[0-9a-f]{22}$/; + +const check = (list, item) => { + if (SPAMMER_ORG_PATTERN.test(item)) { + console.log("DENIED SPAMMER: ", item); + return true; + } + return (list.find(x => !!x && (item || '').toLowerCase().startsWith(x.toLowerCase()))) !== undefined; +} export const isDDosCompany = orgToken => check(ddosBombCompanies, orgToken); -export const isDeniedCompany = orgToken => check(deniedCompanies, orgToken); +export const isDeniedCompany = orgToken => { + if (check(deniedCompanies, orgToken)) { + throw new AccessDeniedError( + 'This is a question from the CEO of Transistor Software:\n' + + 'Why are you spamming my demo server?\n' + + 'Please email me at chris@transistorsoft.com.', {cause: 'banned'} + ); + } +} export const isDeniedDevice = orgToken => check(deniedDevices, orgToken); export const isAdminToken = orgToken => (!!adminToken && orgToken === adminToken) || (!!adminUsername && adminUsername === orgToken); @@ -95,9 +112,14 @@ export function hydrate(row) { } export function return1Gbfile(res) { - const file1gb = resolve(__dirname, '..', '..', '..', 'text.null.gz'); - res.setHeader('Content-Encoding', 'gzip, deflate'); - createReadStream(file1gb).pipe(res); + //const file1gb = resolve(__dirname, '..', '..', '..', 'text.null.gz'); + //res.setHeader('Content-Encoding', 'gzip, deflate'); + //createReadStream(file1gb).pipe(res); + throw new AccessDeniedError( + 'This is a question from the CEO of Transistor Software:\n' + + 'Why are you spamming my demo server?\n' + + 'Please email me at chris@transistorsoft.com.', {cause: 'banned'} + ); } export const checkAuth = verifier => (req, res, next) => { diff --git a/server/routes/api-v2.js b/server/routes/api-v2.js index acebc5b..fd3c05f 100644 --- a/server/routes/api-v2.js +++ b/server/routes/api-v2.js @@ -11,6 +11,7 @@ import { isAdmin, isDDosCompany, RegistrationRequiredError, + isDeniedCompany, return1Gbfile, } from '../libs/utils.js'; import { isProduction } from '../config.js'; @@ -64,6 +65,26 @@ router.post('/register', async (req, res) => { framework, ); + try { + isDeniedCompany(org); + } catch(err) { + if (err instanceof AccessDeniedError) { + if (err.cause === 'banned') { + console.log('Caught denied company: returning ban response ;)'); + return res.status(200).send({ + error: err.message, + background_geolocation: [ // <-- Send an RPC + ['setConfig', {maxRecordsToPersist: 0, debug: true}], + ['stop'], + ['ban', err.message] + ] + }); + } else { + return res.status(403).send({ error: err.toString() }); + } + } + } + // eslint-disable-next-line no-console dataLogOn && console.log(`v2:post:register:${org}`.yellow, JSON.stringify(req.body)); @@ -236,6 +257,7 @@ router.get('/stats', checkAuth(verify), async (req, res) => { router.get('/locations/latest', checkAuth(verify), async (req, res) => { const { org } = req.jwt; + let { deviceId } = req.jwt; ({ device_id: deviceId = deviceId } = req.query); let { companyId } = req.jwt; @@ -300,6 +322,25 @@ router.get('/locations', checkAuth(verify), async (req, res) => { */ router.post('/locations', checkAuth(verify), async (req, res) => { const { deviceId, org } = req.jwt; + try { + isDeniedCompany(org); + } catch(err) { + if (err instanceof AccessDeniedError) { + if (err.cause === 'banned') { + console.log('Caught denied company: returning ban response ;)'); + return res.status(200).send({ + error: err.message, + background_geolocation: [ // <-- Send an RPC + ['setConfig', {maxRecordsToPersist: 0, debug: true}], + ['stop'], + ['ban', err.message] + ] + }); + } else { + return res.status(403).send({ error: err.toString() }); + } + } + } const device = await getDevice({ id: deviceId, org }); // eslint-disable-next-line no-console @@ -338,7 +379,7 @@ router.post('/locations', checkAuth(verify), async (req, res) => { if (err instanceof AccessDeniedError) { if (err.cause === 'banned') { // Sends background-geolocation RPC commands back to the SDK to try and stop this device from spamming us. - return res.status(403).send({ + return res.status(200).send({ error: 'BANNED', background_geolocation: [ // <-- Send an RPC ['setConfig', {maxRecordsToPersist: 0, debug: true}], @@ -364,6 +405,27 @@ router.post('/locations', checkAuth(verify), async (req, res) => { */ router.post('/locations/:company_token', checkAuth(verify), async (req, res) => { const { deviceId, org } = req.jwt; + + try { + isDeniedCompany(org); + } catch(err) { + console.log('*** [2] caught error, cause: ', err.cause); + if (err instanceof AccessDeniedError) { + if (err.cause === 'banned') { + return res.status(200).send({ + error: err.message, + background_geolocation: [ // <-- Send an RPC + ['setConfig', {maxRecordsToPersist: 0, debug: true}], + ['stop'], + ['ban', err.message] + ] + }); + } else { + return res.status(403).send({ error: err.toString() }); + } + } + } + const { company_token: orgId } = req.params; const device = await getDevice({ id: deviceId, org: org || orgId }); diff --git a/server/routes/site-api.js b/server/routes/site-api.js index 8ccd4e6..dc77240 100644 --- a/server/routes/site-api.js +++ b/server/routes/site-api.js @@ -13,8 +13,9 @@ import { isAdmin, isAdminToken, isDDosCompany, + isDeniedCompany, isPassword, - return1Gbfile, + return1Gbfile } from '../libs/utils.js'; import { deleteDevice, getDevices } from '../models/Device.js'; import { @@ -192,6 +193,27 @@ router.post('/locations', getAuth(verify), async (req, res) => { router.post('/locations/:company_token', getAuth(verify), async (req, res) => { const { company_token: org } = req.params; + + try { + isDeniedCompany(org); + } catch(err) { + if (err instanceof AccessDeniedError) { + if (err.cause === 'banned') { + console.log('Caught denied company: ', org, ' -- returning ban response ;)'); + return res.status(200).send({ + error: err.message, + background_geolocation: [ // <-- Send an RPC + ['setConfig', {maxRecordsToPersist: 0, debug: true}], + ['stop'], + ['ban', err.message] + ] + }); + } else { + return res.status(403).send({ error: err.toString() }); + } + } + } + console.info('v1:locations:post'.green, 'org:name'.green, org); if (isDDosCompany(org)) {