-
+
-
-
+
+
-
-
-
+
+
+
Files
- «
- »
+ «
+ »
- - + +
@@ -62,6 +62,6 @@
-
+
diff --git a/core/auth.js b/core/auth.js index 4a57f5e6..3e9c93aa 100644 --- a/core/auth.js +++ b/core/auth.js @@ -1,8 +1,8 @@ import * as core from './core.js'; import * as form from './form.js'; -var gTokens = {}; -var gDatabase = new Database("auth"); +let gTokens = {}; +let gDatabase = new Database("auth"); const kRefreshInterval = 1 * 7 * 24 * 60 * 60 * 1000; @@ -75,7 +75,7 @@ function verifyPassword(password, hash) { } function hashPassword(password) { - var salt = bCrypt.gensalt(12); + let salt = bCrypt.gensalt(12); return bCrypt.hashpw(password, salt); } @@ -99,14 +99,14 @@ function makeAdministrator(name) { } function getCookies(headers) { - var cookies = {}; + let 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(); + let parts = headers.cookie.split(/,|;/); + for (let i in parts) { + let equals = parts[i].indexOf("="); + let name = parts[i].substring(0, equals).trim(); + let value = parts[i].substring(equals + 1).trim(); cookies[name] = value; } } @@ -115,18 +115,18 @@ function getCookies(headers) { } function handler(request, response) { - var session = getCookies(request.headers).session; + let session = getCookies(request.headers).session; if (request.uri == "/login") { - var sessionIsNew = false; - var loginError; + let sessionIsNew = false; + let loginError; - var formData = form.decodeForm(request.query); + let formData = form.decodeForm(request.query); if (request.method == "POST" || formData.submit) { sessionIsNew = true; formData = form.decodeForm(utf8Decode(request.body), formData); if (formData.submit == "Login") { - var account = gDatabase.get("user:" + formData.name); + let account = gDatabase.get("user:" + formData.name); account = account ? JSON.parse(account) : account; if (formData.register == "1") { if (!account && @@ -171,15 +171,15 @@ function handler(request, response) { } } - var cookie = `session=${session}; path=/; Max-Age=${kRefreshInterval}; Secure; SameSite=Strict`; - var entry = readSession(session); + let cookie = `session=${session}; path=/; Max-Age=${kRefreshInterval}; Secure; SameSite=Strict`; + let entry = readSession(session); if (entry && formData.return) { response.writeHead(303, {"Location": formData.return, "Set-Cookie": cookie}); response.end(); } else { File.readFile("core/auth.html").then(function(data) { - var html = utf8Decode(data); - var contents = ""; + let html = utf8Decode(data); + let contents = ""; if (entry) { if (sessionIsNew) { @@ -216,7 +216,7 @@ function handler(request, response) { contents += '\n'; contents += ''; } - var text = html.replace("", contents); + let text = html.replace("", contents); response.writeHead(200, {"Content-Type": "text/html; charset=utf-8", "Set-Cookie": cookie, "Content-Length": text.length}); response.end(text); }).catch(function(error) { @@ -234,8 +234,8 @@ function handler(request, response) { } function getPermissions(session) { - var permissions; - var entry = readSession(session); + let permissions; + let entry = readSession(session); if (entry) { permissions = getPermissionsForUser(entry.name); permissions.authenticated = entry.name !== "guest"; @@ -244,9 +244,9 @@ function getPermissions(session) { } function getPermissionsForUser(userName) { - var permissions = {}; + let permissions = {}; if (core.globalSettings && core.globalSettings.permissions && core.globalSettings.permissions[userName]) { - for (var i in core.globalSettings.permissions[userName]) { + for (let i in core.globalSettings.permissions[userName]) { permissions[core.globalSettings.permissions[userName][i]] = true; } } @@ -254,9 +254,9 @@ function getPermissionsForUser(userName) { } function query(headers) { - var session = getCookies(headers).session; - var entry; - var autologin = tildefriends.args.autologin; + let session = getCookies(headers).session; + let entry; + let autologin = tildefriends.args.autologin; if (entry = autologin ? {name: autologin} : readSession(session)) { return { session: entry, diff --git a/core/client.js b/core/client.js index 75555682..a62b6f35 100644 --- a/core/client.js +++ b/core/client.js @@ -1,5 +1,3 @@ -"use strict"; - let gSocket; let gCredentials; let gPermissions; @@ -952,6 +950,27 @@ window.addEventListener("load", function() { window.addEventListener("message", message, false); window.addEventListener("online", connectSocket); document.getElementById("name").value = window.location.pathname; + document.getElementById('edit_link').addEventListener('click', function(event) { + event.preventDefault(); + toggleEdit(); + }); + document.getElementById('show_permissions_link').addEventListener('click', () => showPermissions()); + document.getElementById('files_hide').addEventListener('click', () => hideFiles()); + document.getElementById('files_show').addEventListener('click', () => showFiles()); + document.getElementById('closeStats').addEventListener('click', () => closeStats()); + document.getElementById('closeEditor').addEventListener('click', () => closeEditor()); + document.getElementById('save').addEventListener('click', () => save()); + document.getElementById('delete').addEventListener('click', () => deleteApp()); + document.getElementById('trace_button').addEventListener('click', function(event) { + event.preventDefault(); + trace(); + }); + document.getElementById('stats_button').addEventListener('click', function(event) { + event.preventDefault(); + toggleStats(); + }); + document.getElementById('new_file_button').addEventListener('click', () => newFile()); + document.getElementById('remove_file_button').addEventListener('click', () => removeFile()); for (let tag of document.getElementsByTagName('a')) { if (tag.accessKey) { tag.classList.add('tooltip_parent'); diff --git a/core/core.js b/core/core.js index cf9fcbee..3b4b3e4c 100644 --- a/core/core.js +++ b/core/core.js @@ -2,9 +2,9 @@ import * as auth from './auth.js'; import * as app from './app.js'; import * as httpd from './httpd.js'; -var gProcessIndex = 0; -var gProcesses = {}; -var gStatsTimer = false; +let gProcessIndex = 0; +let gProcesses = {}; +let gStatsTimer = false; const k_global_settings = { index: { @@ -34,20 +34,20 @@ const k_global_settings = { }, }; -var gGlobalSettings = { +let gGlobalSettings = { index: "/~core/apps/", }; -var kGlobalSettingsFile = "data/global/settings.json"; +let kGlobalSettingsFile = "data/global/settings.json"; -var kPingInterval = 60 * 1000; +let kPingInterval = 60 * 1000; function printError(out, error) { if (error.stackTrace) { out.print(error.fileName + ":" + error.lineNumber + ": " + error.message); out.print(error.stackTrace); } else { - for (var i in error) { + for (let i in error) { out.print(i); } out.print(error.toString()); @@ -55,9 +55,9 @@ function printError(out, error) { } function invoke(handlers, argv) { - var promises = []; + let promises = []; if (handlers) { - for (var i = 0; i < handlers.length; ++i) { + for (let i = 0; i < handlers.length; ++i) { try { promises.push(handlers[i](...argv)); } catch (error) { @@ -71,9 +71,9 @@ function invoke(handlers, argv) { } function broadcastEvent(eventName, argv) { - var promises = []; - for (var i in gProcesses) { - var process = gProcesses[i]; + let promises = []; + for (let i in gProcesses) { + let process = gProcesses[i]; if (process.eventHandlers[eventName]) { promises.push(invoke(process.eventHandlers[eventName], argv)); } @@ -82,14 +82,14 @@ function broadcastEvent(eventName, argv) { } function broadcast(message) { - var sender = this; - var promises = []; - for (var i in gProcesses) { - var process = gProcesses[i]; + let sender = this; + let promises = []; + for (let i in gProcesses) { + let process = gProcesses[i]; if (process != sender && process.packageOwner == sender.packageOwner && process.packageName == sender.packageName) { - var from = getUser(process, sender); + let from = getUser(process, sender); promises.push(postMessageInternal(from, process, message)); } } @@ -119,9 +119,9 @@ function getApps(user, process) { } } if (user) { - var db = new Database(user); + let db = new Database(user); try { - var names = JSON.parse(db.get('apps')); + let names = JSON.parse(db.get('apps')); return Object.fromEntries(names.map(name => [name, db.get('path:' + name)])); } catch { } @@ -136,9 +136,9 @@ function postMessageInternal(from, to, message) { } async function getSessionProcessBlob(blobId, session, options) { - var actualOptions = {timeout: kPingInterval}; + let actualOptions = {timeout: kPingInterval}; if (options) { - for (var i in options) { + for (let i in options) { actualOptions[i] = options[i]; } } @@ -148,7 +148,7 @@ async function getSessionProcessBlob(blobId, session, options) { let gManifestCache = {}; async function getProcessBlob(blobId, key, options) { - var process = gProcesses[key]; + let process = gProcesses[key]; if (!process && !(options && "create" in options && !options.create)) { try { @@ -165,8 +165,8 @@ async function getProcessBlob(blobId, key, options) { process.lastPing = null; process.timeout = options.timeout; process.stats = false; - var resolveReady; - var rejectReady; + let resolveReady; + let rejectReady; process.ready = new Promise(function(resolve, reject) { resolveReady = resolve; rejectReady = reject; @@ -177,7 +177,7 @@ async function getProcessBlob(blobId, key, options) { process.task = null; delete gProcesses[key]; }; - var imports = { + let imports = { 'core': { 'broadcast': broadcast.bind(process), 'register': function(eventName, handler) { @@ -352,11 +352,11 @@ async function getProcessBlob(blobId, key, options) { process.credentials.session && process.credentials.session.name) { imports.database = function(key) { - var db = new Database(process.credentials.session.name + ':' + key); + let db = new Database(process.credentials.session.name + ':' + key); return Object.fromEntries(Object.keys(db).map(x => [x, db[x].bind(db)])); }; imports.my_shared_database = function(packageName, key) { - var db = new Database(':shared:' + process.credentials.session.name + ':' + packageName + ':' + key); + let db = new Database(':shared:' + process.credentials.session.name + ':' + packageName + ':' + key); return Object.fromEntries(Object.keys(db).map(x => [x, db[x].bind(db)])); }; imports.databases = function() { @@ -365,7 +365,7 @@ async function getProcessBlob(blobId, key, options) { } if (options.packageOwner && options.packageName) { imports.shared_database = function(key) { - var db = new Database(':shared:' + options.packageOwner + ':' + options.packageName + ':' + key); + let db = new Database(':shared:' + options.packageOwner + ':' + options.packageName + ':' + key); return Object.fromEntries(Object.keys(db).map(x => [x, db[x].bind(db)])); } } @@ -380,14 +380,14 @@ async function getProcessBlob(blobId, key, options) { process.task.setImports(imports); process.task.activate(); let source = await getBlobOrContent(blobId); - var appSourceName = blobId; - var appSource = utf8Decode(source); + let appSourceName = blobId; + let appSource = utf8Decode(source); try { - var appObject = JSON.parse(appSource); + let appObject = JSON.parse(appSource); if (appObject.type == "tildefriends-app") { appSourceName = 'app.js'; - var id = appObject.files[appSourceName]; - var blob = await getBlobOrContent(id); + let id = appObject.files[appSourceName]; + let blob = await getBlobOrContent(id); appSource = utf8Decode(blob); await process.task.loadFile(['/tfrpc.js', await File.readFile('core/tfrpc.js')]); await Promise.all(Object.keys(appObject.files).map(async function(f) { @@ -425,7 +425,7 @@ function setGlobalSettings(settings) { } } -var kStaticFiles = [ +let kStaticFiles = [ {uri: '/', path: 'index.html', type: 'text/html; charset=UTF-8'}, {uri: '/style.css', type: 'text/css; charset=UTF-8'}, {uri: '/favicon.png', type: 'image/png'}, @@ -436,8 +436,8 @@ var kStaticFiles = [ function startsWithBytes(data, bytes) { if (data.byteLength >= bytes.length) { - var dataBytes = new Uint8Array(data.slice(0, bytes.length)); - for (var i = 0; i < bytes.length; i++) { + let dataBytes = new Uint8Array(data.slice(0, bytes.length)); + for (let i = 0; i < bytes.length; i++) { if (dataBytes[i] != bytes[i] && bytes[i] !== null) { return; } @@ -447,10 +447,10 @@ function startsWithBytes(data, bytes) { } async function staticFileHandler(request, response, blobId, uri) { - for (var i in kStaticFiles) { + for (let i in kStaticFiles) { if (uri === kStaticFiles[i].uri) { - var path = kStaticFiles[i].path || uri.substring(1); - var type = kStaticFiles[i].type || guessType(path); + let path = kStaticFiles[i].path || uri.substring(1); + let type = kStaticFiles[i].type || guessType(path); let stat = await File.stat('core/' + path); let id = `${stat.mtime}_${stat.size}`; @@ -459,7 +459,7 @@ async function staticFileHandler(request, response, blobId, uri) { response.writeHead(304, {}); response.end(); } else { - var data = await File.readFile('core/' + path); + let data = await File.readFile('core/' + path); response.writeHead(200, Object.assign( { 'Content-Type': type, @@ -486,7 +486,7 @@ const k_mime_types = { }; async function staticDirectoryHandler(request, response, directory, uri) { - var filename = uri || 'index.html'; + let filename = uri || 'index.html'; if (filename.indexOf('..') != -1) { response.writeHead(404, {"Content-Type": "text/plain; charset=utf-8", "Content-Length": "File not found".length}); response.end("File not found"); @@ -501,7 +501,7 @@ async function staticDirectoryHandler(request, response, directory, uri) { response.writeHead(304, {}); response.end(); } else { - var data = await File.readFile(directory + filename); + let data = await File.readFile(directory + filename); response.writeHead(200, { 'Content-Type': k_mime_types[filename.split('.').pop()] || 'text/plain', 'Content-Length': data.byteLength, @@ -516,7 +516,7 @@ async function staticDirectoryHandler(request, response, directory, uri) { } async function wellKnownHandler(request, response, path) { - var data = await File.readFile("data/global/.well-known/" + path); + let data = await File.readFile("data/global/.well-known/" + path); if (data) { response.writeHead(200, {"Content-Type": "text/plain", "Content-Length": data.length}); response.end(data); @@ -578,12 +578,12 @@ function guessType(path) { 'js': 'text/javascript', 'svg': 'image/svg+xml', }; - var extension = path.split('.').pop(); + let extension = path.split('.').pop(); return k_extension_to_type[extension]; } async function blobHandler(request, response, blobId, uri) { - for (var i in kStaticFiles) { + for (let i in kStaticFiles) { if (uri === kStaticFiles[i].uri && kStaticFiles[i].path) { let stat = await File.stat('core/' + kStaticFiles[i].path); let id = `${stat.mtime}_${stat.size}`; @@ -592,7 +592,7 @@ async function blobHandler(request, response, blobId, uri) { response.writeHead(304, {}); response.end(); } else { - var data = await File.readFile('core/' + kStaticFiles[i].path); + let data = await File.readFile('core/' + kStaticFiles[i].path); response.writeHead(200, Object.assign( { 'Content-Type': kStaticFiles[i].type, @@ -612,11 +612,12 @@ async function blobHandler(request, response, blobId, uri) { return; } - var process; + let process; if (uri == "/view") { - var data; + let data; + let match; if (match = /^\/\~(\w+)\/(\w+)$/.exec(blobId)) { - var id = await new Database(match[1]).get('path:' + match[2]); + let id = await new Database(match[1]).get('path:' + match[2]); if (id) { if (request.headers['if-none-match'] === '"' + id + '"') { response.writeHead(304, {}); @@ -624,7 +625,7 @@ async function blobHandler(request, response, blobId, uri) { } else { data = await getBlobOrContent(id); if (match[3]) { - var appObject = JSON.parse(data); + let appObject = JSON.parse(data); data = appObject.files[match[3]]; } sendData(response, data, undefined, {etag: '"' + id + '"'}); @@ -647,17 +648,17 @@ async function blobHandler(request, response, blobId, uri) { } } } else if (uri == "/save") { - var match; + let match; if (match = /^\/\~(\w+)\/(\w+)$/.exec(blobId)) { let newBlobId = await ssb.blobStore(request.body); - var user = match[1]; - var appName = match[2]; - var credentials = auth.query(request.headers); + let user = match[1]; + let appName = match[2]; + let credentials = auth.query(request.headers); if (credentials && credentials.session && (credentials.session.name == user || (credentials.permissions.administration && user == 'core'))) { - var database = new Database(user); - var apps = new Set(); + let database = new Database(user); + let apps = new Set(); let apps_original = database.get('apps'); try { apps = new Set(JSON.parse(apps_original)); @@ -691,14 +692,14 @@ async function blobHandler(request, response, blobId, uri) { } else if (uri == "/delete") { let match; if (match = /^\/\~(\w+)\/(\w+)$/.exec(blobId)) { - var user = match[1]; - var appName = match[2]; - var credentials = auth.query(request.headers); + let user = match[1]; + let appName = match[2]; + let credentials = auth.query(request.headers); if (credentials && credentials.session && (credentials.session.name == user || (credentials.permissions.administration && user == 'core'))) { - var database = new Database(user); - var apps = new Set(); + let database = new Database(user); + let apps = new Set(); try { apps = new Set(JSON.parse(database.get('apps'))); } catch { @@ -717,12 +718,13 @@ async function blobHandler(request, response, blobId, uri) { response.writeHead(200, {"Content-Type": "text/plain; charset=utf-8"}); response.end('OK'); } else { - var data; - var type; - var headers; + let data; + let type; + let headers; + let match; if (match = /^\/\~(\w+)\/(\w+)$/.exec(blobId)) { - var db = new Database(match[1]); - var id = await db.get('path:' + match[2]); + let db = new Database(match[1]); + let id = await db.get('path:' + match[2]); if (id) { if (request.headers['if-none-match'] && request.headers['if-none-match'] == '"' + id + '"') { headers = { @@ -732,7 +734,7 @@ async function blobHandler(request, response, blobId, uri) { response.end(); } else { data = utf8Decode(await getBlobOrContent(id)); - var appObject = JSON.parse(data); + let appObject = JSON.parse(data); data = appObject.files[uri.substring(1)]; data = await getBlobOrContent(data); type = guessType(uri); @@ -747,7 +749,7 @@ async function blobHandler(request, response, blobId, uri) { } } else { data = utf8Decode(await getBlobOrContent(blobId)); - var appObject = JSON.parse(data); + let appObject = JSON.parse(data); data = appObject.files[uri.substring(1)]; data = await getBlobOrContent(data); headers = { @@ -767,10 +769,10 @@ ssb.addEventListener('connections', function() { }); async function loadSettings() { - var data; + let data; try { - var settings = new Database('core').get('settings'); + let settings = new Database('core').get('settings'); if (settings) { data = JSON.parse(settings); } @@ -816,7 +818,7 @@ function enableStats(process, enabled) { loadSettings().then(function() { httpd.all("/login", auth.handler); httpd.all("", function(request, response) { - var match; + let match; if (request.uri === "/" || request.uri === "") { response.writeHead(303, {"Location": (request.client.tls ? 'https://' : 'http://') + request.headers.host + gGlobalSettings.index, "Content-Length": "0"}); return response.end(); @@ -837,15 +839,15 @@ loadSettings().then(function() { } else if (match = /^(.*)(\/(?:save|delete)?)$/.exec(request.uri)) { return blobHandler(request, response, match[1], match[2]); } else if (match = /^\/trace$/.exec(request.uri)) { - var data = trace(); + let data = trace(); response.writeHead(200, {"Content-Type": "application/json; charset=utf-8", "Content-Length": data.length.toString()}); return response.end(data); } else if (match = /^\/disconnections$/.exec(request.uri)) { - var data = utf8Encode(JSON.stringify(disconnectionsDebug(), null, 2)); + let data = utf8Encode(JSON.stringify(disconnectionsDebug(), null, 2)); response.writeHead(200, {"Content-Type": "application/json; charset=utf-8", "Content-Length": data.byteLength.toString()}); return response.end(data); } else if (match = /^\/debug$/.exec(request.uri)) { - var data = JSON.stringify(getDebug(), null, 2); + let data = JSON.stringify(getDebug(), null, 2); response.writeHead(200, {"Content-Type": "application/json; charset=utf-8", "Content-Length": data.length.toString()}); return response.end(data); } else if (request.uri == "/robots.txt") { @@ -853,7 +855,7 @@ loadSettings().then(function() { } else if ((match = /^\/.well-known\/(.*)/.exec(request.uri)) && request.uri.indexOf("..") == -1) { return wellKnownHandler(request, response, match[1]); } else { - var data = "File not found."; + let data = "File not found."; response.writeHead(404, {"Content-Type": "text/plain; charset=utf-8", "Content-Length": data.length.toString()}); return response.end(data); } diff --git a/core/httpd.js b/core/httpd.js index 5a68197f..cf557a4f 100644 --- a/core/httpd.js +++ b/core/httpd.js @@ -1,7 +1,5 @@ import * as core from './core.js'; -"use strict"; - let gHandlers = []; let gSocketHandlers = []; let gBadRequests = {}; diff --git a/core/index.html b/core/index.html index 8815c06c..6a2e71dd 100644 --- a/core/index.html +++ b/core/index.html @@ -11,8 +11,8 @@ 😎 Tilde Friends apps - edit - 🎛️ + edit + 🎛️ @@ -22,31 +22,31 @@