Skip to content

Commit 6079030

Browse files
committed
feat: add bitset for proFeaturesOfMessage & rotatingKeyGeneration
1 parent d062724 commit 6079030

File tree

11 files changed

+96
-123
lines changed

11 files changed

+96
-123
lines changed

include/pro/pro.hpp

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include <napi.h>
34
#include <oxenc/base64.h>
45
#include <oxenc/hex.h>
56

@@ -135,7 +136,7 @@ class ProWrapper : public Napi::ObjectWrap<ProWrapper> {
135136
// we expect two arguments that match:
136137
// first: {
137138
// "utf16": string,
138-
// "proFeatures": Array<ProFeature>,
139+
// "proFeaturesBitset": bigint,
139140
// }
140141

141142
assertInfoLength(info, 1);
@@ -147,27 +148,13 @@ class ProWrapper : public Napi::ObjectWrap<ProWrapper> {
147148
if (first.IsEmpty())
148149
throw std::invalid_argument("proFeaturesForMessage first received empty");
149150

150-
assertIsArray(first.Get("proFeatures"), "proFeaturesForMessage.proFeatures");
151-
auto proFeaturesJS = first.Get("proFeatures").As<Napi::Array>();
152-
std::vector<std::string> proFeatures;
153-
proFeatures.reserve(proFeaturesJS.Length());
154-
for (uint32_t i = 0; i < proFeaturesJS.Length(); i++) {
155-
auto itemValue = proFeaturesJS.Get(i);
156-
assertIsString(itemValue, "proFeaturesForMessage.proFeatures.itemValue");
157-
std::string item =
158-
toCppString(itemValue, "proFeaturesForMessage.proFeatures.itemValue");
159-
proFeatures.push_back(item);
160-
}
161-
162-
SESSION_PROTOCOL_PRO_EXTRA_FEATURES flags = 0;
163-
for (std::string& feature : proFeatures) {
164-
// Note: 10K_CHARACTER_LIMIT cannot be requested by the caller
165-
if (feature == "PRO_BADGE") {
166-
flags |= SESSION_PROTOCOL_PRO_EXTRA_FEATURES_PRO_BADGE;
167-
} else if (feature == "ANIMATED_AVATAR") {
168-
flags |= SESSION_PROTOCOL_PRO_EXTRA_FEATURES_ANIMATED_AVATAR;
169-
}
170-
}
151+
assertIsBigint(
152+
first.Get("proFeaturesBitset"), "proFeaturesForMessage.proFeaturesBitset");
153+
154+
auto lossless = true;
155+
SESSION_PROTOCOL_PRO_FEATURES flags =
156+
first.Get("proFeaturesBitset").As<Napi::BigInt>().Uint64Value(&lossless);
157+
171158
assertIsString(first.Get("utf16"), "proFeaturesForMessage.utf16");
172159
std::u16string utf16 = first.Get("utf16").As<Napi::String>().Utf16Value();
173160
auto pro_features_msg =
@@ -179,7 +166,7 @@ class ProWrapper : public Napi::ObjectWrap<ProWrapper> {
179166
obj["error"] =
180167
pro_features_msg.error.size() ? toJs(env, pro_features_msg.error) : env.Null();
181168
obj["codepointCount"] = toJs(env, pro_features_msg.codepoint_count);
182-
obj["proFeatures"] = proFeaturesToJs(env, pro_features_msg.features);
169+
obj["proFeaturesBitset"] = proFeaturesToJsBitset(env, pro_features_msg.features);
183170

184171
return obj;
185172
});
@@ -355,11 +342,12 @@ class ProWrapper : public Napi::ObjectWrap<ProWrapper> {
355342
auto master_privkey =
356343
toCppString(master_privkey_js, "proStatusRequestBody.masterPrivKeyHex");
357344

358-
assert_length(master_privkey, 64, "proStatusRequestBody.masterPrivKeyHex");
345+
auto master_privkey_decoded = from_hex(master_privkey);
346+
assert_length(master_privkey_decoded, 64, "proStatusRequestBody.masterPrivKeyHex");
359347

360348
auto json = pro_backend::GetProStatusRequest::build_to_json(
361349
static_cast<uint8_t>(requestVersion.Int32Value()),
362-
to_span(from_hex(master_privkey)),
350+
to_span(master_privkey_decoded),
363351
unix_ts_ms,
364352
withPaymentHistory);
365353

include/pro/types.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ struct toJs_impl<session::DecodedPro> {
7777
: decoded_pro.status == ProStatus::Valid ? "Valid"
7878
: "Expired");
7979
obj["proProof"] = toJs(env, decoded_pro.proof);
80-
obj["proFeatures"] = proFeaturesToJs(env, decoded_pro.features);
80+
obj["proFeaturesBitset"] = proFeaturesToJsBitset(env, decoded_pro.features);
8181

8282
return obj;
8383
}

include/user_config.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,7 @@ class UserConfigWrapper : public ConfigBaseImpl, public Napi::ObjectWrap<UserCon
3838
Napi::Value getProConfig(const Napi::CallbackInfo& info);
3939
void setProConfig(const Napi::CallbackInfo& info);
4040
Napi::Value generateProMasterKey(const Napi::CallbackInfo& info);
41+
Napi::Value generateRotatingPrivKeyHex(const Napi::CallbackInfo& info);
42+
4143
};
4244
}; // namespace session::nodeapi

