diff --git a/app/api.js b/app/api.js index 69c7216c..5986ff9f 100644 --- a/app/api.js +++ b/app/api.js @@ -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, diff --git a/app/keychain.js b/app/keychain.js index bb19864b..cfd7a331 100644 --- a/app/keychain.js +++ b/app/keychain.js @@ -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'); } - this._nonce = n; } setIV(ivB64) { diff --git a/app/ownedFile.js b/app/ownedFile.js index b482caf8..ca41fd0a 100644 --- a/app/ownedFile.js +++ b/app/ownedFile.js @@ -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 }; } } diff --git a/app/templates/blank.js b/app/pages/blank.js similarity index 100% rename from app/templates/blank.js rename to app/pages/blank.js diff --git a/app/templates/completed.js b/app/pages/completed.js similarity index 94% rename from app/templates/completed.js rename to app/pages/completed.js index 88bb9958..fa1fb896 100644 --- a/app/templates/completed.js +++ b/app/pages/completed.js @@ -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) { diff --git a/app/templates/download.js b/app/pages/download.js similarity index 95% rename from app/templates/download.js rename to app/pages/download.js index 8e0c81c8..eb6b8b37 100644 --- a/app/templates/download.js +++ b/app/pages/download.js @@ -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) { diff --git a/app/templates/error.js b/app/pages/error.js similarity index 100% rename from app/templates/error.js rename to app/pages/error.js diff --git a/app/templates/legal.js b/app/pages/legal.js similarity index 100% rename from app/templates/legal.js rename to app/pages/legal.js diff --git a/app/templates/notFound.js b/app/pages/notFound.js similarity index 100% rename from app/templates/notFound.js rename to app/pages/notFound.js diff --git a/app/templates/preview.js b/app/pages/preview.js similarity index 100% rename from app/templates/preview.js rename to app/pages/preview.js diff --git a/app/templates/share.js b/app/pages/share.js similarity index 92% rename from app/templates/share.js rename to app/pages/share.js index 1ee8b4ba..5fa8b127 100644 --- a/app/templates/share.js +++ b/app/pages/share.js @@ -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) { })}` ]); 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` diff --git a/app/templates/unsupported.js b/app/pages/unsupported.js similarity index 100% rename from app/templates/unsupported.js rename to app/pages/unsupported.js diff --git a/app/templates/upload.js b/app/pages/upload.js similarity index 95% rename from app/templates/upload.js rename to app/pages/upload.js index c8bb2caf..7a21bd3b 100644 --- a/app/templates/upload.js +++ b/app/pages/upload.js @@ -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) { diff --git a/app/templates/welcome.js b/app/pages/welcome.js similarity index 97% rename from app/templates/welcome.js rename to app/pages/welcome.js index 172f06a5..8f61ce2d 100644 --- a/app/templates/welcome.js +++ b/app/pages/welcome.js @@ -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) { diff --git a/app/routes/download.js b/app/routes/download.js index ca0f2b71..c2073422 100644 --- a/app/routes/download.js +++ b/app/routes/download.js @@ -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'); diff --git a/app/routes/home.js b/app/routes/home.js index 2be53047..3f101804 100644 --- a/app/routes/home.js +++ b/app/routes/home.js @@ -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) { diff --git a/app/routes/index.js b/app/routes/index.js index dfe6c34c..67818e58 100644 --- a/app/routes/index.js +++ b/app/routes/index.js @@ -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; diff --git a/server/routes/index.js b/server/routes/index.js index 5ac3a49d..9d69f3d6 100644 --- a/server/routes/index.js +++ b/server/routes/index.js @@ -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')); diff --git a/server/routes/info.js b/server/routes/info.js new file mode 100644 index 00000000..50893df1 --- /dev/null +++ b/server/routes/info.js @@ -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); + } +}; diff --git a/server/routes/metadata.js b/server/routes/metadata.js index 60e38c58..572df298 100644 --- a/server/routes/metadata.js +++ b/server/routes/metadata.js @@ -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 });