You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Invite tokens currently have no TTL — once created, they remain valid indefinitely until revoke_invite() is called. A lost URL from months ago is still live.
Store a created-at timestamp alongside the (hashed, per #10) token. On lookup in get_post_by_token() and in handle_invite_request(), reject tokens older than MAP_INVITE_TTL (default DAY_IN_SECONDS, filterable).
Sketch (assuming we land #10 first so the storage shape changes anyway):
constTOKEN_META_KEY = '_map_invite_token'; // now stores an array: [ 'hash' => ..., 'created' => int ]publicstaticfunctioncreate_invite_url( int$post_id ): string {
$token = wp_generate_password( 32, false );
update_post_meta(
$post_id,
self::TOKEN_META_KEY,
array(
'hash' => hash( 'sha256', $token ),
'created' => time(),
)
);
returnself::build_url( $token );
}
publicstaticfunctionget_post_by_token( string$token ): ?\WP_Post {
if ( '' === $token ) {
returnnull;
}
$hash = hash( 'sha256', $token );
$ttl = (int) apply_filters( 'map_invite_ttl', DAY_IN_SECONDS );
// Query by hash via a meta_query on the serialized sub-key.// Simpler: query by post_status etc., then hash_equals + TTL check in PHP.
…
}
The array meta shape plus a TTL check means lookup can no longer be a single meta_value equality query. Two realistic approaches:
Store hash as the meta value (scalar) and keep created in a second meta key _map_invite_created. Preserves the simple meta_value lookup; requires updating both on create/revoke.
Store as serialized array (as sketched). Query posts by a lightweight hash index (either by also keeping a _map_invite_hash scalar alongside, or by shifting to a custom table — related to the broader storage discussion in Update README with project description and Playground link #7).
Option 1 is the smaller change.
Handling expiry in handle_invite_request()
When an expired token is presented, surface the same "invalid or revoked" error message (wp_die) — don't leak whether it was expired vs never-existed vs revoked.
Optionally: delete expired tokens as a side-effect of encountering them, so they don't persist in the DB forever.
Filter
apply_filters( 'map_invite_ttl', DAY_IN_SECONDS ) so sites that want longer/shorter can override.
Tests to add
Token older than TTL is rejected.
Token within TTL is accepted.
Filter can override TTL.
handle_invite_request with expired token shows the same error page as an invalid token.
References
Internal security review, Apr 2026. Depends on / coordinates with #10.
Summary
Invite tokens currently have no TTL — once created, they remain valid indefinitely until
revoke_invite()is called. A lost URL from months ago is still live.Agreed in review to add a 24-hour expiry.
Where
includes/class-map-invite.php—create_invite_url(),get_post_by_token(),handle_invite_request().Suggested fix
Store a created-at timestamp alongside the (hashed, per #10) token. On lookup in
get_post_by_token()and inhandle_invite_request(), reject tokens older thanMAP_INVITE_TTL(defaultDAY_IN_SECONDS, filterable).Sketch (assuming we land #10 first so the storage shape changes anyway):
The
arraymeta shape plus a TTL check means lookup can no longer be a singlemeta_valueequality query. Two realistic approaches:createdin a second meta key_map_invite_created. Preserves the simplemeta_valuelookup; requires updating both on create/revoke._map_invite_hashscalar alongside, or by shifting to a custom table — related to the broader storage discussion in Update README with project description and Playground link #7).Option 1 is the smaller change.
Handling expiry in
handle_invite_request()When an expired token is presented, surface the same "invalid or revoked" error message (
wp_die) — don't leak whether it was expired vs never-existed vs revoked.Optionally: delete expired tokens as a side-effect of encountering them, so they don't persist in the DB forever.
Filter
apply_filters( 'map_invite_ttl', DAY_IN_SECONDS )so sites that want longer/shorter can override.Tests to add
handle_invite_requestwith expired token shows the same error page as an invalid token.References
Internal security review, Apr 2026. Depends on / coordinates with #10.