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;
}
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) {
const result = await fetchWithAuthAndRetry(
`/api/metadata/${id}`,
@ -63,8 +72,6 @@ export async function metadata(id, keychain) {
const data = await result.response.json();
const meta = await keychain.decryptMetadata(b64ToArray(data.metadata));
return {
dtotal: data.dtotal,
dlimit: data.dlimit,
size: data.size,
ttl: data.ttl,
iv: meta.iv,

View file

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

View file

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

View file

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

View file

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

View file

@ -2,9 +2,9 @@
const html = require('choo/html');
const assets = require('../../common/assets');
const notFound = require('./notFound');
const uploadPasswordSet = require('./uploadPasswordSet');
const uploadPasswordUnset = require('./uploadPasswordUnset');
const selectbox = require('./selectbox');
const uploadPasswordSet = require('../templates/uploadPasswordSet');
const uploadPasswordUnset = require('../templates/uploadPasswordUnset');
const selectbox = require('../templates/selectbox');
const { allowedCopy, delay, fadeOut } = require('../utils');
function expireInfo(file, translate, emit) {
@ -16,7 +16,7 @@ function expireInfo(file, translate, emit) {
})}</div>`
]);
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 changed = value => emit('changeLimit', { file, value });
select.parentNode.replaceChild(
@ -32,7 +32,7 @@ module.exports = function(state, emit) {
return notFound(state, emit);
}
const passwordSection = file.hasPassword()
const passwordSection = file.hasPassword
? uploadPasswordSet(state, emit)
: uploadPasswordUnset(state, emit);
const div = html`

View file

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

View file

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

View file

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

View file

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

View file

@ -41,14 +41,14 @@ function body(template) {
}
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/:key', body(download));
app.route('/completed', body(require('../templates/completed')));
app.route('/unsupported/:reason', body(require('../templates/unsupported')));
app.route('/legal', body(require('../templates/legal')));
app.route('/error', body(require('../templates/error')));
app.route('/blank', body(require('../templates/blank')));
app.route('*', body(require('../templates/notFound')));
app.route('/completed', body(require('../pages/completed')));
app.route('/unsupported/:reason', body(require('../pages/unsupported')));
app.route('/legal', body(require('../pages/legal')));
app.route('/error', body(require('../pages/error')));
app.route('/blank', body(require('../pages/blank')));
app.route('*', body(require('../pages/notFound')));
module.exports = app;

View file

@ -95,6 +95,7 @@ module.exports = function(app) {
app.post('/api/delete/:id', require('./delete'));
app.post('/api/password/:id', require('./password'));
app.post('/api/params/:id', require('./params'));
app.post('/api/info/:id', require('./info'));
app.get('/__version__', function(req, res) {
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);
res.send({
metadata: meta.metadata,
dtotal: +meta.dl,
dlimit: +meta.dlimit,
finalDownload: +meta.dl + 1 === +meta.dlimit,
size,
ttl
});