ssb: Support publishing private messages from the command-line. #89
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 26m28s
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 26m28s
This commit is contained in:
104
src/ssb.js.c
104
src/ssb.js.c
@ -1857,11 +1857,6 @@ static JSValue _tf_ssb_createTunnel(JSContext* context, JSValueConst this_val, i
|
||||
return result ? JS_TRUE : JS_FALSE;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
k_max_private_message_recipients = 8
|
||||
};
|
||||
|
||||
static bool _tf_ssb_get_private_key_curve25519_internal(sqlite3* db, const char* user, const char* identity, uint8_t out_private_key[static crypto_sign_SECRETKEYBYTES])
|
||||
{
|
||||
if (!user || !identity)
|
||||
@ -1910,14 +1905,12 @@ typedef struct _private_message_encrypt_t
|
||||
{
|
||||
const char* signer_user;
|
||||
const char* signer_identity;
|
||||
uint8_t recipients[k_max_private_message_recipients][crypto_scalarmult_curve25519_SCALARBYTES];
|
||||
const char* recipients[k_max_private_message_recipients];
|
||||
int recipient_count;
|
||||
const char* message;
|
||||
size_t message_size;
|
||||
JSValue promise[2];
|
||||
bool error_id_not_found;
|
||||
bool error_secretbox_failed;
|
||||
bool error_scalarmult_failed;
|
||||
char* encrypted;
|
||||
size_t encrypted_length;
|
||||
} private_message_encrypt_t;
|
||||
@ -1933,73 +1926,8 @@ static void _tf_ssb_private_message_encrypt_work(tf_ssb_t* ssb, void* user_data)
|
||||
|
||||
if (found)
|
||||
{
|
||||
uint8_t public_key[crypto_box_PUBLICKEYBYTES] = { 0 };
|
||||
uint8_t secret_key[crypto_box_SECRETKEYBYTES] = { 0 };
|
||||
uint8_t nonce[crypto_box_NONCEBYTES] = { 0 };
|
||||
uint8_t body_key[crypto_box_SECRETKEYBYTES] = { 0 };
|
||||
crypto_box_keypair(public_key, secret_key);
|
||||
randombytes_buf(nonce, sizeof(nonce));
|
||||
randombytes_buf(body_key, sizeof(body_key));
|
||||
|
||||
uint8_t length_and_key[1 + sizeof(body_key)];
|
||||
length_and_key[0] = (uint8_t)work->recipient_count;
|
||||
memcpy(length_and_key + 1, body_key, sizeof(body_key));
|
||||
|
||||
size_t payload_size =
|
||||
sizeof(nonce) + sizeof(public_key) + (crypto_secretbox_MACBYTES + sizeof(length_and_key)) * work->recipient_count + crypto_secretbox_MACBYTES + work->message_size;
|
||||
|
||||
uint8_t* payload = tf_malloc(payload_size);
|
||||
|
||||
uint8_t* p = payload;
|
||||
memcpy(p, nonce, sizeof(nonce));
|
||||
p += sizeof(nonce);
|
||||
|
||||
memcpy(p, public_key, sizeof(public_key));
|
||||
p += sizeof(public_key);
|
||||
|
||||
for (int i = 0; i < work->recipient_count; i++)
|
||||
{
|
||||
uint8_t shared_secret[crypto_secretbox_KEYBYTES] = { 0 };
|
||||
if (crypto_scalarmult(shared_secret, secret_key, work->recipients[i]) == 0)
|
||||
{
|
||||
if (crypto_secretbox_easy(p, length_and_key, sizeof(length_and_key), nonce, shared_secret) != 0)
|
||||
{
|
||||
work->error_secretbox_failed = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
p += crypto_secretbox_MACBYTES + sizeof(length_and_key);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
work->error_scalarmult_failed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!work->error_secretbox_failed && !work->error_scalarmult_failed)
|
||||
{
|
||||
if (crypto_secretbox_easy(p, (const uint8_t*)work->message, work->message_size, nonce, body_key) != 0)
|
||||
{
|
||||
work->error_scalarmult_failed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
p += crypto_secretbox_MACBYTES + work->message_size;
|
||||
assert((size_t)(p - payload) == payload_size);
|
||||
|
||||
char* encoded = tf_malloc(payload_size * 2 + 5);
|
||||
size_t encoded_length = tf_base64_encode(payload, payload_size, encoded, payload_size * 2 + 5);
|
||||
memcpy(encoded + encoded_length, ".box", 5);
|
||||
encoded_length += 4;
|
||||
|
||||
work->encrypted = encoded;
|
||||
work->encrypted_length = encoded_length;
|
||||
}
|
||||
}
|
||||
tf_free(payload);
|
||||
work->encrypted = tf_ssb_private_message_encrypt(private_key, work->recipients, work->recipient_count, work->message, work->message_size);
|
||||
work->encrypted_length = work->encrypted ? strlen(work->encrypted) : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2012,13 +1940,9 @@ static void _tf_ssb_private_message_encrypt_after_work(tf_ssb_t* ssb, int status
|
||||
private_message_encrypt_t* work = user_data;
|
||||
JSContext* context = tf_ssb_get_context(ssb);
|
||||
JSValue result = JS_UNDEFINED;
|
||||
if (work->error_secretbox_failed)
|
||||
if (!work->encrypted)
|
||||
{
|
||||
result = JS_ThrowInternalError(context, "crypto_secretbox_easy failed");
|
||||
}
|
||||
else if (work->error_scalarmult_failed)
|
||||
{
|
||||
result = JS_ThrowInternalError(context, "crypto_scalarmult failed");
|
||||
result = JS_ThrowInternalError(context, "Encrypt failed.");
|
||||
}
|
||||
else if (work->error_id_not_found)
|
||||
{
|
||||
@ -2030,6 +1954,10 @@ static void _tf_ssb_private_message_encrypt_after_work(tf_ssb_t* ssb, int status
|
||||
tf_free((void*)work->encrypted);
|
||||
}
|
||||
|
||||
for (int i = 0; i < work->recipient_count; i++)
|
||||
{
|
||||
tf_free((void*)work->recipients[i]);
|
||||
}
|
||||
JSValue error = JS_Call(context, work->promise[0], JS_UNDEFINED, 1, &result);
|
||||
JS_FreeValue(context, result);
|
||||
tf_util_report_error(context, error);
|
||||
@ -2051,24 +1979,14 @@ static JSValue _tf_ssb_private_message_encrypt(JSContext* context, JSValueConst
|
||||
return JS_ThrowRangeError(context, "Number of recipients must be between 1 and %d.", k_max_private_message_recipients);
|
||||
}
|
||||
|
||||
uint8_t recipients[k_max_private_message_recipients][crypto_scalarmult_curve25519_SCALARBYTES] = { 0 };
|
||||
char* recipients[k_max_private_message_recipients] = { 0 };
|
||||
for (int i = 0; i < recipient_count && JS_IsUndefined(result); i++)
|
||||
{
|
||||
JSValue recipient = JS_GetPropertyUint32(context, argv[2], i);
|
||||
const char* id = JS_ToCString(context, recipient);
|
||||
if (id)
|
||||
{
|
||||
const char* type = strstr(id, ".ed25519");
|
||||
const char* id_start = *id == '@' ? id + 1 : id;
|
||||
uint8_t key[crypto_box_PUBLICKEYBYTES] = { 0 };
|
||||
if (tf_base64_decode(id_start, type ? (size_t)(type - id_start) : strlen(id_start), key, sizeof(key)) != sizeof(key))
|
||||
{
|
||||
result = JS_ThrowInternalError(context, "Invalid recipient: %s.\n", id);
|
||||
}
|
||||
else if (crypto_sign_ed25519_pk_to_curve25519(recipients[i], key) != 0)
|
||||
{
|
||||
result = JS_ThrowInternalError(context, "Failed to convert recipient ID.\n");
|
||||
}
|
||||
recipients[i] = tf_strdup(id);
|
||||
JS_FreeCString(context, id);
|
||||
}
|
||||
JS_FreeValue(context, recipient);
|
||||
|
Reference in New Issue
Block a user