Skip to content

Commit

Permalink
Merge pull request #70 from mpretty-cyro/add-supplement-flag
Browse files Browse the repository at this point in the history
Added supplement flag to indicate invited member key rotation type
  • Loading branch information
jagerman committed Oct 26, 2023
2 parents 986caaa + 61fd7c6 commit 4305c78
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 5 deletions.
1 change: 1 addition & 0 deletions include/session/config/groups/members.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ 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
bool supplement;

} config_group_member;

Expand Down
27 changes: 23 additions & 4 deletions include/session/config/groups/members.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ using namespace std::literals;
/// - 2 if an invite was created but failed to send for some reason (and thus can be resent)
/// - omitted once an invite is accepted. (This also gets omitted if the `A` admin flag gets
/// set).
/// s - invite supplemental keys flag (only set when `I` is set): if set (to 1) then this invite
/// was issued with the intention of sending the user the existing active decryption keys
/// (allowing them to access current messages); if omitted (with `I` set) then the invitation
/// was not meant to give access to past configs/messages (and was presumably issued with a
/// group rekey).
/// A - flag set to 1 if the member is an admin, omitted otherwise.
/// P - promotion (to admin) status; this will be one of:
/// - 1 if a promotion has been sent.
Expand Down Expand Up @@ -81,7 +86,18 @@ struct member {
///
/// See also `promoted()` if you want to check for either an admin or someone being promoted to
/// admin.
bool admin = 0;
bool admin = false;

/// API: groups/member::supplement
///
/// Member variable
///
/// Flag that is set to indicate to the group that this member was added with a supplemental key
/// rotation so that other admins can trigger the same key rotation method if they send a new
/// invitation to the same member.
///
/// Note that this should be cleared when a member accepts an invitation.
bool supplement = false;

// Flags to track an invited user. This value is typically not used directly, but rather via
// the `set_invited()`, `invite_pending()` and similar methods.
Expand All @@ -101,11 +117,14 @@ struct member {

/// API: groups/members::set_accepted
///
/// This clears the "invited" flag for this user, thus indicating that the user has accepted an
/// invitation and is now a regular member of the group.
/// This clears the "invited" and "supplement" flags for this user, thus indicating that the
/// user has accepted an invitation and is now a regular member of the group.
///
/// Inputs: none
void set_accepted() { invite_status = 0; }
void set_accepted() {
invite_status = 0;
supplement = false;
}

/// API: groups/member::invite_pending
///
Expand Down
4 changes: 4 additions & 0 deletions src/config/groups/members.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ void Members::set(const member& mem) {
set_flag(info["A"], mem.admin);
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);
}

void member::load(const dict& info_dict) {
Expand All @@ -68,6 +69,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);
supplement = invite_pending() && !promoted() ? maybe_int(info_dict, "s").value_or(0) : 0;
}

/// Load _val from the current iterator position; if it is invalid, skip to the next key until we
Expand Down Expand Up @@ -139,6 +141,7 @@ 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;
supplement = m.supplement;
}

void member::into(config_group_member& m) const {
Expand All @@ -155,6 +158,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.supplement = supplement;
}

void member::set_name(std::string n) {
Expand Down
1 change: 1 addition & 0 deletions tests/test_group_keys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ TEST_CASE("Group Keys - C++ API", "[config][groups][keys][cpp]") {

auto memb = admin1.members.get_or_construct(m.session_id);
memb.set_invited();
memb.supplement = true;
memb.name = i == 0 ? "fred" : "JOHN";
admin1.members.set(memb);

Expand Down
9 changes: 8 additions & 1 deletion tests/test_group_members.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ 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.supplement);
if (i < 10) {
CHECK(m.admin);
CHECK(m.name == "Admin " + std::to_string(i));
Expand Down Expand Up @@ -147,12 +148,16 @@ TEST_CASE("Group Members", "[config][groups][members]") {
}
for (int i = 50; i < 55; i++) {
auto m = gmem2.get_or_construct(sids[i]);
m.set_invited();
m.set_invited(); // failed invite
if (i % 2)
m.supplement = true;
gmem2.set(m);
}
for (int i = 55; i < 58; i++) {
auto m = gmem2.get_or_construct(sids[i]);
m.set_invited(true);
if (i % 2)
m.supplement = true;
gmem2.set(m);
}
for (int i = 58; i < 62; i++) {
Expand Down Expand Up @@ -187,6 +192,7 @@ TEST_CASE("Group Members", "[config][groups][members]") {
(i < 20 ? "http://example.com/" + std::to_string(i) : ""));
CHECK(m.invite_pending() == (50 <= i && i < 58));
CHECK(m.invite_failed() == (55 <= i && i < 58));
CHECK(m.supplement == (i % 2 && 50 < i && i < 58));
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));
Expand Down Expand Up @@ -237,6 +243,7 @@ TEST_CASE("Group Members", "[config][groups][members]") {
(i < 20 ? "http://example.com/" + std::to_string(i) : ""));
CHECK(m.invite_pending() == (55 <= i && i < 58));
CHECK(m.invite_failed() == (i == 57));
CHECK(m.supplement == (i == 55 || i == 57));
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));
Expand Down

0 comments on commit 4305c78

Please sign in to comment.