Merge pull request #739 from mozilla/fileInfo

added /api/info/:id route
This commit is contained in:
Danny Coates 2018-01-30 17:46:31 -08:00 committed by GitHub
commit a74a70fd8c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 74 additions and 38 deletions

View file

@ -53,6 +53,15 @@ export async function setParams(id, owner_token, params) {
return response.ok; return response.ok;
} }
export async function fileInfo(id, owner_token) {
const response = await fetch(`/api/info/${id}`, post({ owner_token }));
if (response.ok) {
const obj = await response.json();
return obj;
}
throw new Error(response.status);
}
export async function metadata(id, keychain) { export async function metadata(id, keychain) {
const result = await fetchWithAuthAndRetry( const result = await fetchWithAuthAndRetry(
`/api/metadata/${id}`, `/api/metadata/${id}`,
@ -63,8 +72,6 @@ export async function metadata(id, keychain) {
const data = await result.response.json(); const data = await result.response.json();
const meta = await keychain.decryptMetadata(b64ToArray(data.metadata)); const meta = await keychain.decryptMetadata(b64ToArray(data.metadata));
return { return {
dtotal: data.dtotal,
dlimit: data.dlimit,
size: data.size, size: data.size,
ttl: data.ttl, ttl: data.ttl,
iv: meta.iv, iv: meta.iv,

View file

@ -83,10 +83,10 @@ export default class Keychain extends Nanobus {
} }
set nonce(n) { set nonce(n) {
if (n !== this.nonce) { if (n && n !== this._nonce) {
this.emit('nonceChanged', n); this._nonce = n;
this.emit('nonceChanged');
} }
this._nonce = n;
} }
setIV(ivB64) { setIV(ivB64) {

View file

@ -1,6 +1,6 @@
import Keychain from './keychain'; import Keychain from './keychain';
import { arrayToB64 } from './utils'; import { arrayToB64 } from './utils';
import { del, metadata, setParams, setPassword } from './api'; import { del, fileInfo, setParams, setPassword } from './api';
export default class OwnedFile { export default class OwnedFile {
constructor(obj, storage) { constructor(obj, storage) {
@ -18,17 +18,14 @@ export default class OwnedFile {
this.dtotal = obj.dtotal || 0; this.dtotal = obj.dtotal || 0;
this.keychain = new Keychain(obj.secretKey, obj.nonce); this.keychain = new Keychain(obj.secretKey, obj.nonce);
this.keychain.on('nonceChanged', () => storage.writeFile(this)); this.keychain.on('nonceChanged', () => storage.writeFile(this));
if (obj.authKeyB64) { this._hasPassword = !!obj.hasPassword;
this.authKeyB64 = obj.authKeyB64;
this.keychain.setAuthKey(obj.authKeyB64);
}
} }
async setPassword(password) { async setPassword(password) {
this.password = password; this.password = password;
this._hasPassword = true;
this.keychain.setPassword(password, this.url); this.keychain.setPassword(password, this.url);
const result = await setPassword(this.id, this.ownerToken, this.keychain); const result = await setPassword(this.id, this.ownerToken, this.keychain);
this.authKeyB64 = await this.keychain.authKeyB64();
return result; return result;
} }
@ -44,14 +41,15 @@ export default class OwnedFile {
return Promise.resolve(true); return Promise.resolve(true);
} }
hasPassword() { get hasPassword() {
return !!this.authKeyB64; return !!this._hasPassword;
} }
async updateDownloadCount() { async updateDownloadCount() {
try { try {
const result = await metadata(this.id, this.keychain); const result = await fileInfo(this.id, this.ownerToken);
this.dtotal = result.dtotal; this.dtotal = result.dtotal;
this.dlimit = result.dlimit;
} catch (e) { } catch (e) {
if (e.message === '404') { if (e.message === '404') {
this.dtotal = this.dlimit; this.dtotal = this.dlimit;
@ -75,7 +73,7 @@ export default class OwnedFile {
ownerToken: this.ownerToken, ownerToken: this.ownerToken,
dlimit: this.dlimit, dlimit: this.dlimit,
dtotal: this.dtotal, dtotal: this.dtotal,
authKeyB64: this.authKeyB64 hasPassword: this.hasPassword
}; };
} }
} }

View file

@ -1,5 +1,5 @@
const html = require('choo/html'); const html = require('choo/html');
const progress = require('./progress'); const progress = require('../templates/progress');
const { fadeOut } = require('../utils'); const { fadeOut } = require('../utils');
module.exports = function(state, emit) { module.exports = function(state, emit) {

View file

@ -1,5 +1,5 @@
const html = require('choo/html'); const html = require('choo/html');
const progress = require('./progress'); const progress = require('../templates/progress');
const { bytes } = require('../utils'); const { bytes } = require('../utils');
module.exports = function(state, emit) { module.exports = function(state, emit) {

View file

@ -2,9 +2,9 @@
const html = require('choo/html'); const html = require('choo/html');
const assets = require('../../common/assets'); const assets = require('../../common/assets');
const notFound = require('./notFound'); const notFound = require('./notFound');
const uploadPasswordSet = require('./uploadPasswordSet'); const uploadPasswordSet = require('../templates/uploadPasswordSet');
const uploadPasswordUnset = require('./uploadPasswordUnset'); const uploadPasswordUnset = require('../templates/uploadPasswordUnset');
const selectbox = require('./selectbox'); const selectbox = require('../templates/selectbox');
const { allowedCopy, delay, fadeOut } = require('../utils'); const { allowedCopy, delay, fadeOut } = require('../utils');
function expireInfo(file, translate, emit) { function expireInfo(file, translate, emit) {
@ -16,7 +16,7 @@ function expireInfo(file, translate, emit) {
})}</div>` })}</div>`
]); ]);
const select = el.querySelector('select'); const select = el.querySelector('select');
const options = [1, 2, 3, 4, 5, 20]; const options = [1, 2, 3, 4, 5, 20].filter(i => i > (file.dtotal || 0));
const t = num => translate('downloadCount', { num }); const t = num => translate('downloadCount', { num });
const changed = value => emit('changeLimit', { file, value }); const changed = value => emit('changeLimit', { file, value });
select.parentNode.replaceChild( select.parentNode.replaceChild(
@ -32,7 +32,7 @@ module.exports = function(state, emit) {
return notFound(state, emit); return notFound(state, emit);
} }
const passwordSection = file.hasPassword() const passwordSection = file.hasPassword
? uploadPasswordSet(state, emit) ? uploadPasswordSet(state, emit)
: uploadPasswordUnset(state, emit); : uploadPasswordUnset(state, emit);
const div = html` const div = html`

View file

@ -1,5 +1,5 @@
const html = require('choo/html'); const html = require('choo/html');
const progress = require('./progress'); const progress = require('../templates/progress');
const { bytes } = require('../utils'); const { bytes } = require('../utils');
module.exports = function(state, emit) { module.exports = function(state, emit) {

View file

@ -1,7 +1,7 @@
/* global MAXFILESIZE */ /* global MAXFILESIZE */
const html = require('choo/html'); const html = require('choo/html');
const assets = require('../../common/assets'); const assets = require('../../common/assets');
const fileList = require('./fileList'); const fileList = require('../templates/fileList');
const { bytes, fadeOut } = require('../utils'); const { bytes, fadeOut } = require('../utils');
module.exports = function(state, emit) { module.exports = function(state, emit) {

View file

@ -1,6 +1,6 @@
const preview = require('../templates/preview'); const preview = require('../pages/preview');
const download = require('../templates/download'); const download = require('../pages/download');
const notFound = require('../templates/notFound'); const notFound = require('../pages/notFound');
const downloadPassword = require('../templates/downloadPassword'); const downloadPassword = require('../templates/downloadPassword');
const downloadButton = require('../templates/downloadButton'); const downloadButton = require('../templates/downloadButton');

View file

@ -1,5 +1,5 @@
const welcome = require('../templates/welcome'); const welcome = require('../pages/welcome');
const upload = require('../templates/upload'); const upload = require('../pages/upload');
module.exports = function(state, emit) { module.exports = function(state, emit) {
if (state.transfer) { if (state.transfer) {

View file

@ -41,14 +41,14 @@ function body(template) {
} }
app.route('/', body(require('./home'))); app.route('/', body(require('./home')));
app.route('/share/:id', body(require('../templates/share'))); app.route('/share/:id', body(require('../pages/share')));
app.route('/download/:id', body(download)); app.route('/download/:id', body(download));
app.route('/download/:id/:key', body(download)); app.route('/download/:id/:key', body(download));
app.route('/completed', body(require('../templates/completed'))); app.route('/completed', body(require('../pages/completed')));
app.route('/unsupported/:reason', body(require('../templates/unsupported'))); app.route('/unsupported/:reason', body(require('../pages/unsupported')));
app.route('/legal', body(require('../templates/legal'))); app.route('/legal', body(require('../pages/legal')));
app.route('/error', body(require('../templates/error'))); app.route('/error', body(require('../pages/error')));
app.route('/blank', body(require('../templates/blank'))); app.route('/blank', body(require('../pages/blank')));
app.route('*', body(require('../templates/notFound'))); app.route('*', body(require('../pages/notFound')));
module.exports = app; module.exports = app;

View file

@ -95,6 +95,7 @@ module.exports = function(app) {
app.post('/api/delete/:id', require('./delete')); app.post('/api/delete/:id', require('./delete'));
app.post('/api/password/:id', require('./password')); app.post('/api/password/:id', require('./password'));
app.post('/api/params/:id', require('./params')); app.post('/api/params/:id', require('./params'));
app.post('/api/info/:id', require('./info'));
app.get('/__version__', function(req, res) { app.get('/__version__', function(req, res) {
res.sendFile(require.resolve('../../dist/version.json')); res.sendFile(require.resolve('../../dist/version.json'));

31
server/routes/info.js Normal file
View file

@ -0,0 +1,31 @@
const storage = require('../storage');
function validateID(route_id) {
return route_id.match(/^[0-9a-fA-F]{10}$/) !== null;
}
module.exports = async function(req, res) {
const id = req.params.id;
if (!validateID(id)) {
return res.sendStatus(404);
}
const ownerToken = req.body.owner_token;
if (!ownerToken) {
return res.sendStatus(400);
}
try {
const meta = await storage.metadata(id);
if (meta.owner !== ownerToken) {
return res.sendStatus(400);
}
const ttl = await storage.ttl(id);
return res.send({
dlimit: meta.dlimit,
dtotal: meta.dl,
ttl
});
} catch (e) {
res.sendStatus(404);
}
};

View file

@ -29,8 +29,7 @@ module.exports = async function(req, res) {
const ttl = await storage.ttl(id); const ttl = await storage.ttl(id);
res.send({ res.send({
metadata: meta.metadata, metadata: meta.metadata,
dtotal: +meta.dl, finalDownload: +meta.dl + 1 === +meta.dlimit,
dlimit: +meta.dlimit,
size, size,
ttl ttl
}); });