Bug: GROUP_INVITE expiration not enforced (invites never expire)
Summary
Closed-group invites (GROUP_INVITE) include a TTL/expiration parameter, but expiration is not enforced anywhere in Qortal Core. As a result, any invite can be accepted indefinitely, even long after its intended expiry, allowing late/unwanted joins to closed groups.
Impact / Why this matters
- Closed-groups effectively have permanent invites unless admins manually cancel them or kick members after they join.
- Admins who issue short-lived invites (e.g. “valid for 1 day”) cannot rely on TTL for access control.
- Users can accept an old invite months later and become a member, which is surprising and can be a privacy/security concern for groups that assume invite expiry works.
- Current workaround is manual: kick members after they join, or preemptively cancel invites.
Expected behavior
For closed groups, once an invite’s TTL has passed:
- The invite should be treated as invalid/expired.
- A
JOIN_GROUP should not be auto-approved by an expired invite (ideally it becomes a join request again, requiring a fresh invite/approval).
Actual behavior
- Issued invites can be accepted at any time, regardless of TTL/expiration.
JOIN_GROUP finds an invite record and finalizes membership even if the invite’s expires_when is in the past.
Technical cause (current implementation)
In short: expiration is data-only right now; it is never consulted in validation/finalization logic.
Reproduction (simple)
- Create a closed group.
- Admin sends
GROUP_INVITE to address X with a short TTL (e.g. 60 seconds).
- Wait until TTL has passed.
- Address X sends
JOIN_GROUP.
- Observe: X is still added as a member (invite behaves as non-expiring).
Proposed fix (high level)
-
Consensus-enforced expiry on membership finalization (behind a feature trigger):
- After the trigger height, treat an invite as valid only if
expiry == null/0 (never) OR finalization-time <= expires_when.
- If expired, ignore invite and handle
JOIN_GROUP as a join request (preferred) or reject (more disruptive).
- Must be feature-triggered because it changes membership outcomes (consensus).
-
API filtering for invites:
- Default invite-list endpoints should omit expired invites.
- Add optional flag (e.g.
includeExpired=true) to show them for debugging/UI needs.
-
Tests:
Notes / Related
- There is a manual cancellation tx (
CANCEL_GROUP_INVITE), but that’s not a substitute for TTL enforcement.
- Prefer filtering over DB pruning for expired invites (avoid unnecessary state mutation; keep consensus logic deterministic).
Bug:
GROUP_INVITEexpiration not enforced (invites never expire)Summary
Closed-group invites (
GROUP_INVITE) include a TTL/expiration parameter, but expiration is not enforced anywhere in Qortal Core. As a result, any invite can be accepted indefinitely, even long after its intended expiry, allowing late/unwanted joins to closed groups.Impact / Why this matters
Expected behavior
For closed groups, once an invite’s TTL has passed:
JOIN_GROUPshould not be auto-approved by an expired invite (ideally it becomes a join request again, requiring a fresh invite/approval).Actual behavior
JOIN_GROUPfinds an invite record and finalizes membership even if the invite’sexpires_whenis in the past.Technical cause (current implementation)
Invite TTL is stored and
expires_whenis computed when savingGROUP_INVITE(expiry persisted inGroupInvites.expires_when).However:
expires_whenat all; it only checks whether an invite exists and then uses it to approve membership.In short: expiration is data-only right now; it is never consulted in validation/finalization logic.
Reproduction (simple)
GROUP_INVITEto address X with a short TTL (e.g. 60 seconds).JOIN_GROUP.Proposed fix (high level)
Consensus-enforced expiry on membership finalization (behind a feature trigger):
expiry == null/0 (never)ORfinalization-time <= expires_when.JOIN_GROUPas a join request (preferred) or reject (more disruptive).API filtering for invites:
includeExpired=true) to show them for debugging/UI needs.Tests:
Add unit/integration tests covering:
Notes / Related
CANCEL_GROUP_INVITE), but that’s not a substitute for TTL enforcement.