From d9cbe058ab459d23e054f818ba460eab3ebf1f2c Mon Sep 17 00:00:00 2001 From: Danny Coates Date: Sat, 25 Jul 2020 15:36:09 -0700 Subject: [PATCH] added hmac auth to report route --- app/api.js | 19 +++++++++++++------ app/controller.js | 9 +-------- app/fileReceiver.js | 6 +++++- app/serviceWorker.js | 2 +- server/routes/index.js | 2 +- server/routes/report.js | 39 +++++++++++---------------------------- server/storage/index.js | 12 +++++++----- 7 files changed, 39 insertions(+), 50 deletions(-) diff --git a/app/api.js b/app/api.js index caace3f8..228dbee2 100644 --- a/app/api.js +++ b/app/api.js @@ -61,7 +61,10 @@ async function fetchWithAuth(url, params, keychain) { const result = {}; params = params || {}; const h = await keychain.authHeader(); - params.headers = new Headers({ Authorization: h }); + params.headers = new Headers({ + Authorization: h, + 'Content-Type': 'application/json' + }); const response = await fetch(url, params); result.response = response; result.ok = response.ok; @@ -439,15 +442,19 @@ export async function getConstants() { throw new Error(response.status); } -export async function reportLink(id, key, reason) { - const response = await fetch( +export async function reportLink(id, keychain, reason) { + const result = await fetchWithAuthAndRetry( getApiUrl(`/api/report/${id}`), - post({ key, reason }) + { + method: 'POST', + body: JSON.stringify({ reason }) + }, + keychain ); - if (response.ok) { + if (result.ok) { return; } - throw new Error(response.status); + throw new Error(result.response.status); } diff --git a/app/controller.js b/app/controller.js index d6e2c588..3231c676 100644 --- a/app/controller.js +++ b/app/controller.js @@ -1,6 +1,5 @@ import FileSender from './fileSender'; import FileReceiver from './fileReceiver'; -import { reportLink } from './api'; import { copyToClipboard, delay, openLinksInNewTab, percent } from './utils'; import * as metrics from './metrics'; import { bytes, locale } from './utils'; @@ -315,13 +314,7 @@ export default function(state, emitter) { emitter.on('report', async ({ reason }) => { try { - const file = state.fileInfo; - if (!file) { - // TODO - emitter.emit('pushState', '/error'); - return render(); - } - await reportLink(file.id, file.secretKey, reason); + await state.transfer.reportLink(reason); render(); } catch (err) { console.error(err); diff --git a/app/fileReceiver.js b/app/fileReceiver.js index 60942a18..6f2d8e2c 100644 --- a/app/fileReceiver.js +++ b/app/fileReceiver.js @@ -1,7 +1,7 @@ import Nanobus from 'nanobus'; import Keychain from './keychain'; import { delay, bytes, streamToArrayBuffer } from './utils'; -import { downloadFile, metadata, getApiUrl } from './api'; +import { downloadFile, metadata, getApiUrl, reportLink } from './api'; import { blobStream } from './streams'; import Zip from './zip'; @@ -53,6 +53,10 @@ export default class FileReceiver extends Nanobus { this.state = 'ready'; } + async reportLink(reason) { + await reportLink(this.fileInfo.id, this.keychain, reason); + } + sendMessageToSw(msg) { return new Promise((resolve, reject) => { const channel = new MessageChannel(); diff --git a/app/serviceWorker.js b/app/serviceWorker.js index bc824e2d..34ae25b2 100644 --- a/app/serviceWorker.js +++ b/app/serviceWorker.js @@ -9,7 +9,7 @@ import contentDisposition from 'content-disposition'; let noSave = false; const map = new Map(); const IMAGES = /.*\.(png|svg|jpg)$/; -const VERSIONED_ASSET = /\.[A-Fa-f0-9]{8}\.(js|css|png|svg|jpg)$/; +const VERSIONED_ASSET = /\.[A-Fa-f0-9]{8}\.(js|css|png|svg|jpg)(#\w+)?$/; const DOWNLOAD_URL = /\/api\/download\/([A-Fa-f0-9]{4,})/; const FONT = /\.woff2?$/; diff --git a/server/routes/index.js b/server/routes/index.js index c5c27c8d..637e6a85 100644 --- a/server/routes/index.js +++ b/server/routes/index.js @@ -127,7 +127,7 @@ module.exports = function(app) { require('./params') ); app.post(`/api/info/:id${ID_REGEX}`, auth.owner, require('./info')); - app.post(`/api/report/:id${ID_REGEX}`, require('./report')); + app.post(`/api/report/:id${ID_REGEX}`, auth.hmac, require('./report')); app.post('/api/metrics', require('./metrics')); app.get('/__version__', function(req, res) { // eslint-disable-next-line node/no-missing-require diff --git a/server/routes/report.js b/server/routes/report.js index 88b2d4a5..466e1f85 100644 --- a/server/routes/report.js +++ b/server/routes/report.js @@ -1,38 +1,21 @@ const storage = require('../storage'); -const Keychain = require('../keychain'); const { statReportEvent } = require('../amplitude'); module.exports = async function(req, res) { try { const id = req.params.id; const meta = await storage.metadata(id); - if (meta.flagged) { - return res.sendStatus(200); - } - try { - const key = req.body.key; - const keychain = new Keychain(key); - const metadata = await keychain.decryptMetadata( - Buffer.from(meta.metadata, 'base64') - ); - if (metadata.manifest) { - storage.flag(id, key); - statReportEvent({ - id, - ip: req.ip, - owner: meta.owner, - reason: req.body.reason, - download_limit: meta.dlimit, - download_count: meta.dl, - agent: req.ua.browser.name || req.ua.ua.substring(0, 6) - }); - return res.sendStatus(200); - } - res.sendStatus(400); - } catch (e) { - console.error(e); - res.sendStatus(400); - } + storage.flag(id); + statReportEvent({ + id, + ip: req.ip, + owner: meta.owner, + reason: req.body.reason, + download_limit: meta.dlimit, + download_count: meta.dl, + agent: req.ua.browser.name || req.ua.ua.substring(0, 6) + }); + res.sendStatus(200); } catch (e) { res.sendStatus(404); } diff --git a/server/storage/index.js b/server/storage/index.js index c8bedec2..9131fe2b 100644 --- a/server/storage/index.js +++ b/server/storage/index.js @@ -80,14 +80,16 @@ class DB { } async kill(id) { - const { filePath } = await this.getPrefixedInfo(id); - this.storage.del(filePath); - this.redis.hset(id, 'dead', 1); + const { filePath, dead } = await this.getPrefixedInfo(id); + if (!dead) { + this.storage.del(filePath); + this.redis.hset(id, 'dead', 1); + } } - async flag(id, key) { + async flag(id) { await this.kill(id); - this.redis.hmset(id, { flagged: 1, key }); + this.redis.hset(id, 'flagged', 1); } async del(id) {