diff --git a/lib/application.js b/lib/application.js index 7850209..91c894c 100644 --- a/lib/application.js +++ b/lib/application.js @@ -34,7 +34,8 @@ class Application extends events.EventEmitter { createSandbox() { const introspection = async () => [...this.api.keys()]; - const application = { security, api: { introspection } }; + const context = Object.freeze({}); + const application = { security, api: { introspection }, context }; for (const name of this.namespaces) application[name] = this[name]; const sandbox = { console: this.logger, application, Buffer, api }; sandbox.global = sandbox; @@ -51,7 +52,7 @@ class Application extends events.EventEmitter { const data = await fsp.readFile(fileName, 'utf8'); const code = data.startsWith('({') ? data : `({ access: 'logged', method: ${data.trim().slice(0, -1)} });`; - const src = `'use strict';\ncontext => ${code}`; + const src = `'use strict';\n${code}`; const options = { filename: fileName, lineOffset: -1 }; try { return new vm.Script(src, options); @@ -61,9 +62,10 @@ class Application extends events.EventEmitter { } } - runScript(methodName, sandbox = this.sandbox) { + runScript(methodName, session) { + const { sandbox } = (session || this); const script = this.api.get(methodName); - if (!script) throw new Error('Not found'); + if (!script) return null; return script.runInContext(sandbox, SCRIPT_OPTIONS); } diff --git a/lib/auth.js b/lib/auth.js index 2128aae..69e1516 100644 --- a/lib/auth.js +++ b/lib/auth.js @@ -57,8 +57,7 @@ module.exports = application => { const fillPool = () => { const need = SANDBOX_POOL - pool.length; for (let i = 0; i < need; i++) { - const sandbox = application.createSandbox(); - pool.push(sandbox); + pool.push(application.createSandbox()); } }; @@ -90,7 +89,7 @@ module.exports = application => { this.token = token; this.sandbox = sandbox; this.data = contextData; - this.context = new Proxy(contextData, contextHandler); + sandbox.context = new Proxy(contextData, contextHandler); } } diff --git a/lib/server.js b/lib/server.js index 4de6f3f..9052425 100644 --- a/lib/server.js +++ b/lib/server.js @@ -55,13 +55,13 @@ class Client { } static() { - const { url } = this.req; + const { req: { url }, res, application } = this; const filePath = url === '/' ? '/index.html' : url; const fileExt = path.extname(filePath).substring(1); const mimeType = MIME_TYPES[fileExt] || MIME_TYPES.html; - this.res.writeHead(200, { 'Content-Type': mimeType }); - const data = this.application.cache.get(filePath); - if (data) this.res.end(data); + res.writeHead(200, { 'Content-Type': mimeType }); + const data = application.cache.get(filePath); + if (data) res.end(data); else this.error(404); } @@ -81,44 +81,40 @@ class Client { res.end(result); } - async execute(method, args) { - const { application } = this; + async rpc(method, args) { + const { application, res, connection } = this; const { semaphore } = application.server; - await semaphore.enter(); + try { + await semaphore.enter(); + } catch { + this.error(504); + return; + } try { const session = await application.auth.restore(this); - const sandbox = session ? session.sandbox : undefined; - const context = session ? session.context : {}; - const exp = application.runScript(method, sandbox); - const proc = exp(context); + const proc = application.runScript(method, session); + if (!proc) { + this.error(404); + return; + } if (!session && proc.access !== 'public') { - semaphore.leave(); - throw new Error(`Forbidden: /api/${method}`); + this.error(403, new Error(`Forbidden: /api/${method}`)); + return; } const result = await proc.method(args); if (!session && proc.access === 'public') { const session = application.auth.start(this, result.userId); result.token = session.token; } - return JSON.stringify(result); + const data = JSON.stringify(result); + if (connection) connection.send(data); + else res.end(data); + } catch (err) { + this.error(500, err); } finally { semaphore.leave(); } } - - async rpc(method, args) { - const { res, connection } = this; - try { - const result = await this.execute(method, args); - if (connection) connection.send(result); - else res.end(result); - } catch (err) { - if (err.message === 'Not found') this.error(404); - else if (err.message === 'Semaphore timeout') this.error(504); - else if (err.message.startsWith('Forbidden:')) this.error(403, err); - else this.error(500, err); - } - } } const listener = application => (req, res) => {