diff --git a/include/pro/pro.hpp b/include/pro/pro.hpp index 8859e39..b245436 100644 --- a/include/pro/pro.hpp +++ b/include/pro/pro.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -110,22 +111,6 @@ class ProWrapper : public Napi::ObjectWrap { "proStatusRequestBody", static_cast( napi_writable | napi_configurable)), - - // Note: those are not plugged in for now as we do this parsing through zod - // on desktop. - // Pro responses parsing - // StaticMethod<&ProWrapper::proProofParseResponse>( - // "proProofParseResponse", - // static_cast( - // napi_writable | napi_configurable)), - // StaticMethod<&ProWrapper::proRevocationsParseResponse>( - // "proRevocationsParseResponse", - // static_cast( - // napi_writable | napi_configurable)), - // StaticMethod<&ProWrapper::proStatusParseResponse>( - // "proStatusParseResponse", - // static_cast( - // napi_writable | napi_configurable)), }); } @@ -135,7 +120,7 @@ class ProWrapper : public Napi::ObjectWrap { // we expect two arguments that match: // first: { // "utf16": string, - // "proFeatures": Array, + // "proFeaturesBitset": bigint, // } assertInfoLength(info, 1); @@ -147,27 +132,13 @@ class ProWrapper : public Napi::ObjectWrap { if (first.IsEmpty()) throw std::invalid_argument("proFeaturesForMessage first received empty"); - assertIsArray(first.Get("proFeatures"), "proFeaturesForMessage.proFeatures"); - auto proFeaturesJS = first.Get("proFeatures").As(); - std::vector proFeatures; - proFeatures.reserve(proFeaturesJS.Length()); - for (uint32_t i = 0; i < proFeaturesJS.Length(); i++) { - auto itemValue = proFeaturesJS.Get(i); - assertIsString(itemValue, "proFeaturesForMessage.proFeatures.itemValue"); - std::string item = - toCppString(itemValue, "proFeaturesForMessage.proFeatures.itemValue"); - proFeatures.push_back(item); - } - - SESSION_PROTOCOL_PRO_EXTRA_FEATURES flags = 0; - for (std::string& feature : proFeatures) { - // Note: 10K_CHARACTER_LIMIT cannot be requested by the caller - if (feature == "PRO_BADGE") { - flags |= SESSION_PROTOCOL_PRO_EXTRA_FEATURES_PRO_BADGE; - } else if (feature == "ANIMATED_AVATAR") { - flags |= SESSION_PROTOCOL_PRO_EXTRA_FEATURES_ANIMATED_AVATAR; - } - } + assertIsBigint( + first.Get("proFeaturesBitset"), "proFeaturesForMessage.proFeaturesBitset"); + + auto lossless = true; + SESSION_PROTOCOL_PRO_FEATURES flags = + first.Get("proFeaturesBitset").As().Uint64Value(&lossless); + assertIsString(first.Get("utf16"), "proFeaturesForMessage.utf16"); std::u16string utf16 = first.Get("utf16").As().Utf16Value(); auto pro_features_msg = @@ -179,7 +150,7 @@ class ProWrapper : public Napi::ObjectWrap { obj["error"] = pro_features_msg.error.size() ? toJs(env, pro_features_msg.error) : env.Null(); obj["codepointCount"] = toJs(env, pro_features_msg.codepoint_count); - obj["proFeatures"] = proFeaturesToJs(env, pro_features_msg.features); + obj["proFeaturesBitset"] = proFeaturesToJsBitset(env, pro_features_msg.features); return obj; }); @@ -219,9 +190,6 @@ class ProWrapper : public Napi::ObjectWrap { std::string rotating_privkey = toCppString(rotating_privkey_js, "proProofRequestBody.rotatingPrivKeyHex"); - assert_length(master_privkey, 64, "masterPrivKeyHex"); - assert_length(rotating_privkey, 64, "rotatingPrivkey"); - auto master_privkey_decoded = from_hex(master_privkey); auto rotating_privkey_decoded = from_hex(rotating_privkey); @@ -235,33 +203,6 @@ class ProWrapper : public Napi::ObjectWrap { }); }; - static Napi::Value proProofParseResponse(const Napi::CallbackInfo& info) { - return wrapResult(info, [&] { - // we expect arguments that match: - // first: { - // "json": string, - // } - - assertInfoLength(info, 1); - assertIsObject(info[0]); - auto env = info.Env(); - - auto first = info[0].As(); - - if (first.IsEmpty()) - throw std::invalid_argument("proProofParseResponse first received empty"); - - assertIsString(first.Get("json"), "proProofParseResponse.json"); - auto json_str = toCppString(first.Get("json"), "proProofParseResponse.json"); - auto parsed = pro_backend::AddProPaymentOrGetProProofResponse::parse(json_str); - - auto obj = toJs(env, static_cast(parsed)); - obj["proof"] = toJsOrNullIfErrors(env, parsed.proof, parsed.errors); - - return obj; - }); - }; - static Napi::Value proRevocationsRequestBody(const Napi::CallbackInfo& info) { return wrapResult(info, [&] { // we expect arguments that match: @@ -293,35 +234,6 @@ class ProWrapper : public Napi::ObjectWrap { }); }; - static Napi::Value proRevocationsParseResponse(const Napi::CallbackInfo& info) { - return wrapResult(info, [&] { - // we expect arguments that match: - // first: { - // "json": string, - // } - - assertInfoLength(info, 1); - assertIsObject(info[0]); - auto env = info.Env(); - - auto first = info[0].As(); - - if (first.IsEmpty()) - throw std::invalid_argument("proRevocationsParseResponse first received empty"); - - assertIsString(first.Get("json"), "proRevocationsParseResponse.json"); - auto json_str = toCppString(first.Get("json"), "proRevocationsParseResponse.json"); - auto parsed = pro_backend::GetProRevocationsResponse::parse(json_str); - - auto obj = toJs(env, static_cast(parsed)); - // if error is set, the body might not be parsable so don't try to use it - obj["ticket"] = parsed.errors.size() ? env.Null() : toJs(env, parsed.ticket); - obj["items"] = parsed.errors.size() ? env.Null() : toJs(env, parsed.items); - - return obj; - }); - }; - static Napi::Value proStatusRequestBody(const Napi::CallbackInfo& info) { return wrapResult(info, [&] { // we expect arguments that match: @@ -355,55 +267,17 @@ class ProWrapper : public Napi::ObjectWrap { auto master_privkey = toCppString(master_privkey_js, "proStatusRequestBody.masterPrivKeyHex"); - assert_length(master_privkey, 64, "proStatusRequestBody.masterPrivKeyHex"); + auto master_privkey_decoded = from_hex(master_privkey); auto json = pro_backend::GetProStatusRequest::build_to_json( static_cast(requestVersion.Int32Value()), - to_span(from_hex(master_privkey)), + to_span(master_privkey_decoded), unix_ts_ms, withPaymentHistory); return json; }); }; - - static Napi::Value proStatusParseResponse(const Napi::CallbackInfo& info) { - return wrapResult(info, [&] { - // we expect arguments that match: - // first: { - // "json": string, - // } - - assertInfoLength(info, 1); - assertIsObject(info[0]); - auto env = info.Env(); - - auto first = info[0].As(); - - if (first.IsEmpty()) - throw std::invalid_argument("proStatusParseResponse first received empty"); - - assertIsString(first.Get("json"), "proStatusParseResponse.json"); - auto json_str = toCppString(first.Get("json"), "proStatusParseResponse.json"); - auto parsed = pro_backend::GetProStatusResponse::parse(json_str); - - auto obj = toJs(env, static_cast(parsed)); - - obj["items"] = toJsOrNullIfErrors(env, parsed.items, parsed.errors); - obj["userStatus"] = toJsOrNullIfErrors( - env, proBackendEnumToString(parsed.user_status), parsed.errors); - - obj["errorReport"] = toJsOrNullIfErrors( - env, proBackendEnumToString(parsed.error_report), parsed.errors); - - obj["autoRenewing"] = toJsOrNullIfErrors(env, parsed.auto_renewing, parsed.errors); - obj["expiryTsMs"] = toJsOrNullIfErrors(env, parsed.expiry_unix_ts_ms, parsed.errors); - obj["gracePeriodMs"] = - toJsOrNullIfErrors(env, parsed.grace_period_duration_ms, parsed.errors); - - return obj; - }); - }; }; }; // namespace session::nodeapi diff --git a/include/pro/types.hpp b/include/pro/types.hpp index a8ce087..e5d4091 100644 --- a/include/pro/types.hpp +++ b/include/pro/types.hpp @@ -19,6 +19,7 @@ struct toJs_impl { obj["genIndexHashB64"] = toJs(env, oxenc::to_base64(pro_proof.gen_index_hash)); obj["rotatingPubkeyHex"] = toJs(env, oxenc::to_hex(pro_proof.rotating_pubkey)); obj["expiryMs"] = toJs(env, pro_proof.expiry_unix_ts.time_since_epoch().count()); + obj["signatureHex"] = toJs(env, oxenc::to_hex(pro_proof.sig)); return obj; } @@ -77,7 +78,7 @@ struct toJs_impl { : decoded_pro.status == ProStatus::Valid ? "Valid" : "Expired"); obj["proProof"] = toJs(env, decoded_pro.proof); - obj["proFeatures"] = proFeaturesToJs(env, decoded_pro.features); + obj["proFeaturesBitset"] = proFeaturesToJsBitset(env, decoded_pro.features); return obj; } diff --git a/include/user_config.hpp b/include/user_config.hpp index ba4ca5d..c61bdb3 100644 --- a/include/user_config.hpp +++ b/include/user_config.hpp @@ -3,6 +3,7 @@ #include #include "base_config.hpp" +#include "session/config/pro.hpp" #include "session/config/user_profile.hpp" #include "utilities.hpp" @@ -15,6 +16,10 @@ class UserConfigWrapper : public ConfigBaseImpl, public Napi::ObjectWrap pro_config; + int64_t pro_user_features = 0; + config::UserProfile& config{get_config()}; Napi::Value getPriority(const Napi::CallbackInfo& info); @@ -37,6 +42,10 @@ class UserConfigWrapper : public ConfigBaseImpl, public Napi::ObjectWrap toCppBufferView(Napi::Value x, const std::string& std::vector toCppBuffer(Napi::Value x, const std::string& identifier); int64_t toCppInteger(Napi::Value x, const std::string& identifier, bool allowUndefined = false); + +/** + * Same as toCppInteger, but for BigInt + */ +int64_t toCppIntegerB(Napi::Value x, const std::string& identifier, bool allowUndefined = false); + std::optional maybeNonemptyInt(Napi::Value x, const std::string& identifier); std::optional maybeNonemptyBoolean(Napi::Value x, const std::string& identifier); std::optional maybeNonemptySysSeconds( @@ -394,7 +401,8 @@ Napi::Object decrypt_result_to_JS( confirm_pushed_entry_t confirm_pushed_entry_from_JS(const Napi::Env& env, const Napi::Object& obj); -Napi::Object proFeaturesToJs(const Napi::Env& env, const SESSION_PROTOCOL_PRO_FEATURES bitset); +Napi::BigInt proFeaturesToJsBitset( + const Napi::Env& env, const SESSION_PROTOCOL_PRO_FEATURES bitset); std::span from_hex_to_span(std::string_view x); @@ -405,10 +413,11 @@ template std::array from_hex_to_array(std::string x) { std::string as_hex = oxenc::from_hex(x); if (as_hex.size() != N) { - throw std::invalid_argument(fmt::format( - "from_hex_to_array: Decoded hex size mismatch: expected {}, got {}", - N, - as_hex.size())); + throw std::invalid_argument( + fmt::format( + "from_hex_to_array: Decoded hex size mismatch: expected {}, got {}", + N, + as_hex.size())); } std::array result; @@ -424,16 +433,15 @@ std::vector from_base64_to_vector(std::string_view x); // Concept to match containers with a size() method template concept HasSize = requires(T t) { - { - t.size() - } -> std::convertible_to; + {t.size()}->std::convertible_to; }; template void assert_length(const T& x, size_t n, std::string_view base_identifier) { if (x.size() != n) { - throw std::invalid_argument(fmt::format( - "assert_length: expected {}, got {} for {}", n, x.size(), base_identifier)); + throw std::invalid_argument( + fmt::format( + "assert_length: expected {}, got {} for {}", n, x.size(), base_identifier)); } } diff --git a/libsession-util b/libsession-util index 32bda61..0fd3d5c 160000 --- a/libsession-util +++ b/libsession-util @@ -1 +1 @@ -Subproject commit 32bda61d0a108841c773a02271ad8dd377eba3c7 +Subproject commit 0fd3d5cc07704b375f0185c5fb49ad9b5cfb8756 diff --git a/src/encrypt_decrypt/encrypt_decrypt.cpp b/src/encrypt_decrypt/encrypt_decrypt.cpp index 753ee6e..ee5860f 100644 --- a/src/encrypt_decrypt/encrypt_decrypt.cpp +++ b/src/encrypt_decrypt/encrypt_decrypt.cpp @@ -95,10 +95,10 @@ std::optional> extractProRotatingEd25519PrivKeyAsVect maybeNonemptyString(obj.Get("proRotatingEd25519PrivKey"), identifier); if (proRotatingEd25519PrivKeyHex.has_value() && proRotatingEd25519PrivKeyHex.value().size()) { - assert_length(*proRotatingEd25519PrivKeyHex, 64, identifier); auto ret = from_hex_to_vector(*proRotatingEd25519PrivKeyHex); + assert_length(ret, 64, identifier); return ret; } @@ -636,8 +636,9 @@ Napi::Value MultiEncryptWrapper::decryptForCommunity(const Napi::CallbackInfo& i auto contentOrEnvelope = extractContentOrEnvelope(obj, "decryptForCommunity.obj.contentOrEnvelope"); - decrypted.push_back(session::decode_for_community( - contentOrEnvelope, nowMs, proBackendPubkeyHex)); + decrypted.push_back( + session::decode_for_community( + contentOrEnvelope, nowMs, proBackendPubkeyHex)); decryptedServerIds.push_back(serverId); } catch (const std::exception& e) { @@ -654,12 +655,10 @@ Napi::Value MultiEncryptWrapper::decryptForCommunity(const Napi::CallbackInfo& i for (auto& d : decrypted) { auto to_insert = Napi::Object::New(info.Env()); - std::span content_plaintext_unpadded = - std::span(d.content_plaintext).subspan(0, d.content_plaintext_unpadded_size); to_insert.Set( "envelope", d.envelope ? toJs(info.Env(), *d.envelope) : info.Env().Null()); - to_insert.Set("contentPlaintextUnpadded", toJs(info.Env(), content_plaintext_unpadded)); + to_insert.Set("contentPlaintextUnpadded", toJs(info.Env(), d.content_plaintext)); to_insert.Set("serverId", toJs(info.Env(), decryptedServerIds[i])); to_insert.Set( @@ -732,8 +731,9 @@ Napi::Value MultiEncryptWrapper::decryptFor1o1(const Napi::CallbackInfo& info) { auto envelopePayload = extractEnvelopePayload(obj, "decryptFor1o1.obj.envelopePayload"); - decrypted.push_back(session::decode_envelope( - keys, envelopePayload, nowMs, proBackendPubkeyHex)); + decrypted.push_back( + session::decode_envelope( + keys, envelopePayload, nowMs, proBackendPubkeyHex)); decryptedMessageHashes.push_back(messageHash); } catch (const std::exception& e) { log::warning( @@ -831,8 +831,9 @@ Napi::Value MultiEncryptWrapper::decryptForGroup(const Napi::CallbackInfo& info) auto envelopePayload = extractEnvelopePayload(obj, "decryptForGroup.obj.envelopePayload"); - decrypted.push_back(session::decode_envelope( - keys, envelopePayload, nowMs, proBackendPubkeyHex)); + decrypted.push_back( + session::decode_envelope( + keys, envelopePayload, nowMs, proBackendPubkeyHex)); decryptedMessageHashes.push_back(messageHash); } catch (const std::exception& e) { log::warning( diff --git a/src/user_config.cpp b/src/user_config.cpp index aafe90b..bba19ad 100644 --- a/src/user_config.cpp +++ b/src/user_config.cpp @@ -1,5 +1,7 @@ #include "user_config.hpp" +#include + #include #include "base_config.hpp" @@ -10,6 +12,7 @@ #include "session/config/base.hpp" #include "session/config/user_profile.hpp" #include "session/ed25519.hpp" +#include "utilities.hpp" namespace session::nodeapi { @@ -59,6 +62,15 @@ session::config::ProConfig pro_config_from_object(Napi::Object input) { rotating_pubkey_cpp.end(), pro_config.proof.rotating_pubkey.begin()); + // extract backend signature + auto signature_hex_js = proof_js.Get("signatureHex"); + assertIsString(signature_hex_js, "pro_config_from_object.signature_hex_js"); + auto signature_hex_cpp = + toCppString(signature_hex_js, "pro_config_from_object.signature_hex_js"); + auto signature_cpp = from_hex_to_vector(signature_hex_cpp); + std::copy(signature_cpp.begin(), signature_cpp.end(), pro_config.proof.sig.begin()); + assert_length(signature_cpp, 64, "pro_config_from_object.signature_cpp"); + // extract expiryMs assertIsNumber(proof_js.Get("expiryMs"), "pro_config_from_object.expiryMs"); pro_config.proof.expiry_unix_ts = @@ -95,8 +107,15 @@ void UserConfigWrapper::Init(Napi::Env env, Napi::Object exports) { InstanceMethod("setNoteToSelfExpiry", &UserConfigWrapper::setNoteToSelfExpiry), InstanceMethod("getProConfig", &UserConfigWrapper::getProConfig), InstanceMethod("setProConfig", &UserConfigWrapper::setProConfig), + InstanceMethod( + "setProFeaturesBitset", &UserConfigWrapper::setProFeaturesBitset), + InstanceMethod( + "getProFeaturesBitset", &UserConfigWrapper::getProFeaturesBitset), InstanceMethod( "generateProMasterKey", &UserConfigWrapper::generateProMasterKey), + InstanceMethod( + "generateRotatingPrivKeyHex", + &UserConfigWrapper::generateRotatingPrivKeyHex), }); } @@ -247,9 +266,11 @@ void UserConfigWrapper::setNoteToSelfExpiry(const Napi::CallbackInfo& info) { Napi::Value UserConfigWrapper::getProConfig(const Napi::CallbackInfo& info) { return wrapResult(info, [&] { - auto pro_config = config.get_pro_config(); - if (pro_config) { - return toJs(info.Env(), *pro_config); + // TODO fixme once extra_data is implemented + + oxen::log::warning(cat, "getProConfig() is not wrapped to libsession"); + if (this->pro_config.has_value()) { + return toJs(info.Env(), this->pro_config); } return info.Env().Null(); @@ -264,8 +285,38 @@ void UserConfigWrapper::setProConfig(const Napi::CallbackInfo& info) { session::config::ProConfig pro_config = pro_config_from_object(pro_config_js.As()); + // TODO fixme once extra_data is implemented + + // config.set_pro_config(pro_config); + this->pro_config = pro_config; + }); +} + +Napi::Value UserConfigWrapper::getProFeaturesBitset(const Napi::CallbackInfo& info) { + return wrapResult(info, [&] { + // TODO fixme once extra_data is implemented + // config.get_pro_features_bitset(); + oxen::log::warning(cat, "getProFeaturesBitset() is not wrapped to libsession"); + return toJs(info.Env(), this->pro_user_features); + }); +} - config.set_pro_config(pro_config); +void UserConfigWrapper::setProFeaturesBitset(const Napi::CallbackInfo& info) { + wrapExceptions(info, [&] { + assertInfoLength(info, 1); + auto pro_features = info[0]; + assertIsObject(info[0]); + auto obj = info[0].As(); + assertIsBigint(obj.Get("proFeaturesBitset"), "UserConfigWrapper::setProFeaturesBitset"); + + auto pro_user_features_js = obj.Get("proFeaturesBitset"); + auto pro_user_features_cpp = toCppIntegerB( + pro_user_features_js, "UserConfigWrapper::setProFeaturesBitset", false); + + // TODO fixme once extra_data is implemented + + // config.set_pro_features_bitset(pro_user_features_cpp); + this->pro_user_features = pro_user_features_cpp; }); } @@ -283,7 +334,21 @@ Napi::Value UserConfigWrapper::generateProMasterKey(const Napi::CallbackInfo& in auto pro_master_key_hex = session::ed25519::ed25519_pro_privkey_for_ed25519_seed(converted); auto obj = Napi::Object::New(info.Env()); - obj["proMasterKey"] = toJs(info.Env(), pro_master_key_hex); + obj["proMasterKeyHex"] = toJs(info.Env(), to_hex(pro_master_key_hex)); + + return obj; + }); +} + +Napi::Value UserConfigWrapper::generateRotatingPrivKeyHex(const Napi::CallbackInfo& info) { + return wrapResult(info, [&] { + assertInfoLength(info, 0); + auto result = session::ed25519::ed25519_key_pair(); + auto [ed_pk, ed_sk] = result; + + std::string rotating_privkey_hex = to_hex(ed_sk); + auto obj = Napi::Object::New(info.Env()); + obj["rotatingPrivKeyHex"] = toJs(info.Env(), rotating_privkey_hex); return obj; }); diff --git a/src/utilities.cpp b/src/utilities.cpp index d81cb20..ae8abaa 100644 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -1,5 +1,6 @@ #include "utilities.hpp" +#include #include #include @@ -22,18 +23,24 @@ void assertInfoMinLength(const Napi::CallbackInfo& info, const int minLength) { void assertIsStringOrNull(const Napi::Value& val, const std::string& identifier) { checkOrThrow( val.IsString() || val.IsNull(), - std::string("Wrong arguments: expected string or null" + identifier).c_str()); + std::string("Wrong arguments: expected string or null: " + identifier).c_str()); } void assertIsNumber(const Napi::Value& val, const std::string& identifier) { checkOrThrow( val.IsNumber() && !val.IsEmpty() && !val.IsNull() && !val.IsUndefined(), - std::string("Wrong arguments: expected number" + identifier).c_str()); + std::string("Wrong arguments: expected number: " + identifier).c_str()); +} + +void assertIsBigint(const Napi::Value& val, const std::string& identifier) { + checkOrThrow( + val.IsBigInt() && !val.IsEmpty() && !val.IsNull() && !val.IsUndefined(), + std::string("Wrong arguments: expected bigint: " + identifier).c_str()); } void assertIsArray(const Napi::Value& val, const std::string& identifier) { checkOrThrow( - val.IsArray(), std::string("Wrong arguments: expected array:" + identifier).c_str()); + val.IsArray(), std::string("Wrong arguments: expected array: " + identifier).c_str()); } void assertIsObject(const Napi::Value& val) { @@ -134,6 +141,16 @@ int64_t toCppInteger(Napi::Value x, const std::string& identifier, bool allowUnd throw std::invalid_argument{"Unsupported type for "s + identifier + ": expected a number"}; } +int64_t toCppIntegerB(Napi::Value x, const std::string& identifier, bool allowUndefined) { + auto lossless = true; + if (allowUndefined && (x.IsNull() || x.IsUndefined())) + return 0; + if (x.IsBigInt()) + return x.As().Int64Value(&lossless); + + throw std::invalid_argument{"Unsupported type for "s + identifier + ": expected a bigint"}; +} + std::optional maybeNonemptyInt(Napi::Value x, const std::string& identifier) { if (x.IsNull() || x.IsUndefined()) return std::nullopt; @@ -345,28 +362,9 @@ confirm_pushed_entry_t confirm_pushed_entry_from_JS(const Napi::Env& env, const return confirmed_pushed_entry; } -Napi::Object proFeaturesToJs(const Napi::Env& env, const SESSION_PROTOCOL_PRO_FEATURES bitset) { - Napi::Array arr = Napi::Array::New(env); - uint32_t index = 0; - - if (bitset == SESSION_PROTOCOL_PRO_FEATURES_NIL) { - return arr; - } - - if (bitset & (SESSION_PROTOCOL_PRO_FEATURES_10K_CHARACTER_LIMIT)) { - arr[index] = Napi::String::New(env, "10K_CHARACTER_LIMIT"); - index++; - } - if (bitset & SESSION_PROTOCOL_PRO_FEATURES_PRO_BADGE) { - arr[index++] = Napi::String::New(env, "PRO_BADGE"); - index++; - } - if (bitset & SESSION_PROTOCOL_PRO_FEATURES_ANIMATED_AVATAR) { - arr[index++] = Napi::String::New(env, "ANIMATED_AVATAR"); - index++; - } - - return arr; +Napi::BigInt proFeaturesToJsBitset( + const Napi::Env& env, const SESSION_PROTOCOL_PRO_FEATURES bitset) { + return Napi::BigInt::New(env, bitset); } std::span from_hex_to_span(std::string_view x) { diff --git a/types/multi_encrypt/multi_encrypt.d.ts b/types/multi_encrypt/multi_encrypt.d.ts index 6f489eb..aa791cb 100644 --- a/types/multi_encrypt/multi_encrypt.d.ts +++ b/types/multi_encrypt/multi_encrypt.d.ts @@ -53,7 +53,7 @@ declare module 'libsession_util_nodejs' { }; type WithNowMs = { nowMs: number }; - type DecodedPro = WithProFeatures & { + type DecodedPro = WithProFeaturesBitset & { proStatus: ProStatus; proProof: ProProof; }; diff --git a/types/pro/pro.d.ts b/types/pro/pro.d.ts index ac256d3..30790a2 100644 --- a/types/pro/pro.d.ts +++ b/types/pro/pro.d.ts @@ -11,12 +11,11 @@ declare module 'libsession_util_nodejs' { }; type ProStatus = 'InvalidProBackendSig' | 'InvalidUserSig' | 'Valid' | 'Expired'; - type ProFeature = '10K_CHARACTER_LIMIT' | 'PRO_BADGE' | 'ANIMATED_AVATAR'; - type ProFeatures = Array; - type WithProFeatures = { proFeatures: ProFeatures }; + type WithProFeaturesBitset = { proFeaturesBitset: bigint }; type WithGenIndexHash = { genIndexHashB64: string }; type WithRequestVersion = { requestVersion: number }; + type WithTicket = { ticket: number }; type WithUnixTsMs = { unixTsMs: number; @@ -29,6 +28,11 @@ declare module 'libsession_util_nodejs' { */ rotatingPubkeyHex: string; expiryMs: number; + /** + * signature of the pro proof provided by the backend (hex) + * 64 bytes, 128 chars + */ + signatureHex: string; }; type WithRotatingPrivKeyHex = { @@ -38,15 +42,11 @@ declare module 'libsession_util_nodejs' { rotatingPrivKeyHex: string; }; + type ProConfig = WithRotatingPrivKeyHex & { proProof: ProProof; }; - // type WithProBackendResponse = { - // status: number; - // errors: Array; - // }; - export type ProOriginatingPlatform = 'Nil' | 'Google' | 'iOS'; export type ProBackendProviderConstantType = { @@ -158,36 +158,24 @@ declare module 'libsession_util_nodejs' { }; type ProWrapper = { - proFeaturesForMessage: (args: { - utf16: string; - /** - * If the utf16 requires 10K_CHARACTER_LIMIT to be set, it will be set in the return. - * If provided (here) as an input, it will be ignored. - */ - proFeatures: ProFeatures; - }) => WithProFeatures & { + proFeaturesForMessage: ( + args: WithProFeaturesBitset & { + utf16: string; + } + ) => WithProFeaturesBitset & { status: 'SUCCESS' | 'UTF_DECODING_ERROR' | 'EXCEEDS_CHARACTER_LIMIT'; }; proProofRequestBody: ( args: WithMasterPrivKeyHex & WithRequestVersion & WithUnixTsMs & WithRotatingPrivKeyHex ) => string; - // proProofParseResponse: (args: { - // json: string; - // }) => WithProBackendResponse & { proof: ProProof | null }; - /** * @param version: Request version. The latest accepted version is 0 * @param ticket: 4-byte monotonic integer for the caller's revocation list iteration. Set to 0 if unknown; otherwise, use the latest known `ticket` from a prior `GetProRevocationsResponse` to allow the Session Pro Backend to omit the revocation list if it has not changed. * @returns the stringified body to include in the request */ - proRevocationsRequestBody: (args: WithRequestVersion & { ticket: number }) => string; - - // proRevocationsParseResponse: (args: { json: string }) => WithProBackendResponse & { - // ticket: number | null; - // items: Array | null; - // }; + proRevocationsRequestBody: (args: WithRequestVersion & WithTicket) => string; proStatusRequestBody: ( args: WithMasterPrivKeyHex & @@ -196,16 +184,6 @@ declare module 'libsession_util_nodejs' { withPaymentHistory: boolean; } ) => string; - - // proStatusParseResponse: (args: { json: string }) => WithProBackendResponse & { - // ticket: number | null; - // items: Array; - // userStatus: number; - // errorReport: number; - // autoRenewing: boolean; - // expiryUnixTsMs: number; - // gracePeriodDurationMs: number; - // }; }; export type ProActionsCalls = MakeWrapperActionCalls; @@ -218,9 +196,6 @@ declare module 'libsession_util_nodejs' { public static proProofRequestBody: ProWrapper['proProofRequestBody']; public static proRevocationsRequestBody: ProWrapper['proRevocationsRequestBody']; public static proStatusRequestBody: ProWrapper['proStatusRequestBody']; - // public static proProofParseResponse: ProWrapper['proProofParseResponse']; - // public static proRevocationsParseResponse: ProWrapper['proRevocationsParseResponse']; - // public static proStatusParseResponse: ProWrapper['proStatusParseResponse']; } /** @@ -233,7 +208,4 @@ declare module 'libsession_util_nodejs' { | MakeActionCall | MakeActionCall | MakeActionCall; - // | MakeActionCall - // | MakeActionCall - // | MakeActionCall } diff --git a/types/user/userconfig.d.ts b/types/user/userconfig.d.ts index 0070557..3cfbd40 100644 --- a/types/user/userconfig.d.ts +++ b/types/user/userconfig.d.ts @@ -40,6 +40,14 @@ declare module 'libsession_util_nodejs' { setProConfig: (proConfig: ProConfig) => void; getProConfig: () => ProConfig | null; + + setProFeaturesBitset: (args: WithProFeaturesBitset) => void; + /** + * + * @returns 0 if no pro user features are enabled, the bitset of pro features enabled otherwise + */ + getProFeaturesBitset: () => bigint; + generateProMasterKey: ({ ed25519SeedHex, }: { @@ -49,10 +57,16 @@ declare module 'libsession_util_nodejs' { ed25519SeedHex: string; }) => { /** - * 64 bytes + * 64 bytes, 128 chars */ - proMasterKey: Uint8Array; + proMasterKeyHex: string; }; + + /** + * Generates a new rotating private key for the user. + * Note: this should only be done once per device, and saved to the DB or the extra_data of `UserProfile`. + */ + generateRotatingPrivKeyHex: () => WithRotatingPrivKeyHex; }; export type UserConfigWrapperActionsCalls = MakeWrapperActionCalls; @@ -77,7 +91,10 @@ declare module 'libsession_util_nodejs' { public setNoteToSelfExpiry: UserConfigWrapper['setNoteToSelfExpiry']; public getProConfig: UserConfigWrapper['getProConfig']; public setProConfig: UserConfigWrapper['setProConfig']; + public getProFeaturesBitset: UserConfigWrapper['getProFeaturesBitset']; + public setProFeaturesBitset: UserConfigWrapper['setProFeaturesBitset']; public generateProMasterKey: UserConfigWrapper['generateProMasterKey']; + public generateRotatingPrivKeyHex: UserConfigWrapper['generateRotatingPrivKeyHex']; } /** @@ -103,5 +120,8 @@ declare module 'libsession_util_nodejs' { | MakeActionCall | MakeActionCall | MakeActionCall - | MakeActionCall; + | MakeActionCall + | MakeActionCall + | MakeActionCall + | MakeActionCall; }