Skip to content

Commit

Permalink
Merge pull request #72 from mpretty-cyro/add-remove-pending
Browse files Browse the repository at this point in the history
Added the `removed_status` value and a way to retrieve the current `GROUP_KEYS` generation
  • Loading branch information
jagerman committed Nov 17, 2023
2 parents 573e46c + 61c792b commit b4c8e53
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 2 deletions.
11 changes: 11 additions & 0 deletions include/session/config/groups/keys.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,17 @@ LIBSESSION_EXPORT bool groups_keys_key_supplement(
unsigned char** message,
size_t* message_len);

/// API: groups/groups_keys_current_generation
///
/// Returns the current generation number for the latest keys message.
///
/// Inputs:
/// - `conf` -- [in] Pointer to the config object
///
/// Oututs:
/// - `int` -- latest keys generation number
LIBSESSION_EXPORT int groups_keys_current_generation(config_group_keys* conf);

/// API: groups/groups_keys_swarm_make_subaccount
///
/// Constructs a swarm subaccount signing value that a member can use to access messages in the
Expand Down
8 changes: 8 additions & 0 deletions include/session/config/groups/keys.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,14 @@ class Keys final : public ConfigSig {
return key_supplement(std::vector{{std::move(sid)}});
}

/// API: groups/current_generation
///
/// Returns the current generation number for the latest keys message.
///
/// Oututs:
/// - `int` -- latest keys generation number.
int current_generation() const { return keys_.empty() ? 0 : keys_.back().generation; }