include/utilities.hpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ void assertInfoMinLength(const Napi::CallbackInfo& info, const int minLength);
4343

4444
void assertIsStringOrNull(const Napi::Value& value, const std::string& identifier = "");
4545
void assertIsNumber(const Napi::Value& value, const std::string& identifier);
46+
void assertIsBigint(const Napi::Value& val, const std::string& identifier);
4647
void assertIsArray(const Napi::Value& value, const std::string& identifier);
4748
void assertIsObject(const Napi::Value& value);
4849
void assertIsUInt8ArrayOrNull(const Napi::Value& value);
@@ -394,7 +395,8 @@ Napi::Object decrypt_result_to_JS(
394395

395396
confirm_pushed_entry_t confirm_pushed_entry_from_JS(const Napi::Env& env, const Napi::Object& obj);
396397

397-
Napi::Object proFeaturesToJs(const Napi::Env& env, const SESSION_PROTOCOL_PRO_FEATURES bitset);
398+
Napi::BigInt proFeaturesToJsBitset(
399+
const Napi::Env& env, const SESSION_PROTOCOL_PRO_FEATURES bitset);
398400

399401
std::span<const uint8_t> from_hex_to_span(std::string_view x);
400402

@@ -405,10 +407,11 @@ template <std::size_t N>
405407
std::array<uint8_t, N> from_hex_to_array(std::string x) {
406408
std::string as_hex = oxenc::from_hex(x);
407409
if (as_hex.size() != N) {
408-
throw std::invalid_argument(fmt::format(
409-
"from_hex_to_array: Decoded hex size mismatch: expected {}, got {}",
410-
N,
411-
as_hex.size()));
410+
throw std::invalid_argument(
411+
fmt::format(
412+
"from_hex_to_array: Decoded hex size mismatch: expected {}, got {}",
413+
N,
414+
as_hex.size()));
412415
}
413416

414417
std::array<uint8_t, N> result;
@@ -424,16 +427,15 @@ std::vector<unsigned char> from_base64_to_vector(std::string_view x);
424427
// Concept to match containers with a size() method
425428
template <typename T>
426429
concept HasSize = requires(T t) {
427-
{
428-
t.size()
429-
} -> std::convertible_to<size_t>;
430+
{t.size()}->std::convertible_to<size_t>;
430431
};
431432

432433
template <HasSize T>
433434
void assert_length(const T& x, size_t n, std::string_view base_identifier) {
434435
if (x.size() != n) {
435-
throw std::invalid_argument(fmt::format(
436-
"assert_length: expected {}, got {} for {}", n, x.size(), base_identifier));
436+
throw std::invalid_argument(
437+
fmt::format(
438+
"assert_length: expected {}, got {} for {}", n, x.size(), base_identifier));
437439
}
438440
}
439441

src/encrypt_decrypt/encrypt_decrypt.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -636,8 +636,9 @@ Napi::Value MultiEncryptWrapper::decryptForCommunity(const Napi::CallbackInfo& i
636636

637637
auto contentOrEnvelope =
638638
extractContentOrEnvelope(obj, "decryptForCommunity.obj.contentOrEnvelope");
639-
decrypted.push_back(session::decode_for_community(
640-
contentOrEnvelope, nowMs, proBackendPubkeyHex));
639+
decrypted.push_back(
640+
session::decode_for_community(
641+
contentOrEnvelope, nowMs, proBackendPubkeyHex));
641642
decryptedServerIds.push_back(serverId);
642643

643644
} catch (const std::exception& e) {
@@ -654,12 +655,10 @@ Napi::Value MultiEncryptWrapper::decryptForCommunity(const Napi::CallbackInfo& i
654655

655656
for (auto& d : decrypted) {
656657
auto to_insert = Napi::Object::New(info.Env());
657-
std::span<unsigned char> content_plaintext_unpadded =
658-
std::span(d.content_plaintext).subspan(0, d.content_plaintext_unpadded_size);
659658

660659
to_insert.Set(
661660
"envelope", d.envelope ? toJs(info.Env(), *d.envelope) : info.Env().Null());
662-
to_insert.Set("contentPlaintextUnpadded", toJs(info.Env(), content_plaintext_unpadded));
661+
to_insert.Set("contentPlaintextUnpadded", toJs(info.Env(), d.content_plaintext));
663662
to_insert.Set("serverId", toJs(info.Env(), decryptedServerIds[i]));
664663

665664
to_insert.Set(
@@ -732,8 +731,9 @@ Napi::Value MultiEncryptWrapper::decryptFor1o1(const Napi::CallbackInfo& info) {
732731

733732
auto envelopePayload =
734733
extractEnvelopePayload(obj, "decryptFor1o1.obj.envelopePayload");
735-
decrypted.push_back(session::decode_envelope(
736-
keys, envelopePayload, nowMs, proBackendPubkeyHex));
734+
decrypted.push_back(
735+
session::decode_envelope(
736+
keys, envelopePayload, nowMs, proBackendPubkeyHex));
737737
decryptedMessageHashes.push_back(messageHash);
738738
} catch (const std::exception& e) {
739739
log::warning(
@@ -831,8 +831,9 @@ Napi::Value MultiEncryptWrapper::decryptForGroup(const Napi::CallbackInfo& info)
831831

832832
auto envelopePayload =
833833
extractEnvelopePayload(obj, "decryptForGroup.obj.envelopePayload");
834-
decrypted.push_back(session::decode_envelope(
835-
keys, envelopePayload, nowMs, proBackendPubkeyHex));
834+
decrypted.push_back(
835+
session::decode_envelope(
836+
keys, envelopePayload, nowMs, proBackendPubkeyHex));
836837
decryptedMessageHashes.push_back(messageHash);
837838
} catch (const std::exception& e) {
838839
log::warning(

src/user_config.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,11 @@ void UserConfigWrapper::setNoteToSelfExpiry(const Napi::CallbackInfo& info) {
247247

248248
Napi::Value UserConfigWrapper::getProConfig(const Napi::CallbackInfo& info) {
249249
return wrapResult(info, [&] {
250-
auto pro_config = config.get_pro_config();
251-
if (pro_config) {
252-
return toJs(info.Env(), *pro_config);
253-
}
250+
// TODO fixme once extra_data is implemented
251+
// auto pro_config = config.get_pro_config();
252+
// if (pro_config) {
253+
// return toJs(info.Env(), *pro_config);
254+
// }
254255

255256
return info.Env().Null();
256257
});
@@ -264,8 +265,9 @@ void UserConfigWrapper::setProConfig(const Napi::CallbackInfo& info) {
264265

265266
session::config::ProConfig pro_config =
266267
pro_config_from_object(pro_config_js.As<Napi::Object>());
268+
// TODO fixme once extra_data is implemented
267269

268-
config.set_pro_config(pro_config);
270+
// config.set_pro_config(pro_config);
269271
});
270272
}
271273

@@ -283,7 +285,21 @@ Napi::Value UserConfigWrapper::generateProMasterKey(const Napi::CallbackInfo& in
283285

284286
auto pro_master_key_hex = session::ed25519::ed25519_pro_privkey_for_ed25519_seed(converted);
285287
auto obj = Napi::Object::New(info.Env());
286-
obj["proMasterKey"] = toJs(info.Env(), pro_master_key_hex);
288+
obj["proMasterKeyHex"] = toJs(info.Env(), to_hex(pro_master_key_hex));
289+
290+
return obj;
291+
});
292+
}
293+
294+
Napi::Value UserConfigWrapper::generateRotatingPrivKeyHex(const Napi::CallbackInfo& info) {
295+
return wrapResult(info, [&] {
296+
assertInfoLength(info, 0);
297+
auto result = session::ed25519::ed25519_key_pair();
298+
auto [ed_pk, ed_sk] = result;
299+
300+
std::string rotating_privkey_hex = to_hex(ed_sk);
301+
auto obj = Napi::Object::New(info.Env());
302+
obj["rotatingPrivKeyHex"] = toJs(info.Env(), rotating_privkey_hex);
287303

288304
return obj;
289305
});

src/utilities.cpp

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "utilities.hpp"
22

3+
#include <napi.h>
34
#include <oxenc/base64.h>
45
#include <oxenc/hex.h>
56

@@ -22,18 +23,24 @@ void assertInfoMinLength(const Napi::CallbackInfo& info, const int minLength) {
2223
void assertIsStringOrNull(const Napi::Value& val, const std::string& identifier) {
2324
checkOrThrow(
2425
val.IsString() || val.IsNull(),
25-
std::string("Wrong arguments: expected string or null" + identifier).c_str());
26+
std::string("Wrong arguments: expected string or null: " + identifier).c_str());
2627
}
2728

2829
void assertIsNumber(const Napi::Value& val, const std::string& identifier) {
2930
checkOrThrow(
3031
val.IsNumber() && !val.IsEmpty() && !val.IsNull() && !val.IsUndefined(),
31-
std::string("Wrong arguments: expected number" + identifier).c_str());
32+
std::string("Wrong arguments: expected number: " + identifier).c_str());
33+
}
34+
35+
void assertIsBigint(const Napi::Value& val, const std::string& identifier) {
36+
checkOrThrow(
37+
val.IsBigInt() && !val.IsEmpty() && !val.IsNull() && !val.IsUndefined(),
38+
std::string("Wrong arguments: expected bigint: " + identifier).c_str());
3239
}
3340

3441
void assertIsArray(const Napi::Value& val, const std::string& identifier) {
3542
checkOrThrow(
36-
val.IsArray(), std::string("Wrong arguments: expected array:" + identifier).c_str());
43+
val.IsArray(), std::string("Wrong arguments: expected array: " + identifier).c_str());
3744
}
3845

3946
void assertIsObject(const Napi::Value& val) {
@@ -345,28 +352,10 @@ confirm_pushed_entry_t confirm_pushed_entry_from_JS(const Napi::Env& env, const
345352
return confirmed_pushed_entry;
346353
}
347354

348-
Napi::Object proFeaturesToJs(const Napi::Env& env, const SESSION_PROTOCOL_PRO_FEATURES bitset) {
349-
Napi::Array arr = Napi::Array::New(env);
350-
uint32_t index = 0;
351-
352-
if (bitset == SESSION_PROTOCOL_PRO_FEATURES_NIL) {
353-
return arr;
354-
}
355-
356-
if (bitset & (SESSION_PROTOCOL_PRO_FEATURES_10K_CHARACTER_LIMIT)) {
357-
arr[index] = Napi::String::New(env, "10K_CHARACTER_LIMIT");
358-
index++;
359-
}
360-
if (bitset & SESSION_PROTOCOL_PRO_FEATURES_PRO_BADGE) {
361-
arr[index++] = Napi::String::New(env, "PRO_BADGE");
362-
index++;
363-
}
364-
if (bitset & SESSION_PROTOCOL_PRO_FEATURES_ANIMATED_AVATAR) {
365-
arr[index++] = Napi::String::New(env, "ANIMATED_AVATAR");
366-
index++;
367-
}
368-
369-
return arr;
355+
Napi::BigInt proFeaturesToJsBitset(
356+
const Napi::Env& env, const SESSION_PROTOCOL_PRO_FEATURES bitset) {
357+
// 2^53 should be enough for now. If we do need more we can use a bigint
358+
return Napi::BigInt::New(env, bitset);
370359
}
371360

372361
std::span<const uint8_t> from_hex_to_span(std::string_view x) {

types/multi_encrypt/multi_encrypt.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ declare module 'libsession_util_nodejs' {
5353
};
5454
type WithNowMs = { nowMs: number };
5555

56-
type DecodedPro = WithProFeatures & {
56+
type DecodedPro = WithProFeaturesBitset & {
5757
proStatus: ProStatus;
5858
proProof: ProProof;
5959
};

0 commit comments

Comments
 (0)