mirror of
https://github.com/block/buzz.git
synced 2026-10-28 04:51:40 +00:00
fix(db): distinguish issuer timeout denials
Co-authored-by: Codex <codex@openai.com> Signed-off-by: Brad Seiler <seiler@squareup.com> Signed-off-by: Local Builder <1c476cb1127ea270cb900bdc3891060140bdd1173f91498030ee9b4db01c2f20@buzz.block.builderlab.xyz>
This commit is contained in:
@@ -151,6 +151,8 @@ the same machine.
|
||||
New invitations are durable v2 bearers. A community ban permanently revokes
|
||||
outstanding v2 invitations issued by that principal or its recorded agents.
|
||||
Unban does not restore them; an unrestricted issuer can mint new invitations.
|
||||
An issuer or verified owner timeout also blocks claims on existing invitations
|
||||
while it lasts, without durable revocation. Claims resume after timeout expiry.
|
||||
Claim credentials are verified without user writes. Successful claims commit
|
||||
verified ownership with membership, policy evidence, and v2 consumption.
|
||||
Rejected claims create no users or owner links.
|
||||
|
||||
@@ -60,6 +60,8 @@ pub enum ClaimOutcome {
|
||||
Invalid,
|
||||
/// The issuer's invitation was permanently revoked.
|
||||
Revoked,
|
||||
/// The issuer or its owner is currently banned or timed out.
|
||||
IssuerRestricted,
|
||||
/// The claimant or its verified owner is banned or timed out.
|
||||
Restricted,
|
||||
}
|
||||
@@ -403,9 +405,12 @@ pub async fn claim_relay_invite_with_owner(
|
||||
|
||||
let revoked_at: Option<DateTime<Utc>> = invite.try_get("revoked_at")?;
|
||||
let issuer: String = invite.try_get("created_by")?;
|
||||
if revoked_at.is_some() || principal_restricted(&mut tx, community, &issuer).await? {
|
||||
if revoked_at.is_some() {
|
||||
return Ok(ClaimOutcome::Revoked.into());
|
||||
}
|
||||
if principal_restricted(&mut tx, community, &issuer).await? {
|
||||
return Ok(ClaimOutcome::IssuerRestricted.into());
|
||||
}
|
||||
|
||||
let uses_remaining = || max_uses.map(|mu| mu - use_count);
|
||||
|
||||
|
||||
@@ -110,3 +110,51 @@ async fn successful_claim_reports_only_committed_user_creation() {
|
||||
assert!(!retry.inserted && !retry.owner_link_created);
|
||||
assert_eq!(retry.users_created, 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore = "requires Postgres"]
|
||||
async fn issuer_timeout_denies_temporarily_without_revoking_invite() {
|
||||
let pool = postgres_tests::setup_pool().await;
|
||||
let community = postgres_tests::make_test_community(&pool).await;
|
||||
let issuer = postgres_tests::test_pubkey();
|
||||
let claimant = postgres_tests::test_pubkey();
|
||||
let invite = mint_relay_invite(&pool, community, &issuer, 3600, Some(1))
|
||||
.await
|
||||
.unwrap();
|
||||
sqlx::query("INSERT INTO community_bans (community_id,pubkey,muted_until,actor_pubkey) VALUES ($1,$2,clock_timestamp()+interval '1 hour',$2)")
|
||||
.bind(community.as_uuid()).bind(hex::decode(&issuer).unwrap()).execute(&pool).await.unwrap();
|
||||
assert_eq!(
|
||||
claim_relay_invite(
|
||||
&pool,
|
||||
community,
|
||||
&hash_v2_code(&invite.code),
|
||||
&claimant,
|
||||
None
|
||||
)
|
||||
.await
|
||||
.unwrap(),
|
||||
ClaimOutcome::IssuerRestricted
|
||||
);
|
||||
let revoked: Option<DateTime<Utc>> =
|
||||
sqlx::query_scalar("SELECT revoked_at FROM relay_invites WHERE community_id=$1 AND id=$2")
|
||||
.bind(community.as_uuid())
|
||||
.bind(invite.invite_id)
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(revoked.is_none());
|
||||
sqlx::query("UPDATE community_bans SET muted_until=clock_timestamp()-interval '1 second' WHERE community_id=$1")
|
||||
.bind(community.as_uuid()).execute(&pool).await.unwrap();
|
||||
assert!(matches!(
|
||||
claim_relay_invite(
|
||||
&pool,
|
||||
community,
|
||||
&hash_v2_code(&invite.code),
|
||||
&claimant,
|
||||
None
|
||||
)
|
||||
.await
|
||||
.unwrap(),
|
||||
ClaimOutcome::Joined { use_count: 1, .. }
|
||||
));
|
||||
}
|
||||
|
||||
@@ -508,7 +508,8 @@ pub async fn claim_invite(
|
||||
buzz_db::relay_invite::ClaimOutcome::Exhausted => {
|
||||
Err(api_error(StatusCode::FORBIDDEN, "invite_exhausted"))
|
||||
}
|
||||
buzz_db::relay_invite::ClaimOutcome::Revoked => {
|
||||
buzz_db::relay_invite::ClaimOutcome::Revoked
|
||||
| buzz_db::relay_invite::ClaimOutcome::IssuerRestricted => {
|
||||
Err(api_error(StatusCode::FORBIDDEN, "invite_invalid"))
|
||||
}
|
||||
buzz_db::relay_invite::ClaimOutcome::Restricted => {
|
||||
|
||||
Reference in New Issue
Block a user