From 00bdf1df4a6524bc441b28a600b77195c064bf64 Mon Sep 17 00:00:00 2001 From: Cory McWilliams Date: Fri, 18 Mar 2022 01:24:29 +0000 Subject: [PATCH] Use proper js modules for apps. Kludge enough things to make things seem to work. Need to apply this to core still. git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3862 ed5197a5-7fde-0310-b194-c3ffbd925b24 --- core/app.js | 14 +++++++++++-- core/auth.js | 41 ++++++++++++++++++++++++++----------- core/core.js | 58 +++++++++++++++++++--------------------------------- src/task.c | 51 +++++++++++++++++++++++++++++++++++++++------ 4 files changed, 107 insertions(+), 57 deletions(-) diff --git a/core/app.js b/core/app.js index e237646c..c5623062 100644 --- a/core/app.js +++ b/core/app.js @@ -1,5 +1,14 @@ "use strict"; +var auth = require('auth'); +var core = require('core'); + +var gSessionIndex = 0; + +function makeSessionId() { + return (gSessionIndex++).toString(); +} + function App() { this._on_output = null; this._send_queue = []; @@ -96,7 +105,7 @@ function socket(request, response, client) { options.packageName = packageName; var sessionId = makeSessionId(); if (blobId) { - process = await getSessionProcessBlob(blobId, sessionId, options); + process = await core.getSessionProcessBlob(blobId, sessionId, options); } if (process) { process.app.readOutput(function(message) { @@ -140,7 +149,7 @@ function socket(request, response, client) { } } else { if (process && process.eventHandlers['message']) { - await invoke(process.eventHandlers['message'], [message]); + await core.invoke(process.eventHandlers['message'], [message]); } } } else if (event.opCode == 0x8) { @@ -160,3 +169,4 @@ function socket(request, response, client) { } exports.socket = socket; +exports.App = App; diff --git a/core/auth.js b/core/auth.js index b9f6a7b4..637c4879 100644 --- a/core/auth.js +++ b/core/auth.js @@ -2,6 +2,7 @@ var gTokens = {}; +var core = require('core'); var form = require('form'); var http = require('http'); @@ -51,22 +52,38 @@ function hashPassword(password) { } function noAdministrator() { - return !gGlobalSettings || !gGlobalSettings.permissions || !Object.keys(gGlobalSettings.permissions).some(function(name) { - return gGlobalSettings.permissions[name].indexOf("administration") != -1; + return !core.globalSettings || !core.globalSettings.permissions || !Object.keys(core.globalSettings.permissions).some(function(name) { + return core.globalSettings.permissions[name].indexOf("administration") != -1; }); } function makeAdministrator(name) { - if (!gGlobalSettings.permissions) { - gGlobalSettings.permissions = {}; + if (!core.globalSettings.permissions) { + core.globalSettings.permissions = {}; } - if (!gGlobalSettings.permissions[name]) { - gGlobalSettings.permissions[name] = []; + if (!core.globalSettings.permissions[name]) { + core.globalSettings.permissions[name] = []; } - if (gGlobalSettings.permissions[name].indexOf("administration") == -1) { - gGlobalSettings.permissions[name].push("administration"); + if (core.globalSettings.permissions[name].indexOf("administration") == -1) { + core.globalSettings.permissions[name].push("administration"); } - setGlobalSettings(gGlobalSettings); + core.setGlobalSettings(core.globalSettings); +} + +function getCookies(headers) { + var cookies = {}; + + if (headers.cookie) { + var parts = headers.cookie.split(/,|;/); + for (var i in parts) { + var equals = parts[i].indexOf("="); + var name = parts[i].substring(0, equals).trim(); + var value = parts[i].substring(equals + 1).trim(); + cookies[name] = value; + } + } + + return cookies; } function authHandler(request, response) { @@ -185,9 +202,9 @@ function getPermissions(session) { function getPermissionsForUser(userName) { var permissions = {}; - if (gGlobalSettings && gGlobalSettings.permissions && gGlobalSettings.permissions[userName]) { - for (var i in gGlobalSettings.permissions[userName]) { - permissions[gGlobalSettings.permissions[userName][i]] = true; + if (core.globalSettings && core.globalSettings.permissions && core.globalSettings.permissions[userName]) { + for (var i in core.globalSettings.permissions[userName]) { + permissions[core.globalSettings.permissions[userName][i]] = true; } } return permissions; diff --git a/core/core.js b/core/core.js index c03663be..9c5a80aa 100644 --- a/core/core.js +++ b/core/core.js @@ -5,7 +5,6 @@ var app = require("app"); var gProcessIndex = 0; var gProcesses = {}; -var gSessionIndex = 0; var gStatsTimer = false; var gGlobalSettings = { @@ -16,26 +15,6 @@ var kGlobalSettingsFile = "data/global/settings.json"; var kPingInterval = 60 * 1000; -function getCookies(headers) { - var cookies = {}; - - if (headers.cookie) { - var parts = headers.cookie.split(/,|;/); - for (var i in parts) { - var equals = parts[i].indexOf("="); - var name = parts[i].substring(0, equals).trim(); - var value = parts[i].substring(equals + 1).trim(); - cookies[name] = value; - } - } - - return cookies; -} - -function makeSessionId() { - return (gSessionIndex++).toString(); -} - function printError(out, error) { if (error.stackTrace) { out.print(error.fileName + ":" + error.lineNumber + ": " + error.message); @@ -154,7 +133,7 @@ async function getProcessBlob(blobId, key, options) { process.credentials = options.credentials || {}; process.task = new Task(); process.eventHandlers = {}; - process.app = new App(); + process.app = new app.App(); process.lastActive = Date.now(); process.lastPing = null; process.timeout = options.timeout; @@ -233,14 +212,14 @@ async function getProcessBlob(blobId, key, options) { var appSourceName = blobId; var appSource = utf8Decode(source); try { - var app = JSON.parse(appSource); - if (app.type == "tildefriends-app") { + var appObject = JSON.parse(appSource); + if (appObject.type == "tildefriends-app") { appSourceName = 'app.js'; - var id = app.files[appSourceName]; + var id = appObject.files[appSourceName]; var blob = await getBlobOrContent(id); appSource = utf8Decode(blob); - await Promise.all(Object.keys(app.files).map(async function(f) { - await process.task.loadFile([f, await getBlobOrContent(app.files[f])]); + await Promise.all(Object.keys(appObject.files).map(async function(f) { + await process.task.loadFile([f, await getBlobOrContent(appObject.files[f])]); })); } } catch (e) { @@ -444,8 +423,8 @@ async function blobHandler(request, response, blobId, uri) { } else { data = await getBlobOrContent(id); if (match[3]) { - var app = JSON.parse(data); - data = app.files[match[3]]; + var appObject = JSON.parse(data); + data = appObject.files[match[3]]; } sendData(response, data, undefined, {etag: '"' + id + '"'}); } @@ -462,7 +441,7 @@ async function blobHandler(request, response, blobId, uri) { var match; if (match = /^\/\~(\w+)\/(\w+)$/.exec(blobId)) { var user = match[1]; - var app = match[2]; + var appName = match[2]; var credentials = auth.query(request.headers); if (credentials && credentials.session && (credentials.session.name == user || @@ -473,11 +452,11 @@ async function blobHandler(request, response, blobId, uri) { apps = new Set(JSON.parse(database.get('apps'))); } catch { } - if (!apps.has(app)) { - apps.add(app); + if (!apps.has(appName)) { + apps.add(appName); database.set('apps', JSON.stringify([...apps])); } - database.set('path:' + app, newBlobId); + database.set('path:' + appName, newBlobId); } else { response.writeHead(401, {"Content-Type": "text/plain; charset=utf-8"}); response.end("401 Unauthorized"); @@ -500,8 +479,8 @@ async function blobHandler(request, response, blobId, uri) { response.end(); } else { data = utf8Decode(await getBlobOrContent(id)); - var app = JSON.parse(data); - data = app.files[uri.substring(1)]; + var appObject = JSON.parse(data); + data = appObject.files[uri.substring(1)]; data = await getBlobOrContent(data); type = guessType(uri); headers = {'ETag': '"' + id + '"'}; @@ -512,8 +491,8 @@ async function blobHandler(request, response, blobId, uri) { } } else { data = utf8Decode(await getBlobOrContent(blobId)); - var app = JSON.parse(data); - data = app.files[uri.substring(1)]; + var appObject = JSON.parse(data); + data = appObject.files[uri.substring(1)]; data = await getBlobOrContent(data); sendData(response, data, type, headers); } @@ -608,3 +587,8 @@ loadSettings().then(function() { }).catch(function(error) { print('Failed to load settings.'); }); + +exports.getSessionProcessBlob = getSessionProcessBlob; +exports.invoke = invoke; +exports.globalSettings = gGlobalSettings; +exports.setGlobalSettings = setGlobalSettings; diff --git a/src/task.c b/src/task.c index 139d3693..e9f17751 100644 --- a/src/task.c +++ b/src/task.c @@ -347,7 +347,7 @@ int tf_task_execute(tf_task_t* task, const char* fileName) } if (source) { - JSValue result = JS_Eval(task->_context, source, strlen(source), fileName, 0); + JSValue result = JS_Eval(task->_context, source, strlen(source), fileName, JS_EVAL_TYPE_MODULE); tf_util_report_error(task->_context, result); if (!JS_IsError(task->_context, result) && !JS_IsException(result)) { @@ -891,12 +891,15 @@ void tf_task_on_receive_packet(int packetType, const char* begin, size_t length, JSValue result = _tf_task_executeSource(to, source_str, name); if (JS_IsException(result)) { - _tf_task_sendPromiseReject(to, from, promise, JS_GetException(to->_context)); + JSValue exception = JS_GetException(to->_context); + _tf_task_sendPromiseReject(to, from, promise, exception); + JS_FreeValue(to->_context, exception); } else { _tf_task_sendPromiseResolve(to, from, promise, result); } + JS_FreeValue(to->_context, result); JS_FreeCString(to->_context, source_str); JS_FreeCString(to->_context, name); } @@ -1031,7 +1034,7 @@ JSValue _tf_task_require(JSContext* context, JSValueConst this_val, int argc, JS JSValue global = JS_GetGlobalObject(task->_context); JSValue oldExports = JS_GetPropertyStr(task->_context, global, "exports"); JS_SetPropertyStr(task->_context, global, "exports", JS_DupValue(task->_context, exports)); - JSValue eval = JS_Eval(task->_context, source, strlen(source), path, 0); + JSValue eval = JS_Eval(task->_context, source, strlen(source), path, JS_EVAL_TYPE_MODULE); tf_util_report_error(task->_context, eval); if (JS_IsError(task->_context, eval) || JS_IsException(eval)) @@ -1067,7 +1070,7 @@ JSValue _tf_task_require(JSContext* context, JSValueConst this_val, int argc, JS static JSValue _tf_task_executeSource(tf_task_t* task, const char* source, const char* name) { tf_trace_begin(task->_trace, "_tf_task_executeSource"); - JSValue result = JS_Eval(task->_context, source, strlen(source), name, 0); + JSValue result = JS_Eval(task->_context, source, strlen(source), name, JS_EVAL_TYPE_MODULE); if (!*task->_scriptName) { snprintf(task->_scriptName, sizeof(task->_scriptName), "%s", name); @@ -1103,7 +1106,7 @@ JSValue _tf_task_sandbox_require(JSContext* context, JSValueConst this_val, int JSValue global = JS_GetGlobalObject(context); JSValue oldExports = JS_GetPropertyStr(context, global, "exports"); JS_SetPropertyStr(context, global, "exports", JS_DupValue(context, exports)); - JSValue result = JS_Eval(context, source, length, name, 0); + JSValue result = JS_Eval(context, source, length, name, JS_EVAL_TYPE_MODULE); tf_util_report_error(context, result); JS_SetPropertyStr(context, global, "exports", oldExports); JS_FreeValue(context, global); @@ -1117,7 +1120,7 @@ JSValue _tf_task_sandbox_require(JSContext* context, JSValueConst this_val, int JSValue global = JS_GetGlobalObject(context); JSValue oldExports = JS_GetPropertyStr(context, global, "exports"); JS_SetPropertyStr(context, global, "exports", JS_DupValue(context, exports)); - JSValue result = JS_Eval(context, source, length, name, 0); + JSValue result = JS_Eval(context, source, length, name, JS_EVAL_TYPE_MODULE); tf_util_report_error(context, result); JS_SetPropertyStr(context, global, "exports", oldExports); JS_FreeValue(context, global); @@ -1378,6 +1381,40 @@ static void _tf_task_run_jobs_prepare(uv_prepare_t* prepare) } } +JSModuleDef* _tf_task_module_loader(JSContext* context, const char* module_name, void* opaque) +{ + tf_task_t* task = opaque; + JSValue source_value = JS_GetPropertyStr(context, task->_loadedFiles, module_name); + + char* source = NULL; + size_t length = 0; + uint8_t* array = tf_util_try_get_array_buffer(context, &length, source_value); + if (array) + { + source = malloc(length + 1); + memcpy(source, array, length); + source[length] = '\0'; + } + JS_FreeValue(context, source_value); + + if (!source) + { + JS_ThrowReferenceError(context, "Could not load '%s'.", module_name); + return NULL; + } + + JSValue result = JS_Eval(context, source, length, module_name, JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); + free(source); + if (tf_util_report_error(task->_context, result)) + { + return NULL; + } + + JSModuleDef* module = JS_VALUE_GET_PTR(result); + JS_FreeValue(context, result); + return module; +} + tf_task_t* tf_task_create() { tf_task_t* task = malloc(sizeof(tf_task_t)); @@ -1389,6 +1426,8 @@ tf_task_t* tf_task_create() JS_SetHostPromiseRejectionTracker(task->_runtime, _tf_task_promise_rejection_tracker, task); + JS_SetModuleLoaderFunc(task->_runtime, NULL, _tf_task_module_loader, task); + JS_NewClassID(&_import_class_id); JSClassDef def = {