Compare commits
	
		
			2 Commits
		
	
	
		
			700dd7b45a
			...
			0e7d2a8b0e
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 0e7d2a8b0e | |||
| 3743543ef8 | 
@@ -1,5 +1,5 @@
 | 
			
		||||
{
 | 
			
		||||
	"type": "tildefriends-app",
 | 
			
		||||
	"emoji": "🪪",
 | 
			
		||||
	"previous": "&zxsmzdLKsiG/WZt/Gw7JOxepgypoktNNbIyWiyFiJVc=.sha256"
 | 
			
		||||
	"previous": "&5kw/2PgcySwOYCmAkjHTR2xTkIx3i7UjQmtQ8MfgWw8=.sha256"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
import * as tfrpc from '/tfrpc.js';
 | 
			
		||||
 | 
			
		||||
const is_admin = core.user?.credentials?.permissions?.administration;
 | 
			
		||||
 | 
			
		||||
tfrpc.register(async function get_private_key(id) {
 | 
			
		||||
	return bip39Words(await ssb.getPrivateKey(id));
 | 
			
		||||
});
 | 
			
		||||
@@ -15,6 +17,9 @@ tfrpc.register(async function delete_id(id) {
 | 
			
		||||
tfrpc.register(async function reload() {
 | 
			
		||||
	await main();
 | 
			
		||||
});
 | 
			
		||||
tfrpc.register(async function make_server(id) {
 | 
			
		||||
	return await ssb.swapWithServerIdentity(id);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
async function main() {
 | 
			
		||||
	let ids = await ssb.getIdentities();
 | 
			
		||||
@@ -99,6 +104,16 @@ async function main() {
 | 
			
		||||
					alert('Error deleting ID: ' + e);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			handler.make_server = async function make_server(event) {
 | 
			
		||||
				let id = event.srcElement.dataset.id;
 | 
			
		||||
				try {
 | 
			
		||||
					if (confirm('Are you sure you want to make "' + id + '" the server identity?\\n\\nFor it to take effect, you will need to both sign in again and restart Tilde Friends.')) {
 | 
			
		||||
						await tfrpc.rpc.make_server(id);
 | 
			
		||||
					}
 | 
			
		||||
				} catch (e) {
 | 
			
		||||
					alert('Error making server ID: ' + e);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		</script>
 | 
			
		||||
		<header class="w3-theme w3-padding"><h1>SSB Identity Management</h1></header>
 | 
			
		||||
		<div class="w3-card-4 w3-margin">
 | 
			
		||||
@@ -117,13 +132,14 @@ async function main() {
 | 
			
		||||
		<div class="w3-card-4 w3-margin">
 | 
			
		||||
			<header class="w3-container w3-theme-l2"><h2>Identities</h2></header>
 | 
			
		||||
			<ul class="w3-ul">` +
 | 
			
		||||
			ids
 | 
			
		||||
			(ids ?? [])
 | 
			
		||||
				.map(
 | 
			
		||||
					(
 | 
			
		||||
						id
 | 
			
		||||
					) => `<li style="overflow: hidden; text-wrap: nowrap; text-overflow: ellipsis">
 | 
			
		||||
				<button onclick="handler.export_id(event)" data-id="${id}" class="w3-button w3-theme">Export Identity</button>
 | 
			
		||||
				<button onclick="handler.delete_id(event)" data-id="${id}" class="w3-button w3-theme">Delete Identity</button>
 | 
			
		||||
				${is_admin && id != server_id ? `<button onclick="handler.make_server(event)" data-id="${id}" class="w3-button w3-theme">Make Server Identity</button>` : ''}
 | 
			
		||||
				${id}${id == server_id ? ' <div class="w3-tag w3-theme-l4 w3-round">🖥 local server</div>' : ''}
 | 
			
		||||
			</li>`
 | 
			
		||||
				)
 | 
			
		||||
 
 | 
			
		||||
@@ -72,16 +72,21 @@
 | 
			
		||||
						<a
 | 
			
		||||
							class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
 | 
			
		||||
							href="https://f-droid.org/en/packages/com.unprompted.tildefriends.fdroid/"
 | 
			
		||||
							><img src="f-droid.svg" style="height: 2em; margin: 0"
 | 
			
		||||
						/> Get it on F-Droid</a>
 | 
			
		||||
						<a class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
 | 
			
		||||
							href="https://dev.tildefriends.net/releases/tildefriends-x86_64.AppImage">
 | 
			
		||||
							<img src="appimage.svg" style="height: 2em; margin: 0">
 | 
			
		||||
							><img src="f-droid.svg" style="height: 2em; margin: 0" /> Get it
 | 
			
		||||
							on F-Droid</a
 | 
			
		||||
						>
 | 
			
		||||
						<a
 | 
			
		||||
							class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
 | 
			
		||||
							href="https://dev.tildefriends.net/releases/tildefriends-x86_64.AppImage"
 | 
			
		||||
						>
 | 
			
		||||
							<img src="appimage.svg" style="height: 2em; margin: 0" />
 | 
			
		||||
							Get Linux 64-bit AppImage
 | 
			
		||||
						</a>
 | 
			
		||||
						<a class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
 | 
			
		||||
							href="https://play.google.com/store/apps/details?id=com.unprompted.tildefriends">
 | 
			
		||||
							<img src="googleplay.svg" style="height: 2em; margin: 0">
 | 
			
		||||
						<a
 | 
			
		||||
							class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
 | 
			
		||||
							href="https://play.google.com/store/apps/details?id=com.unprompted.tildefriends"
 | 
			
		||||
						>
 | 
			
		||||
							<img src="googleplay.svg" style="height: 2em; margin: 0" />
 | 
			
		||||
							Get it on Google Play (Open Testing)
 | 
			
		||||
						</a>
 | 
			
		||||
					</p>
 | 
			
		||||
@@ -110,9 +115,7 @@
 | 
			
		||||
								>https://www.tildefriends.net/</a
 | 
			
		||||
							>.
 | 
			
		||||
						</li>
 | 
			
		||||
						<li>
 | 
			
		||||
							Create an account to identify yourself with that instance.
 | 
			
		||||
						</li>
 | 
			
		||||
						<li>Create an account to identify yourself with that instance.</li>
 | 
			
		||||
						<li>
 | 
			
		||||
							Describe yourself in your profile in the <b>ssb</b> app. Give
 | 
			
		||||
							yourself a name and an avatar if you like.
 | 
			
		||||
@@ -121,10 +124,16 @@
 | 
			
		||||
							Connect to others.
 | 
			
		||||
							<ul>
 | 
			
		||||
								<li>Automatically discover peers on the same network.</li>
 | 
			
		||||
									<li>Manually connect to rooms and pubs, including <a href="https://www.tildefriends.net/~cory/room/"
 | 
			
		||||
								<li>
 | 
			
		||||
									Manually connect to rooms and pubs, including
 | 
			
		||||
									<a href="https://www.tildefriends.net/~cory/room/"
 | 
			
		||||
										>tildefriends.net itself</a
 | 
			
		||||
									>.</li>
 | 
			
		||||
									<li>Enable <b>Peer Exchange</b> in the <b>admin</b> to discover internet peers.</li>
 | 
			
		||||
									>.
 | 
			
		||||
								</li>
 | 
			
		||||
								<li>
 | 
			
		||||
									Enable <b>Peer Exchange</b> in the <b>admin</b> to discover
 | 
			
		||||
									internet peers.
 | 
			
		||||
								</li>
 | 
			
		||||
							</ul>
 | 
			
		||||
						</li>
 | 
			
		||||
						<li>Follow people to grow your network.</li>
 | 
			
		||||
@@ -216,10 +225,11 @@
 | 
			
		||||
		<div class="w3-container w3-padding-64 w3-light-grey w3-center">
 | 
			
		||||
			<h1 class="w3-jumbo"><b>Boring Technology</b></h1>
 | 
			
		||||
			<p>
 | 
			
		||||
				Tilde Friends is built using boring, trusted tech.  Unless a better reason
 | 
			
		||||
				presents itself, it strives to use only simple and
 | 
			
		||||
				widely adopted dependencies in order to keep it easy to build for
 | 
			
		||||
				all sorts of platforms and maintainable for a very long time.</p>
 | 
			
		||||
				Tilde Friends is built using boring, trusted tech. Unless a better
 | 
			
		||||
				reason presents itself, it strives to use only simple and widely adopted
 | 
			
		||||
				dependencies in order to keep it easy to build for all sorts of
 | 
			
		||||
				platforms and maintainable for a very long time.
 | 
			
		||||
			</p>
 | 
			
		||||
			<p>
 | 
			
		||||
				Though of course for building Tilde Friends apps, you are free to use
 | 
			
		||||
				whatever fits.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								core/core.js
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								core/core.js
									
									
									
									
									
								
							@@ -692,6 +692,18 @@ async function getProcessBlob(blobId, key, options) {
 | 
			
		||||
					);
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
			imports.ssb.swapWithServerIdentity = function (id) {
 | 
			
		||||
				if (
 | 
			
		||||
					process.credentials &&
 | 
			
		||||
					process.credentials.session &&
 | 
			
		||||
					process.credentials.session.name
 | 
			
		||||
				) {
 | 
			
		||||
					return ssb.swapWithServerIdentity(
 | 
			
		||||
						process.credentials.session.name,
 | 
			
		||||
						id
 | 
			
		||||
					);
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
			imports.ssb.addEventListener = undefined;
 | 
			
		||||
			imports.ssb.removeEventListener = undefined;
 | 
			
		||||
			imports.ssb.getIdentityInfo = undefined;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										104
									
								
								src/ssb.js.c
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								src/ssb.js.c
									
									
									
									
									
								
							@@ -360,6 +360,109 @@ static JSValue _tf_ssb_set_server_following_me(JSContext* context, JSValueConst
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct _swap_with_server_identity_t
 | 
			
		||||
{
 | 
			
		||||
	char server_id[k_id_base64_len];
 | 
			
		||||
	char id[k_id_base64_len];
 | 
			
		||||
	JSValue promise[2];
 | 
			
		||||
	char* error;
 | 
			
		||||
	char user[];
 | 
			
		||||
} swap_with_server_identity_t;
 | 
			
		||||
 | 
			
		||||
static void _tf_ssb_swap_with_server_identity_work(tf_ssb_t* ssb, void* user_data)
 | 
			
		||||
{
 | 
			
		||||
	swap_with_server_identity_t* work = user_data;
 | 
			
		||||
	if (tf_ssb_db_user_has_permission(ssb, work->user, "administration"))
 | 
			
		||||
	{
 | 
			
		||||
		sqlite3* db = tf_ssb_acquire_db_writer(ssb);
 | 
			
		||||
		char* error = NULL;
 | 
			
		||||
		if (sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, &error) == SQLITE_OK)
 | 
			
		||||
		{
 | 
			
		||||
			sqlite3_stmt* statement = NULL;
 | 
			
		||||
			if (sqlite3_prepare(db, "UPDATE identities SET user = ? WHERE user = ? AND '@' || public_key = ?", -1, &statement, NULL) == SQLITE_OK)
 | 
			
		||||
			{
 | 
			
		||||
				if (sqlite3_bind_text(statement, 1, work->user, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, ":admin", -1, NULL) == SQLITE_OK &&
 | 
			
		||||
					sqlite3_bind_text(statement, 3, work->server_id, -1, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_DONE && sqlite3_changes(db) == 1 &&
 | 
			
		||||
					sqlite3_reset(statement) == SQLITE_OK && sqlite3_bind_text(statement, 1, ":admin", -1, NULL) == SQLITE_OK &&
 | 
			
		||||
					sqlite3_bind_text(statement, 2, work->user, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 3, work->id, -1, NULL) == SQLITE_OK &&
 | 
			
		||||
					sqlite3_step(statement) == SQLITE_DONE && sqlite3_changes(db) == 1)
 | 
			
		||||
				{
 | 
			
		||||
					error = NULL;
 | 
			
		||||
					if (sqlite3_exec(db, "COMMIT TRANSACTION", NULL, NULL, &error) != SQLITE_OK)
 | 
			
		||||
					{
 | 
			
		||||
						work->error = error ? tf_strdup(error) : tf_strdup(sqlite3_errmsg(db));
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
					work->error = tf_strdup(sqlite3_errmsg(db) ? sqlite3_errmsg(db) : "swap failed");
 | 
			
		||||
				}
 | 
			
		||||
				sqlite3_finalize(statement);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				work->error = tf_strdup(sqlite3_errmsg(db));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			work->error = error ? tf_strdup(error) : tf_strdup(sqlite3_errmsg(db));
 | 
			
		||||
		}
 | 
			
		||||
		tf_ssb_release_db_writer(ssb, db);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		work->error = tf_strdup("not administrator");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _tf_ssb_swap_with_server_identity_after_work(tf_ssb_t* ssb, int status, void* user_data)
 | 
			
		||||
{
 | 
			
		||||
	swap_with_server_identity_t* work = user_data;
 | 
			
		||||
	JSContext* context = tf_ssb_get_context(ssb);
 | 
			
		||||
	JSValue error = JS_UNDEFINED;
 | 
			
		||||
	if (work->error)
 | 
			
		||||
	{
 | 
			
		||||
		JSValue arg = JS_ThrowInternalError(context, "%s", work->error);
 | 
			
		||||
		JSValue exception = JS_GetException(context);
 | 
			
		||||
		error = JS_Call(context, work->promise[1], JS_UNDEFINED, 1, &exception);
 | 
			
		||||
		tf_free(work->error);
 | 
			
		||||
		JS_FreeValue(context, exception);
 | 
			
		||||
		JS_FreeValue(context, arg);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		error = JS_Call(context, work->promise[0], JS_UNDEFINED, 0, NULL);
 | 
			
		||||
	}
 | 
			
		||||
	tf_util_report_error(context, error);
 | 
			
		||||
	JS_FreeValue(context, error);
 | 
			
		||||
	JS_FreeValue(context, work->promise[0]);
 | 
			
		||||
	JS_FreeValue(context, work->promise[1]);
 | 
			
		||||
	tf_free(work);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static JSValue _tf_ssb_swap_with_server_identity(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
 | 
			
		||||
{
 | 
			
		||||
	tf_ssb_t* ssb = JS_GetOpaque(this_val, _tf_ssb_classId);
 | 
			
		||||
	JSValue result = JS_UNDEFINED;
 | 
			
		||||
	if (ssb)
 | 
			
		||||
	{
 | 
			
		||||
		size_t user_length = 0;
 | 
			
		||||
		const char* user = JS_ToCStringLen(context, &user_length, argv[0]);
 | 
			
		||||
		const char* id = JS_ToCString(context, argv[1]);
 | 
			
		||||
		swap_with_server_identity_t* work = tf_malloc(sizeof(swap_with_server_identity_t) + user_length + 1);
 | 
			
		||||
		*work = (swap_with_server_identity_t) { 0 };
 | 
			
		||||
		tf_ssb_whoami(ssb, work->server_id, sizeof(work->server_id));
 | 
			
		||||
		snprintf(work->id, sizeof(work->id), "%s", id);
 | 
			
		||||
		memcpy(work->user, user, user_length + 1);
 | 
			
		||||
		result = JS_NewPromiseCapability(context, work->promise);
 | 
			
		||||
		tf_ssb_run_work(ssb, _tf_ssb_swap_with_server_identity_work, _tf_ssb_swap_with_server_identity_after_work, work);
 | 
			
		||||
		JS_FreeCString(context, user);
 | 
			
		||||
		JS_FreeCString(context, id);
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct _identities_visit_t
 | 
			
		||||
{
 | 
			
		||||
	JSContext* context;
 | 
			
		||||
@@ -2312,6 +2415,7 @@ void tf_ssb_register(JSContext* context, tf_ssb_t* ssb)
 | 
			
		||||
	JS_SetPropertyStr(context, object, "addIdentity", JS_NewCFunction(context, _tf_ssb_addIdentity, "addIdentity", 2));
 | 
			
		||||
	JS_SetPropertyStr(context, object, "deleteIdentity", JS_NewCFunction(context, _tf_ssb_deleteIdentity, "deleteIdentity", 2));
 | 
			
		||||
	JS_SetPropertyStr(context, object, "setServerFollowingMe", JS_NewCFunction(context, _tf_ssb_set_server_following_me, "setServerFollowingMe", 3));
 | 
			
		||||
	JS_SetPropertyStr(context, object, "swapWithServerIdentity", JS_NewCFunction(context, _tf_ssb_swap_with_server_identity, "swapWithServerIdentity", 2));
 | 
			
		||||
	JS_SetPropertyStr(context, object, "getIdentities", JS_NewCFunction(context, _tf_ssb_getIdentities, "getIdentities", 1));
 | 
			
		||||
	JS_SetPropertyStr(context, object, "getPrivateKey", JS_NewCFunction(context, _tf_ssb_getPrivateKey, "getPrivateKey", 2));
 | 
			
		||||
	JS_SetPropertyStr(context, object, "privateMessageEncrypt", JS_NewCFunction(context, _tf_ssb_private_message_encrypt, "privateMessageEncrypt", 4));
 | 
			
		||||
 
 | 
			
		||||
@@ -1295,17 +1295,15 @@ static void _tf_ssb_rpc_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_chang
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _tf_ssb_rpc_broadcasts_changed_visit(const char* host, const struct sockaddr_in* addr, tf_ssb_broadcast_origin_t origin, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data)
 | 
			
		||||
static void _tf_ssb_rpc_broadcasts_changed_visit(
 | 
			
		||||
	const char* host, const struct sockaddr_in* addr, tf_ssb_broadcast_origin_t origin, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data)
 | 
			
		||||
{
 | 
			
		||||
	tf_ssb_t* ssb = user_data;
 | 
			
		||||
	if (tunnel &&
 | 
			
		||||
		(tf_ssb_connection_get_flags(tunnel) & k_tf_ssb_connect_flag_one_shot) != 0 &&
 | 
			
		||||
		!tf_ssb_connection_get_tunnel(tunnel))
 | 
			
		||||
	if (tunnel && (tf_ssb_connection_get_flags(tunnel) & k_tf_ssb_connect_flag_one_shot) != 0 && !tf_ssb_connection_get_tunnel(tunnel))
 | 
			
		||||
	{
 | 
			
		||||
		char target_id[k_id_base64_len] = { 0 };
 | 
			
		||||
		char portal_id[k_id_base64_len] = { 0 };
 | 
			
		||||
		if (tf_ssb_id_bin_to_str(target_id, sizeof(target_id), pub) &&
 | 
			
		||||
			tf_ssb_connection_get_id(tunnel, portal_id, sizeof(portal_id)))
 | 
			
		||||
		if (tf_ssb_id_bin_to_str(target_id, sizeof(target_id), pub) && tf_ssb_connection_get_id(tunnel, portal_id, sizeof(portal_id)))
 | 
			
		||||
		{
 | 
			
		||||
			tf_ssb_tunnel_create(ssb, portal_id, target_id, k_tf_ssb_connect_flag_one_shot);
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user