diff --git a/core/core.js b/core/core.js index 2dbf86dc..29a208bf 100644 --- a/core/core.js +++ b/core/core.js @@ -4,86 +4,6 @@ import * as http from './http.js'; let gProcesses = {}; let gStatsTimer = false; - -const k_global_settings = { - index: { - type: 'string', - default_value: '/~core/apps/', - description: 'Default path.', - }, - index_map: { - type: 'textarea', - default_value: undefined, - description: - 'Mappings from hostname to redirect path, one per line, as in: "www.tildefriends.net=/~core/index/"', - }, - room: { - type: 'boolean', - default_value: true, - description: 'Enable peers to tunnel through this instance as a room.', - }, - room_name: { - type: 'string', - default_value: 'tilde friends tunnel', - description: 'Name of the room.', - }, - replicator: { - type: 'boolean', - default_value: true, - description: 'Enable message and blob replication.', - }, - code_of_conduct: { - type: 'textarea', - default_value: undefined, - description: 'Code of conduct presented at sign-in.', - }, - http_redirect: { - type: 'string', - default_value: undefined, - description: - 'If connecting by HTTP and HTTPS is configured, Location header prefix (ie, "https://example.com")', - }, - fetch_hosts: { - type: 'string', - default_value: undefined, - description: - 'Comma-separated list of host names to which HTTP fetch requests are allowed. None if empty.', - }, - blob_fetch_age_seconds: { - type: 'integer', - default_value: - platform() == 'android' || platform() == 'iphone' - ? 0.5 * 365 * 24 * 60 * 60 - : undefined, - description: - 'Only blobs mentioned more recently than this age will be automatically fetched.', - }, - blob_expire_age_seconds: { - type: 'integer', - default_value: - platform() == 'android' || platform() == 'iphone' - ? 1.0 * 365 * 24 * 60 * 60 - : undefined, - description: 'Blobs older than this will be automatically deleted.', - }, - seeds_host: { - type: 'string', - default_value: 'seeds.tildefriends.net', - description: 'Hostname for seed connections.', - }, - peer_exchange: { - type: 'boolean', - default_value: false, - description: - 'Enable discovery of, sharing of, and connecting to internet peer strangers, including announcing this instance.', - }, - account_registration: { - type: 'boolean', - default_value: true, - description: 'Allow registration of new accounts.', - }, -}; - let kPingInterval = 60 * 1000; /** @@ -486,7 +406,7 @@ async function getProcessBlob(blobId, key, options) { }; if (process.credentials?.permissions?.administration) { imports.core.globalSettingsDescriptions = async function () { - let settings = Object.assign({}, k_global_settings); + let settings = Object.assign({}, defaultGlobalSettings()); for (let [key, value] of Object.entries(await loadSettings())) { if (settings[key]) { settings[key].value = value; @@ -834,7 +754,7 @@ async function loadSettings() { } catch (error) { print('Settings not found in database:', error); } - for (let [key, value] of Object.entries(k_global_settings)) { + for (let [key, value] of Object.entries(defaultGlobalSettings())) { if (data[key] === undefined) { data[key] = value.default_value; } diff --git a/src/util.js.c b/src/util.js.c index 3095b306..47ae730a 100644 --- a/src/util.js.c +++ b/src/util.js.c @@ -20,6 +20,8 @@ #include #endif +#define tf_countof(a) ((int)(sizeof((a)) / sizeof(*(a)))) + static JSValue _util_utf8_encode(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { size_t length = 0; @@ -304,6 +306,66 @@ static JSValue _util_parseHttpResponse(JSContext* context, JSValueConst this_val return result; } +#if defined(__APPLE__) +#include +#endif + +static bool _is_mobile() +{ +#if defined(__ANDROID__) || (defined(__APPLE__) && TARGET_OS_IPHONE) + return true; +#else + return false; +#endif +} + +static JSValue _util_defaultGlobalSettings(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) +{ + typedef struct _setting_t + { + const char* name; + const char* type; + const char* description; + JSValue default_value; + } setting_t; + + const setting_t k_settings[] = { + { .name = "code_of_conduct", .type = "textarea", .description = "Code of conduct presented at sign-in." }, + { .name = "blob_fetch_age_seconds", + .type = "integer", + .description = "Only blobs mentioned more recently than this age will be automatically fetched.", + .default_value = _is_mobile() ? JS_NewInt32(context, (int)(0.5f * 365 * 24 * 60 * 60)) : JS_UNDEFINED }, + { .name = "blob_expire_age_seconds", + .type = "integer", + .description = "Blobs older than this will be automatically deleted.", + .default_value = _is_mobile() ? JS_NewInt32(context, (int)(1.0f * 365 * 24 * 60 * 60)) : JS_UNDEFINED }, + { .name = "fetch_hosts", .type = "string", .description = "Comma-separated list of host names to which HTTP fetch requests are allowed. None if empty." }, + { .name = "http_redirect", .type = "string", .description = "If connecting by HTTP and HTTPS is configured, Location header prefix (ie, \"http://example.com\")" }, + { .name = "index", .type = "string", .description = "Default path.", .default_value = JS_NewString(context, "/~core/apps") }, + { .name = "index_map", .type = "textarea", .description = "Mappings from hostname to redirect path, one per line, as in: \"www.tildefriends.net=/~core/index/\"" }, + { .name = "peer_exchange", + .type = "boolean", + .description = "Enable discovery of, sharing of, and connecting to internet peer strangers, including announcing this instance.", + .default_value = JS_FALSE }, + { .name = "replicator", .type = "boolean", .description = "Enable message and blob replication.", .default_value = JS_TRUE }, + { .name = "room", .type = "boolean", .description = "Enable peers to tunnel through this instance as a room.", .default_value = JS_TRUE }, + { .name = "room_name", .type = "string", .description = "Name of the room.", .default_value = JS_NewString(context, "tilde friends tunnel") }, + { .name = "seeds_host", .type = "string", .description = "Hostname for seed connections.", .default_value = JS_NewString(context, "seeds.tildefriends.net") }, + { .name = "account_registration", .type = "boolean", .description = "Allow registration of new accounts.", .default_value = JS_TRUE }, + }; + + JSValue settings = JS_NewObject(context); + for (int i = 0; i < tf_countof(k_settings); i++) + { + JSValue entry = JS_NewObject(context); + JS_SetPropertyStr(context, entry, "type", JS_NewString(context, k_settings[i].type)); + JS_SetPropertyStr(context, entry, "description", JS_NewString(context, k_settings[i].description)); + JS_SetPropertyStr(context, entry, "default_value", k_settings[i].default_value); + JS_SetPropertyStr(context, settings, k_settings[i].name, entry); + } + return settings; +} + JSValue tf_util_new_uint8_array(JSContext* context, const uint8_t* data, size_t size) { JSValue array_buffer = JS_NewArrayBufferCopy(context, data, size); @@ -327,6 +389,7 @@ void tf_util_register(JSContext* context) JS_SetPropertyStr(context, global, "bip39Bytes", JS_NewCFunction(context, _util_bip39_bytes, "bip39Bytes", 1)); JS_SetPropertyStr(context, global, "print", JS_NewCFunction(context, _util_print, "print", 1)); JS_SetPropertyStr(context, global, "parseHttpResponse", JS_NewCFunction(context, _util_parseHttpResponse, "parseHttpResponse", 2)); + JS_SetPropertyStr(context, global, "defaultGlobalSettings", JS_NewCFunction(context, _util_defaultGlobalSettings, "defaultGlobalSettings", 2)); JS_FreeValue(context, global); }