added hmac auth to report route

This commit is contained in:
Danny Coates 2020-07-25 15:36:09 -07:00
parent 2f6119e2f1
commit d9cbe058ab
No known key found for this signature in database
GPG Key ID: 4C442633C62E00CB
7 changed files with 39 additions and 50 deletions

View File

@ -61,7 +61,10 @@ async function fetchWithAuth(url, params, keychain) {
const result = {}; const result = {};
params = params || {}; params = params || {};
const h = await keychain.authHeader(); 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); const response = await fetch(url, params);
result.response = response; result.response = response;
result.ok = response.ok; result.ok = response.ok;
@ -439,15 +442,19 @@ export async function getConstants() {
throw new Error(response.status); throw new Error(response.status);
} }
export async function reportLink(id, key, reason) { export async function reportLink(id, keychain, reason) {
const response = await fetch( const result = await fetchWithAuthAndRetry(
getApiUrl(`/api/report/${id}`), getApiUrl(`/api/report/${id}`),
post({ key, reason }) {
method: 'POST',
body: JSON.stringify({ reason })
},
keychain
); );
if (response.ok) { if (result.ok) {
return; return;
} }
throw new Error(response.status); throw new Error(result.response.status);
} }

View File

@ -1,6 +1,5 @@
import FileSender from './fileSender'; import FileSender from './fileSender';
import FileReceiver from './fileReceiver'; import FileReceiver from './fileReceiver';
import { reportLink } from './api';
import { copyToClipboard, delay, openLinksInNewTab, percent } from './utils'; import { copyToClipboard, delay, openLinksInNewTab, percent } from './utils';
import * as metrics from './metrics'; import * as metrics from './metrics';
import { bytes, locale } from './utils'; import { bytes, locale } from './utils';
@ -315,13 +314,7 @@ export default function(state, emitter) {
emitter.on('report', async ({ reason }) => { emitter.on('report', async ({ reason }) => {
try { try {
const file = state.fileInfo; await state.transfer.reportLink(reason);
if (!file) {
// TODO
emitter.emit('pushState', '/error');
return render();
}
await reportLink(file.id, file.secretKey, reason);
render(); render();
} catch (err) { } catch (err) {
console.error(err); console.error(err);

View File

@ -1,7 +1,7 @@
import Nanobus from 'nanobus'; import Nanobus from 'nanobus';
import Keychain from './keychain'; import Keychain from './keychain';
import { delay, bytes, streamToArrayBuffer } from './utils'; import { delay, bytes, streamToArrayBuffer } from './utils';
import { downloadFile, metadata, getApiUrl } from './api'; import { downloadFile, metadata, getApiUrl, reportLink } from './api';
import { blobStream } from './streams'; import { blobStream } from './streams';
import Zip from './zip'; import Zip from './zip';
@ -53,6 +53,10 @@ export default class FileReceiver extends Nanobus {
this.state = 'ready'; this.state = 'ready';
} }
async reportLink(reason) {
await reportLink(this.fileInfo.id, this.keychain, reason);
}
sendMessageToSw(msg) { sendMessageToSw(msg) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const channel = new MessageChannel(); const channel = new MessageChannel();

View File

@ -9,7 +9,7 @@ import contentDisposition from 'content-disposition';
let noSave = false; let noSave = false;
const map = new Map(); const map = new Map();
const IMAGES = /.*\.(png|svg|jpg)$/; 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 DOWNLOAD_URL = /\/api\/download\/([A-Fa-f0-9]{4,})/;
const FONT = /\.woff2?$/; const FONT = /\.woff2?$/;

View File

@ -127,7 +127,7 @@ module.exports = function(app) {
require('./params') require('./params')
); );
app.post(`/api/info/:id${ID_REGEX}`, auth.owner, require('./info')); 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.post('/api/metrics', require('./metrics'));
app.get('/__version__', function(req, res) { app.get('/__version__', function(req, res) {
// eslint-disable-next-line node/no-missing-require // eslint-disable-next-line node/no-missing-require

View File

@ -1,38 +1,21 @@
const storage = require('../storage'); const storage = require('../storage');
const Keychain = require('../keychain');
const { statReportEvent } = require('../amplitude'); const { statReportEvent } = require('../amplitude');
module.exports = async function(req, res) { module.exports = async function(req, res) {
try { try {
const id = req.params.id; const id = req.params.id;
const meta = await storage.metadata(id); const meta = await storage.metadata(id);
if (meta.flagged) { storage.flag(id);
return res.sendStatus(200); statReportEvent({
} id,
try { ip: req.ip,
const key = req.body.key; owner: meta.owner,
const keychain = new Keychain(key); reason: req.body.reason,
const metadata = await keychain.decryptMetadata( download_limit: meta.dlimit,
Buffer.from(meta.metadata, 'base64') download_count: meta.dl,
); agent: req.ua.browser.name || req.ua.ua.substring(0, 6)
if (metadata.manifest) { });
storage.flag(id, key); res.sendStatus(200);
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);
}
} catch (e) { } catch (e) {
res.sendStatus(404); res.sendStatus(404);
} }

View File

@ -80,14 +80,16 @@ class DB {
} }
async kill(id) { async kill(id) {
const { filePath } = await this.getPrefixedInfo(id); const { filePath, dead } = await this.getPrefixedInfo(id);
this.storage.del(filePath); if (!dead) {
this.redis.hset(id, 'dead', 1); this.storage.del(filePath);
this.redis.hset(id, 'dead', 1);
}
} }
async flag(id, key) { async flag(id) {
await this.kill(id); await this.kill(id);
this.redis.hmset(id, { flagged: 1, key }); this.redis.hset(id, 'flagged', 1);
} }
async del(id) { async del(id) {