Merge pull request #739 from mozilla/fileInfo
added /api/info/:id route
This commit is contained in:
commit
a74a70fd8c
20 changed files with 74 additions and 38 deletions
11
app/api.js
11
app/api.js
|
@ -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,
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
|
@ -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) {
|
|
@ -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`
|
|
@ -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) {
|
|
@ -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) {
|
|
@ -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');
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
31
server/routes/info.js
Normal 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);
|
||||||
|
}
|
||||||
|
};
|
|
@ -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
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue