Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions include/groups/meta_group_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ class MetaGroupWrapper : public Napi::ObjectWrap<MetaGroupWrapper> {
Napi::Value memberGetOrConstruct(const Napi::CallbackInfo& info);
Napi::Value memberConstructAndSet(const Napi::CallbackInfo& info);

void memberSetNameTruncated(const Napi::CallbackInfo& info);
void memberSetInviteFailed(const Napi::CallbackInfo& info);
void memberSetInviteSent(const Napi::CallbackInfo& info);
void memberSetInviteNotSent(const Napi::CallbackInfo& info);
Expand All @@ -71,7 +70,7 @@ class MetaGroupWrapper : public Napi::ObjectWrap<MetaGroupWrapper> {
void memberSetPromotionSent(const Napi::CallbackInfo& info);
void memberSetPromotionFailed(const Napi::CallbackInfo& info);
void memberSetPromotionAccepted(const Napi::CallbackInfo& info);
void memberSetProfilePicture(const Napi::CallbackInfo& info);
void memberSetProfileDetails(const Napi::CallbackInfo& info);
Napi::Value memberResetAllSendingState(const Napi::CallbackInfo& info);
void memberSetSupplement(const Napi::CallbackInfo& info);
Napi::Value memberEraseAndRekey(const Napi::CallbackInfo& info);
Expand Down
16 changes: 0 additions & 16 deletions include/profile_pic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,6 @@

namespace session::nodeapi {

// Returns {"url": "...", "key": buffer} object; both values will be Null if the pic is not set.

template <>
struct toJs_impl<config::profile_pic> {
Napi::Object operator()(const Napi::Env& env, const config::profile_pic& pic) {
auto obj = Napi::Object::New(env);
if (pic) {
obj["url"] = toJs(env, pic.url);
obj["key"] = toJs(env, pic.key);
} else {
obj["url"] = env.Null();
obj["key"] = env.Null();
}
return obj;
}
};

// Constructs a profile_pic from a Napi::Value which must be either Null or an Object; if an
// Object then it *must* contain "url" (string or null) and "key" (uint8array of size 32 or
Expand Down
7 changes: 6 additions & 1 deletion include/user_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,15 @@ class UserConfigWrapper : public ConfigBaseImpl, public Napi::ObjectWrap<UserCon
Napi::Value getPriority(const Napi::CallbackInfo& info);
Napi::Value getName(const Napi::CallbackInfo& info);
Napi::Value getProfilePic(const Napi::CallbackInfo& info);
Napi::Value getProfilePicWithKeyHex(const Napi::CallbackInfo& info);

void setPriority(const Napi::CallbackInfo& info);
void setName(const Napi::CallbackInfo& info);
void setNameTruncated(const Napi::CallbackInfo& info);
void setProfilePic(const Napi::CallbackInfo& info);
void setNewProfilePic(const Napi::CallbackInfo& info);

void setReuploadProfilePic(const Napi::CallbackInfo& info);
Napi::Value getProfileUpdatedSeconds(const Napi::CallbackInfo& info);

Napi::Value getEnableBlindedMsgRequest(const Napi::CallbackInfo& info);
void setEnableBlindedMsgRequest(const Napi::CallbackInfo& info);
Expand Down
49 changes: 41 additions & 8 deletions include/utilities.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <vector>

#include "session/config/namespaces.hpp"
#include "session/config/profile_pic.hpp"
#include "session/types.hpp"
#include "utilities.hpp"

Expand Down Expand Up @@ -59,20 +60,24 @@ std::vector<unsigned char> toCppBuffer(Napi::Value x, const std::string& identif
int64_t toCppInteger(Napi::Value x, const std::string& identifier, bool allowUndefined = false);
std::optional<int64_t> maybeNonemptyInt(Napi::Value x, const std::string& identifier);
std::optional<bool> maybeNonemptyBoolean(Napi::Value x, const std::string& identifier);
std::optional<std::chrono::sys_seconds> maybeNonemptySysSeconds(
Napi::Value x, const std::string& identifier);

std::chrono::sys_seconds toCppSysSeconds(Napi::Value x, const std::string& identifier);

bool toCppBoolean(Napi::Value x, const std::string& identifier);

// If the object is null/undef/empty returns nullopt, otherwise if a String returns a std::string of
// the value. Throws if something else.
// If the object is null/undef/empty returns nullopt, otherwise if a String returns a
// std::string of the value. Throws if something else.
std::optional<std::string> maybeNonemptyString(Napi::Value x, const std::string& identifier);

// If the object is null/undef/empty returns nullopt, otherwise if a Uint8Array returns a
// std::vector<unsigned char> of the value. Throws if something else.
std::optional<std::vector<unsigned char>> maybeNonemptyBuffer(
Napi::Value x, const std::string& identifier);

// Implementation struct of toJs(); we add specializations of this for any C++ types we want to be
// able to convert into JS types.
// Implementation struct of toJs(); we add specializations of this for any C++ types we want to
// be able to convert into JS types.
template <typename T, typename SFINAE = void>
struct toJs_impl {
// If this gets instantiated it means we're missing a specialization and so fail to compile:
Expand Down Expand Up @@ -176,6 +181,30 @@ struct toJs_impl<std::optional<T>> {
}
};

template <>
struct toJs_impl<std::chrono::sys_seconds> {
auto operator()(const Napi::Env& env, std::chrono::sys_seconds t) const {
return Napi::Number::New(env, t.time_since_epoch().count());
}
};

// Returns {"url": "...", "key": buffer} object; both values will be Null if the pic is not set.

template <>
struct toJs_impl<config::profile_pic> {
auto operator()(const Napi::Env& env, const config::profile_pic& pic) const {
auto obj = Napi::Object::New(env);
if (pic) {
obj["url"] = toJs(env, pic.url);
obj["key"] = toJs(env, pic.key);
} else {
obj["url"] = env.Null();
obj["key"] = env.Null();
}
return obj;
}
};

// Helper for various "get_all" functions that copy [it...end) into a Napi::Array via toJs().
// Throws a Napi::Error on any exception.
template <typename It, typename EndIt>
Expand All @@ -192,8 +221,8 @@ static Napi::Array get_all_impl(const Napi::CallbackInfo& info, size_t size, It
});
}

// Wraps a string in an optional<string_view> which will be nullopt if the input string is empty.
// This is particularly useful with `toJs` to convert empty strings into Null.
// Wraps a string in an optional<string_view> which will be nullopt if the input string is
// empty. This is particularly useful with `toJs` to convert empty strings into Null.
inline std::optional<std::string_view> maybe_string(std::string_view val) {
if (val.empty())
return std::nullopt;
Expand Down Expand Up @@ -231,8 +260,8 @@ auto wrapResult(const Napi::Env& env, Call&& call) {
}
}

// Similar to wrapResult(), but a small shortcut to allow passing `info` instead of `info.Env()` as
// the first argument.
// Similar to wrapResult(), but a small shortcut to allow passing `info` instead of `info.Env()`
// as the first argument.
template <typename Call>
auto wrapResult(const Napi::CallbackInfo& info, Call&& call) {
return wrapResult(info.Env(), std::forward<Call>(call));
Expand Down Expand Up @@ -262,6 +291,10 @@ std::string printable(std::span<const unsigned char> x);
* Keep the current priority if a wrapper
*/
int64_t toPriority(Napi::Value x, int64_t currentPriority);
int64_t toPriority(int64_t newPriority, int64_t currentPriority);

std::optional<session::config::profile_pic> maybeNonemptyProfilePic(
Napi::Value x, const std::string& identifier);

int64_t unix_timestamp_now();

Expand Down
2 changes: 1 addition & 1 deletion libsession-util
Submodule libsession-util updated 43 files
+5 −4 .drone.jsonnet
+1 −1 CMakeLists.txt
+1 −1 external/oxen-libquic
+48 −1 include/session/config/base.hpp
+161 −0 include/session/config/contacts.h
+208 −1 include/session/config/contacts.hpp
+182 −0 include/session/config/convo_info_volatile.h
+97 −7 include/session/config/convo_info_volatile.hpp
+2 −0 include/session/config/encrypt.hpp
+1 −0 include/session/config/groups/members.h
+8 −0 include/session/config/groups/members.hpp
+272 −0 include/session/config/local.h
+215 −0 include/session/config/local.hpp
+4 −0 include/session/config/namespaces.hpp
+7 −0 include/session/config/notify.h
+8 −1 include/session/config/notify.hpp
+20 −0 include/session/config/theme.h
+24 −0 include/session/config/theme.hpp
+36 −2 include/session/config/user_profile.h
+45 −3 include/session/config/user_profile.hpp
+19 −0 include/session/util.hpp
+1 −0 src/CMakeLists.txt
+1 −0 src/config.cpp
+380 −67 src/config/contacts.cpp
+172 −11 src/config/convo_info_volatile.cpp
+2 −1 src/config/groups/keys.cpp
+11 −8 src/config/groups/members.cpp
+65 −0 src/config/internal.cpp
+76 −4 src/config/internal.hpp
+157 −0 src/config/local.cpp
+7 −10 src/config/user_groups.cpp
+126 −62 src/config/user_profile.cpp
+4 −2 src/ed25519.cpp
+47 −21 src/session_network.cpp
+4 −0 src/util.cpp
+1 −0 tests/CMakeLists.txt
+256 −2 tests/test_config_contacts.cpp
+135 −23 tests/test_config_convo_info_volatile.cpp
+74 −0 tests/test_config_local.cpp
+117 −0 tests/test_config_userprofile.cpp
+40 −1 tests/test_group_members.cpp
+5 −4 tests/test_logging.cpp
+65 −70 tests/test_session_network.cpp
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"main": "index.js",
"name": "libsession_util_nodejs",
"description": "Wrappers for the Session Util Library",
"version": "0.5.5",
"version": "0.5.6",
"license": "GPL-3.0",
"author": {
"name": "Oxen Project",
Expand Down
29 changes: 21 additions & 8 deletions src/contacts_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ struct toJs_impl<contact_info> {
obj["nickname"] = toJs(env, maybe_string(contact.nickname));
obj["approved"] = toJs(env, contact.approved);
obj["approvedMe"] = toJs(env, contact.approved_me);
obj["profileUpdatedSeconds"] = toJs(env, contact.profile_updated);
obj["blocked"] = toJs(env, contact.blocked);
obj["priority"] = toJs(env, contact.priority);
obj["createdAtSeconds"] = toJs(env, contact.created);
Expand All @@ -65,6 +66,7 @@ void ContactsConfigWrapper::Init(Napi::Env env, Napi::Object exports) {
InstanceMethod("getAll", &ContactsConfigWrapper::getAll),
InstanceMethod("set", &ContactsConfigWrapper::set),
InstanceMethod("erase", &ContactsConfigWrapper::erase),

});
}

Expand Down Expand Up @@ -122,8 +124,6 @@ void ContactsConfigWrapper::set(const Napi::CallbackInfo& info) {
// created time)
contact.created = unix_timestamp_now();

if (auto name = maybeNonemptyString(obj.Get("name"), "contacts.set name"))
contact.set_name(std::move(*name));
if (auto nickname = maybeNonemptyString(obj.Get("nickname"), "contacts.set nickname"))
contact.set_nickname(std::move(*nickname));
else
Expand All @@ -139,12 +139,25 @@ void ContactsConfigWrapper::set(const Napi::CallbackInfo& info) {
toCppString(obj.Get("expirationMode"), "contacts.set expirationMode"));
contact.exp_timer = std::chrono::seconds{toCppInteger(
obj.Get("expirationTimerSeconds"), "contacts.set expirationTimerSeconds")};
if (auto pic = obj.Get("profilePicture"); !pic.IsUndefined())
contact.profile_picture = profile_pic_from_object(pic);
else
contact.profile_picture.clear();
// if no profile picture are given from the JS side,
// reset that user profile picture

auto newProfileUpdateSeconds = toCppSysSeconds(
obj.Get("profileUpdatedSeconds"), "contacts.set, profileUpdatedSeconds");

// if the saved profile info is older than the new one, update it and the profile fields
// provided
if (contact.profile_updated < newProfileUpdateSeconds) {
contact.profile_updated = newProfileUpdateSeconds;

if (auto name = maybeNonemptyString(obj.Get("name"), "contacts.set name"))
contact.set_name(std::move(*name));

// if no profile picture are given from the JS side,
// reset that user profile picture
if (auto pic = obj.Get("profilePicture"); !pic.IsUndefined())
contact.profile_picture = profile_pic_from_object(pic);
else
contact.profile_picture.clear();
}

config.set(contact);
});
Expand Down
40 changes: 18 additions & 22 deletions src/groups/meta_group_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Napi::Object member_to_js(const Napi::Env& env, const member& info, const member
obj["pubkeyHex"] = toJs(env, info.session_id);
obj["name"] = toJs(env, info.name);
obj["profilePicture"] = toJs(env, info.profile_picture);
obj["profileUpdatedSeconds"] = toJs(env, info.profile_updated);
obj["supplement"] = toJs(env, info.supplement);

switch (status) {
Expand Down Expand Up @@ -110,8 +111,6 @@ void MetaGroupWrapper::Init(Napi::Env env, Napi::Object exports) {
InstanceMethod(
"membersMarkPendingRemoval",
&MetaGroupWrapper::membersMarkPendingRemoval),
InstanceMethod(
"memberSetNameTruncated", &MetaGroupWrapper::memberSetNameTruncated),
InstanceMethod("memberSetSupplement", &MetaGroupWrapper::memberSetSupplement),
InstanceMethod("memberSetInviteSent", &MetaGroupWrapper::memberSetInviteSent),
InstanceMethod(
Expand All @@ -130,7 +129,7 @@ void MetaGroupWrapper::Init(Napi::Env env, Napi::Object exports) {
"memberSetPromotionAccepted",
&MetaGroupWrapper::memberSetPromotionAccepted),
InstanceMethod(
"memberSetProfilePicture", &MetaGroupWrapper::memberSetProfilePicture),
"memberSetProfileDetails", &MetaGroupWrapper::memberSetProfileDetails),
InstanceMethod(
"memberResetAllSendingState",
&MetaGroupWrapper::memberResetAllSendingState),
Expand Down Expand Up @@ -519,21 +518,6 @@ Napi::Value MetaGroupWrapper::memberConstructAndSet(const Napi::CallbackInfo& in
});
}

void MetaGroupWrapper::memberSetNameTruncated(const Napi::CallbackInfo& info) {
wrapExceptions(info, [&] {
assertIsString(info[0]);
assertIsString(info[1]);

auto pubkeyHex = toCppString(info[0], "memberSetNameTruncated pubkeyHex");
auto newName = toCppString(info[1], "memberSetNameTruncated newName");
auto m = this->meta_group->members->get(pubkeyHex);
if (m) {
m->set_name(newName);
this->meta_group->members->set(*m);
}
});
}

void MetaGroupWrapper::memberSetSupplement(const Napi::CallbackInfo& info) {
wrapExceptions(info, [&] {
assertIsString(info[0]);
Expand Down Expand Up @@ -652,18 +636,30 @@ void MetaGroupWrapper::memberSetPromotionAccepted(const Napi::CallbackInfo& info
});
}

void MetaGroupWrapper::memberSetProfilePicture(const Napi::CallbackInfo& info) {
void MetaGroupWrapper::memberSetProfileDetails(const Napi::CallbackInfo& info) {
wrapExceptions(info, [&] {
assertInfoLength(info, 2);
assertIsString(info[0]);
assertIsObject(info[1]);

auto pubkeyHex = toCppString(info[0], "memberSetProfilePicture");
auto profilePicture = profile_pic_from_object(info[1]);
auto pubkeyHex = toCppString(info[0], "memberSetProfileDetails");

auto m = this->meta_group->members->get(pubkeyHex);
if (m) {
auto argsAsObj = info[1].As<Napi::Object>();
auto updatedAtSeconds =
toCppSysSeconds(argsAsObj.Get("profileUpdatedSeconds"), "memberSetProfileDetails");

// if the profile details provided are more recent that the ones saved, update them
if (m && updatedAtSeconds > m->profile_updated) {
m->profile_updated = updatedAtSeconds;

auto profilePicture = profile_pic_from_object(argsAsObj.Get("profilePicture"));
m->profile_picture = profilePicture;

// this will truncate silently if the name is too long
auto newName = toCppString(argsAsObj.Get("name"), "memberSetProfileDetails newName");
m->set_name_truncated(newName);

this->meta_group->members->set(*m);
}
});
Expand Down
41 changes: 39 additions & 2 deletions src/user_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,17 @@ void UserConfigWrapper::Init(Napi::Env env, Napi::Object exports) {
InstanceMethod("getPriority", &UserConfigWrapper::getPriority),
InstanceMethod("getName", &UserConfigWrapper::getName),
InstanceMethod("getProfilePic", &UserConfigWrapper::getProfilePic),
InstanceMethod(
"getProfilePicWithKeyHex", &UserConfigWrapper::getProfilePicWithKeyHex),
InstanceMethod(
"getProfileUpdatedSeconds",
&UserConfigWrapper::getProfileUpdatedSeconds),
InstanceMethod(
"setReuploadProfilePic", &UserConfigWrapper::setReuploadProfilePic),
InstanceMethod("setPriority", &UserConfigWrapper::setPriority),
InstanceMethod("setName", &UserConfigWrapper::setName),
InstanceMethod("setNameTruncated", &UserConfigWrapper::setNameTruncated),
InstanceMethod("setProfilePic", &UserConfigWrapper::setProfilePic),
InstanceMethod("setNewProfilePic", &UserConfigWrapper::setNewProfilePic),
InstanceMethod(
"getEnableBlindedMsgRequest",
&UserConfigWrapper::getEnableBlindedMsgRequest),
Expand Down Expand Up @@ -107,7 +114,7 @@ void UserConfigWrapper::setNameTruncated(const Napi::CallbackInfo& info) {
});
}

void UserConfigWrapper::setProfilePic(const Napi::CallbackInfo& info) {
void UserConfigWrapper::setNewProfilePic(const Napi::CallbackInfo& info) {
return wrapExceptions(info, [&] {
assertInfoLength(info, 1);
auto profile_pic_obj = info[0];
Expand All @@ -119,6 +126,36 @@ void UserConfigWrapper::setProfilePic(const Napi::CallbackInfo& info) {
});
}

void UserConfigWrapper::setReuploadProfilePic(const Napi::CallbackInfo& info) {
assertInfoLength(info, 1);
auto profile_pic_obj = info[0];

if (!profile_pic_obj.IsNull() && !profile_pic_obj.IsUndefined())
assertIsObject(profile_pic_obj);

config.set_reupload_profile_pic(profile_pic_from_object(profile_pic_obj));
}

Napi::Value UserConfigWrapper::getProfileUpdatedSeconds(const Napi::CallbackInfo& info) {
return wrapResult(info, [&] {
auto env = info.Env();
return config.get_profile_updated();
});
}

Napi::Value UserConfigWrapper::getProfilePicWithKeyHex(const Napi::CallbackInfo& info) {
return wrapResult(info, [&]() -> std::optional<std::string> {
auto env = info.Env();
auto pic = config.get_profile_pic();
// if pic.key and url are set, return a combined string with both merged by a hash, and the
// key in hex
if (!pic.url.empty() && !pic.key.empty()) {
return std::string(pic.url + "#" + to_hex(pic.key));
}
return std::nullopt;
});
}

Napi::Value UserConfigWrapper::getEnableBlindedMsgRequest(const Napi::CallbackInfo& info) {
return wrapResult(info, [&] {
auto env = info.Env();
Expand Down
Loading