/// API: groups/Keys::swarm_make_subaccount
///
/// Constructs a swarm subaccount signing value that a member can use to access messages in the
Expand Down
3 changes: 3 additions & 0 deletions include/session/config/groups/members.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ extern "C" {
#include "../util.h"

enum groups_members_invite_status { INVITE_SENT = 1, INVITE_FAILED = 2 };
enum groups_members_remove_status { REMOVED_MEMBER = 1, REMOVED_MEMBER_AND_MESSAGES = 2 };

typedef struct config_group_member {
char session_id[67]; // in hex; 66 hex chars + null terminator.
Expand All @@ -20,6 +21,8 @@ typedef struct config_group_member {
bool admin;
int invited; // 0 == unset, INVITE_SENT = invited, INVITED_FAILED = invite failed to send
int promoted; // same value as `invited`, but for promotion-to-admin
int removed; // 0 == unset, REMOVED_MEMBER = removed, REMOVED_MEMBER_AND_MESSAGES = remove
// member and their messages
bool supplement;

} config_group_member;
Expand Down
40 changes: 40 additions & 0 deletions include/session/config/groups/members.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ using namespace std::literals;
/// - omitted once the promotion is accepted (i.e. once `A` gets set).

constexpr int INVITE_SENT = 1, INVITE_FAILED = 2;
constexpr int REMOVED_MEMBER = 1, REMOVED_MEMBER_AND_MESSAGES = 2;

/// Struct containing member details
struct member {
Expand Down Expand Up @@ -200,6 +201,45 @@ struct member {
/// - `bool` -- true if the member is promoted (or promotion-in-progress)
bool promoted() const { return admin || promotion_pending(); }

// Flags to track a removed user. This value is typically not used directly, but
// rather via the `set_removed()`, `is_removed()` and similar methods.
int removed_status = 0;

/// API: groups/member::set_removed
///
/// Sets the "removed" flag for this user. This marks the user as pending removal from the
/// group. The optional `messages` parameter can be specified as true if we want to remove
/// any messages sent by the member upon a successful removal.
///
/// Inputs:
/// - `messages`: can be specified as true to indicate any messages sent by the member
/// should also be removed upon a successful member removal.
void set_removed(bool messages = false) {
removed_status = messages ? REMOVED_MEMBER_AND_MESSAGES : REMOVED_MEMBER;
}

/// API: groups/member::is_removed
///
/// Returns true if the user should be removed from the group.
///
/// Inputs: none.
///
/// Outputs:
/// - `bool` -- true if the member should be removed from the group
bool is_removed() const { return removed_status > 0; }

/// API: groups/member::should_remove_messages
///
/// Returns true if the users messages should be removed after they are
/// successfully removed.
///
/// Inputs: none.
///
/// Outputs:
/// - `bool` -- true if the members messages should be removed after they are
/// successfully removed from the group
bool should_remove_messages() const { return removed_status == REMOVED_MEMBER_AND_MESSAGES; }

/// API: groups/member::into
///
/// Converts the member info into a C struct.
Expand Down
4 changes: 4 additions & 0 deletions src/config/groups/keys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1565,6 +1565,10 @@ LIBSESSION_C_API bool groups_keys_key_supplement(
}
}

LIBSESSION_EXPORT int groups_keys_current_generation(config_group_keys* conf) {
return unbox(conf).current_generation();
}

LIBSESSION_C_API bool groups_keys_swarm_make_subaccount_flags(
config_group_keys* conf,
const char* session_id,
Expand Down
6 changes: 6 additions & 0 deletions src/config/groups/members.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ void Members::set(const member& mem) {
set_positive_int(info["P"], mem.admin ? 0 : mem.promotion_status);
set_positive_int(info["I"], mem.admin ? 0 : mem.invite_status);
set_flag(info["s"], mem.supplement);
set_positive_int(info["R"], mem.removed_status);
}

void member::load(const dict& info_dict) {
Expand All @@ -69,6 +70,7 @@ void member::load(const dict& info_dict) {
admin = maybe_int(info_dict, "A").value_or(0);
invite_status = admin ? 0 : maybe_int(info_dict, "I").value_or(0);
promotion_status = admin ? 0 : maybe_int(info_dict, "P").value_or(0);
removed_status = maybe_int(info_dict, "R").value_or(0);
supplement = invite_pending() && !promoted() ? maybe_int(info_dict, "s").value_or(0) : 0;
}

Expand Down Expand Up @@ -141,6 +143,9 @@ member::member(const config_group_member& m) : session_id{m.session_id, 66} {
admin = m.admin;
invite_status = (m.invited == INVITE_SENT || m.invited == INVITE_FAILED) ? m.invited : 0;
promotion_status = (m.promoted == INVITE_SENT || m.promoted == INVITE_FAILED) ? m.promoted : 0;
removed_status = (m.removed == REMOVED_MEMBER || m.removed == REMOVED_MEMBER_AND_MESSAGES)
? m.removed
: 0;
supplement = m.supplement;
}

Expand All @@ -158,6 +163,7 @@ void member::into(config_group_member& m) const {
static_assert(groups::INVITE_FAILED == ::INVITE_FAILED);
m.invited = invite_status;
m.promoted = promotion_status;
m.removed = removed_status;
m.supplement = supplement;
}

Expand Down
15 changes: 13 additions & 2 deletions tests/test_group_members.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ TEST_CASE("Group Members", "[config][groups][members]") {
CHECK_FALSE(m.invite_failed());
CHECK_FALSE(m.promotion_pending());
CHECK_FALSE(m.promotion_failed());
CHECK_FALSE(m.is_removed());
CHECK_FALSE(m.should_remove_messages());
CHECK_FALSE(m.supplement);
if (i < 10) {
CHECK(m.admin);
Expand Down Expand Up @@ -165,6 +167,11 @@ TEST_CASE("Group Members", "[config][groups][members]") {
m.set_promoted(i >= 60);
gmem2.set(m);
}
for (int i = 62; i < 66; i++) {
auto m = gmem2.get_or_construct(sids[i]);
m.set_removed(i >= 64);
gmem2.set(m);
}

CHECK(gmem2.get(sids[23]).value().name == "Member 23");

Expand Down Expand Up @@ -196,9 +203,11 @@ TEST_CASE("Group Members", "[config][groups][members]") {
CHECK(m.promoted() == (i < 10 || (i >= 58 && i < 62)));
CHECK(m.promotion_pending() == (i >= 58 && i < 62));
CHECK(m.promotion_failed() == (i >= 60 && i < 62));
CHECK(m.is_removed() == (i >= 62 && i < 66));
CHECK(m.should_remove_messages() == (i >= 64 && i < 66));
i++;
}
CHECK(i == 62);
CHECK(i == 66);
}

for (int i = 0; i < 100; i++) {
Expand Down Expand Up @@ -247,10 +256,12 @@ TEST_CASE("Group Members", "[config][groups][members]") {
CHECK(m.promoted() == (i < 10 || (i >= 58 && i < 62)));
CHECK(m.promotion_pending() == (i >= 59 && i <= 61));
CHECK(m.promotion_failed() == (i >= 60 && i <= 61));
CHECK(m.is_removed() == (i >= 62 && i < 66));
CHECK(m.should_remove_messages() == (i >= 64 && i < 66));
do
i++;
while (is_prime100(i));
}
CHECK(i == 62);
CHECK(i == 66);
}
}

0 comments on commit b4c8e53

Please sign in to comment.