mirror of
https://tangled.org/tranquil.farm/tranquil-pds
synced 2026-08-01 15:06:05 +00:00
invite: require owning account for generated codes
Lewis: May this revision serve well! <lu5a@proton.me>
This commit is contained in:
@@ -43,7 +43,7 @@ pub async fn create_invite_code(
|
||||
match state
|
||||
.repos
|
||||
.infra
|
||||
.create_invite_code(&code, input.use_count, Some(&for_account))
|
||||
.create_invite_code(&code, input.use_count, &for_account)
|
||||
.await
|
||||
{
|
||||
Ok(true) => Ok(Json(CreateInviteCodeOutput { code })),
|
||||
@@ -115,7 +115,7 @@ pub async fn create_invite_codes(
|
||||
async move {
|
||||
let codes: Vec<InviteCodeValue> = (0..code_count).map(|_| gen_invite_code()).collect();
|
||||
infra_repo
|
||||
.create_invite_codes_batch(&codes, use_count, admin_user_id, Some(&account))
|
||||
.create_invite_codes_batch(&codes, use_count, admin_user_id, &account)
|
||||
.await
|
||||
.map(|_| AccountCodes { account, codes })
|
||||
}
|
||||
@@ -188,27 +188,24 @@ pub async fn get_account_invite_codes(
|
||||
let codes = futures::future::join_all(filtered_codes.into_iter().map(|info| {
|
||||
let infra_repo = state.repos.infra.clone();
|
||||
async move {
|
||||
let uses = infra_repo
|
||||
let uses: Vec<InviteCodeUse> = infra_repo
|
||||
.get_invite_code_uses(&info.code)
|
||||
.await
|
||||
.map(|use_rows| {
|
||||
use_rows
|
||||
.into_iter()
|
||||
.map(|u| InviteCodeUse {
|
||||
used_by: u.used_by_did.to_string(),
|
||||
used_by_handle: u.used_by_handle.map(|h| h.to_string()),
|
||||
used_at: u.used_at.to_rfc3339(),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.log_db_err("fetching invite code uses")?
|
||||
.into_iter()
|
||||
.map(|u| InviteCodeUse {
|
||||
used_by: u.used_by_did.to_string(),
|
||||
used_by_handle: u.used_by_handle.map(|h| h.to_string()),
|
||||
used_at: u.used_at.to_rfc3339(),
|
||||
})
|
||||
.unwrap_or_default();
|
||||
.collect();
|
||||
|
||||
let use_count = i32::try_from(uses.len()).unwrap_or(i32::MAX);
|
||||
if !include_used && use_count >= info.available_uses {
|
||||
return None;
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
Some(InviteCode {
|
||||
Ok(Some(InviteCode {
|
||||
code: info.code,
|
||||
available: info.available_uses,
|
||||
disabled: false,
|
||||
@@ -219,11 +216,16 @@ pub async fn get_account_invite_codes(
|
||||
.unwrap_or_else(|| "admin".to_string()),
|
||||
created_at: info.created_at.to_rfc3339(),
|
||||
uses,
|
||||
})
|
||||
}))
|
||||
}
|
||||
}))
|
||||
.await;
|
||||
|
||||
let codes: Vec<InviteCode> = codes.into_iter().flatten().collect();
|
||||
let codes: Vec<InviteCode> = codes
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<Option<InviteCode>>, ApiError>>()?
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect();
|
||||
Ok(Json(GetAccountInviteCodesOutput { codes }))
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ pub trait InfraRepository: Send + Sync {
|
||||
&self,
|
||||
code: &InviteCode,
|
||||
use_count: i32,
|
||||
for_account: Option<&Did>,
|
||||
for_account: &Did,
|
||||
) -> Result<bool, DbError>;
|
||||
|
||||
async fn create_invite_codes_batch(
|
||||
@@ -258,7 +258,7 @@ pub trait InfraRepository: Send + Sync {
|
||||
codes: &[InviteCode],
|
||||
use_count: i32,
|
||||
created_by_user: Uuid,
|
||||
for_account: Option<&Did>,
|
||||
for_account: &Did,
|
||||
) -> Result<(), DbError>;
|
||||
|
||||
async fn get_invite_code_available_uses(
|
||||
|
||||
@@ -7,10 +7,12 @@ use tranquil_db_traits::{
|
||||
InviteCodeSortOrder, InviteCodeState, InviteCodeUse, NotificationHistoryRow, PlcTokenInfo,
|
||||
QueuedComms, ReservedSigningKey, ReservedSigningKeyFull, ValidatedInviteCode,
|
||||
};
|
||||
use tranquil_types::{CidLink, Did, Handle, InviteCode};
|
||||
use tranquil_types::{CidLink, Did, InviteCode};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::col;
|
||||
use super::user::map_sqlx_error;
|
||||
use super::{column, legacy_column, opt_column};
|
||||
|
||||
pub struct PostgresInfraRepository {
|
||||
pool: PgPool,
|
||||
@@ -153,9 +155,9 @@ impl InfraRepository for PostgresInfraRepository {
|
||||
&self,
|
||||
code: &InviteCode,
|
||||
use_count: i32,
|
||||
for_account: Option<&Did>,
|
||||
for_account: &Did,
|
||||
) -> Result<bool, DbError> {
|
||||
let for_account_str = for_account.map(|d| d.as_str());
|
||||
let for_account_str = for_account.as_str();
|
||||
let result = sqlx::query!(
|
||||
r#"INSERT INTO invite_codes (code, available_uses, created_by_user, for_account)
|
||||
SELECT $1, $2, id, $3 FROM users WHERE is_admin = true LIMIT 1"#,
|
||||
@@ -175,9 +177,9 @@ impl InfraRepository for PostgresInfraRepository {
|
||||
codes: &[InviteCode],
|
||||
use_count: i32,
|
||||
created_by_user: Uuid,
|
||||
for_account: Option<&Did>,
|
||||
for_account: &Did,
|
||||
) -> Result<(), DbError> {
|
||||
let for_account_str = for_account.map(|d| d.as_str());
|
||||
let for_account_str = for_account.as_str();
|
||||
let code_strs: Vec<String> = codes.iter().map(|c| c.to_string()).collect();
|
||||
sqlx::query!(
|
||||
r#"INSERT INTO invite_codes (code, available_uses, created_by_user, for_account)
|
||||
@@ -250,17 +252,19 @@ impl InfraRepository for PostgresInfraRepository {
|
||||
.await
|
||||
.map_err(map_sqlx_error)?;
|
||||
|
||||
Ok(results
|
||||
results
|
||||
.into_iter()
|
||||
.map(|r| InviteCodeInfo {
|
||||
code: InviteCode::from(r.code),
|
||||
available_uses: r.available_uses,
|
||||
state: InviteCodeState::from_optional_disabled_flag(r.disabled),
|
||||
for_account: Some(Did::from(r.for_account)),
|
||||
created_at: r.created_at,
|
||||
created_by: None,
|
||||
.map(|r| {
|
||||
Ok(InviteCodeInfo {
|
||||
code: InviteCode::from(r.code),
|
||||
available_uses: r.available_uses,
|
||||
state: InviteCodeState::from_optional_disabled_flag(r.disabled),
|
||||
for_account: legacy_column(r.for_account, col::INVITE_CODES_FOR_ACCOUNT),
|
||||
created_at: r.created_at,
|
||||
created_by: None,
|
||||
})
|
||||
})
|
||||
.collect())
|
||||
.collect()
|
||||
}
|
||||
|
||||
async fn get_invite_code_uses(&self, code: &InviteCode) -> Result<Vec<InviteCodeUse>, DbError> {
|
||||
@@ -278,11 +282,13 @@ impl InfraRepository for PostgresInfraRepository {
|
||||
|
||||
Ok(results
|
||||
.into_iter()
|
||||
.map(|r| InviteCodeUse {
|
||||
code: code.clone(),
|
||||
used_by_did: Did::from(r.did),
|
||||
used_by_handle: Some(Handle::from(r.handle)),
|
||||
used_at: r.used_at,
|
||||
.filter_map(|r| {
|
||||
Some(InviteCodeUse {
|
||||
code: code.clone(),
|
||||
used_by_did: legacy_column(r.did, col::USERS_DID)?,
|
||||
used_by_handle: legacy_column(r.handle, col::USERS_HANDLE),
|
||||
used_at: r.used_at,
|
||||
})
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
@@ -436,10 +442,10 @@ impl InfraRepository for PostgresInfraRepository {
|
||||
.await
|
||||
.map_err(map_sqlx_error)?;
|
||||
|
||||
Ok(results
|
||||
results
|
||||
.into_iter()
|
||||
.map(|r| (r.id, Did::from(r.did)))
|
||||
.collect())
|
||||
.map(|r| Ok((r.id, column(r.did, col::USERS_DID)?)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
async fn get_invite_code_uses_batch(
|
||||
@@ -459,15 +465,17 @@ impl InfraRepository for PostgresInfraRepository {
|
||||
.await
|
||||
.map_err(map_sqlx_error)?;
|
||||
|
||||
Ok(results
|
||||
results
|
||||
.into_iter()
|
||||
.map(|r| InviteCodeUse {
|
||||
code: InviteCode::from(r.code),
|
||||
used_by_did: Did::from(r.did),
|
||||
used_by_handle: None,
|
||||
used_at: r.used_at,
|
||||
.map(|r| {
|
||||
Ok(InviteCodeUse {
|
||||
code: InviteCode::from(r.code),
|
||||
used_by_did: column(r.did, col::USERS_DID)?,
|
||||
used_by_handle: None,
|
||||
used_at: r.used_at,
|
||||
})
|
||||
})
|
||||
.collect())
|
||||
.collect()
|
||||
}
|
||||
|
||||
async fn get_invites_created_by_user(
|
||||
@@ -485,17 +493,19 @@ impl InfraRepository for PostgresInfraRepository {
|
||||
.await
|
||||
.map_err(map_sqlx_error)?;
|
||||
|
||||
Ok(results
|
||||
results
|
||||
.into_iter()
|
||||
.map(|r| InviteCodeInfo {
|
||||
code: InviteCode::from(r.code),
|
||||
available_uses: r.available_uses,
|
||||
state: InviteCodeState::from_optional_disabled_flag(r.disabled),
|
||||
for_account: Some(Did::from(r.for_account)),
|
||||
created_at: r.created_at,
|
||||
created_by: Some(Did::from(r.created_by)),
|
||||
.map(|r| {
|
||||
Ok(InviteCodeInfo {
|
||||
code: InviteCode::from(r.code),
|
||||
available_uses: r.available_uses,
|
||||
state: InviteCodeState::from_optional_disabled_flag(r.disabled),
|
||||
for_account: legacy_column(r.for_account, col::INVITE_CODES_FOR_ACCOUNT),
|
||||
created_at: r.created_at,
|
||||
created_by: Some(column(r.created_by, col::USERS_DID)?),
|
||||
})
|
||||
})
|
||||
.collect())
|
||||
.collect()
|
||||
}
|
||||
|
||||
async fn get_invite_code_info(
|
||||
@@ -513,14 +523,18 @@ impl InfraRepository for PostgresInfraRepository {
|
||||
.await
|
||||
.map_err(map_sqlx_error)?;
|
||||
|
||||
Ok(result.map(|r| InviteCodeInfo {
|
||||
code: InviteCode::from(r.code),
|
||||
available_uses: r.available_uses,
|
||||
state: InviteCodeState::from_optional_disabled_flag(r.disabled),
|
||||
for_account: Some(Did::from(r.for_account)),
|
||||
created_at: r.created_at,
|
||||
created_by: Some(Did::from(r.created_by)),
|
||||
}))
|
||||
result
|
||||
.map(|r| {
|
||||
Ok(InviteCodeInfo {
|
||||
code: InviteCode::from(r.code),
|
||||
available_uses: r.available_uses,
|
||||
state: InviteCodeState::from_optional_disabled_flag(r.disabled),
|
||||
for_account: legacy_column(r.for_account, col::INVITE_CODES_FOR_ACCOUNT),
|
||||
created_at: r.created_at,
|
||||
created_by: Some(column(r.created_by, col::USERS_DID)?),
|
||||
})
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
async fn get_invite_codes_by_users(
|
||||
@@ -539,22 +553,22 @@ impl InfraRepository for PostgresInfraRepository {
|
||||
.await
|
||||
.map_err(map_sqlx_error)?;
|
||||
|
||||
Ok(results
|
||||
results
|
||||
.into_iter()
|
||||
.map(|r| {
|
||||
(
|
||||
Ok((
|
||||
r.created_by_user,
|
||||
InviteCodeInfo {
|
||||
code: InviteCode::from(r.code),
|
||||
available_uses: r.available_uses,
|
||||
state: InviteCodeState::from_optional_disabled_flag(r.disabled),
|
||||
for_account: Some(Did::from(r.for_account)),
|
||||
for_account: legacy_column(r.for_account, col::INVITE_CODES_FOR_ACCOUNT),
|
||||
created_at: r.created_at,
|
||||
created_by: Some(Did::from(r.created_by)),
|
||||
created_by: Some(column(r.created_by, col::USERS_DID)?),
|
||||
},
|
||||
)
|
||||
))
|
||||
})
|
||||
.collect())
|
||||
.collect()
|
||||
}
|
||||
|
||||
async fn get_invite_code_used_by_user(
|
||||
@@ -683,10 +697,14 @@ impl InfraRepository for PostgresInfraRepository {
|
||||
.await
|
||||
.map_err(map_sqlx_error)?;
|
||||
|
||||
Ok(result.map(|r| DeletionRequest {
|
||||
did: Did::from(r.did),
|
||||
expires_at: r.expires_at,
|
||||
}))
|
||||
result
|
||||
.map(|r| {
|
||||
Ok(DeletionRequest {
|
||||
did: column(r.did, col::ACCOUNT_DELETION_REQUESTS_DID)?,
|
||||
expires_at: r.expires_at,
|
||||
})
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
async fn delete_deletion_request(&self, token: &str) -> Result<(), DbError> {
|
||||
@@ -1027,16 +1045,20 @@ impl InfraRepository for PostgresInfraRepository {
|
||||
.await
|
||||
.map_err(map_sqlx_error)?;
|
||||
|
||||
Ok(result.map(|r| AdminAccountInfo {
|
||||
id: r.id,
|
||||
did: Did::from(r.did),
|
||||
handle: Handle::from(r.handle),
|
||||
email: r.email,
|
||||
created_at: r.created_at,
|
||||
invites_disabled: r.invites_disabled.unwrap_or(false),
|
||||
email_verified: r.email_verified,
|
||||
deactivated_at: r.deactivated_at,
|
||||
}))
|
||||
result
|
||||
.map(|r| {
|
||||
Ok(AdminAccountInfo {
|
||||
id: r.id,
|
||||
did: column(r.did, col::USERS_DID)?,
|
||||
handle: column(r.handle, col::USERS_HANDLE)?,
|
||||
email: r.email,
|
||||
created_at: r.created_at,
|
||||
invites_disabled: r.invites_disabled.unwrap_or(false),
|
||||
email_verified: r.email_verified,
|
||||
deactivated_at: r.deactivated_at,
|
||||
})
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
async fn get_admin_account_infos_by_dids(
|
||||
@@ -1058,15 +1080,17 @@ impl InfraRepository for PostgresInfraRepository {
|
||||
|
||||
Ok(results
|
||||
.into_iter()
|
||||
.map(|r| AdminAccountInfo {
|
||||
id: r.id,
|
||||
did: Did::from(r.did),
|
||||
handle: Handle::from(r.handle),
|
||||
email: r.email,
|
||||
created_at: r.created_at,
|
||||
invites_disabled: r.invites_disabled.unwrap_or(false),
|
||||
email_verified: r.email_verified,
|
||||
deactivated_at: r.deactivated_at,
|
||||
.filter_map(|r| {
|
||||
Some(AdminAccountInfo {
|
||||
id: r.id,
|
||||
did: legacy_column(r.did, col::USERS_DID)?,
|
||||
handle: legacy_column(r.handle, col::USERS_HANDLE)?,
|
||||
email: r.email,
|
||||
created_at: r.created_at,
|
||||
invites_disabled: r.invites_disabled.unwrap_or(false),
|
||||
email_verified: r.email_verified,
|
||||
deactivated_at: r.deactivated_at,
|
||||
})
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
@@ -1105,11 +1129,14 @@ impl InfraRepository for PostgresInfraRepository {
|
||||
.await
|
||||
.map_err(map_sqlx_error)?;
|
||||
|
||||
Ok(row.map(|r| DeletionRequestWithToken {
|
||||
token: r.token,
|
||||
did: Did::new(r.did).expect("valid DID in database"),
|
||||
expires_at: r.expires_at,
|
||||
}))
|
||||
row.map(|r| {
|
||||
Ok(DeletionRequestWithToken {
|
||||
token: r.token,
|
||||
did: column(r.did, col::ACCOUNT_DELETION_REQUESTS_DID)?,
|
||||
expires_at: r.expires_at,
|
||||
})
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
async fn get_latest_comms_for_user(
|
||||
@@ -1202,14 +1229,20 @@ impl InfraRepository for PostgresInfraRepository {
|
||||
.await
|
||||
.map_err(map_sqlx_error)?;
|
||||
|
||||
Ok(row.map(|r| ReservedSigningKeyFull {
|
||||
id: r.id,
|
||||
did: r.did.map(|d| Did::new(d).expect("valid DID in database")),
|
||||
public_key_did_key: Did::from(r.public_key_did_key),
|
||||
private_key_bytes: r.private_key_bytes,
|
||||
expires_at: r.expires_at,
|
||||
used_at: r.used_at,
|
||||
}))
|
||||
row.map(|r| {
|
||||
Ok(ReservedSigningKeyFull {
|
||||
id: r.id,
|
||||
did: opt_column(r.did, col::RESERVED_SIGNING_KEYS_DID)?,
|
||||
public_key_did_key: column(
|
||||
r.public_key_did_key,
|
||||
col::RESERVED_SIGNING_KEYS_PUBLIC_KEY_DID_KEY,
|
||||
)?,
|
||||
private_key_bytes: r.private_key_bytes,
|
||||
expires_at: r.expires_at,
|
||||
used_at: r.used_at,
|
||||
})
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
async fn get_plc_tokens_by_did(&self, did: &Did) -> Result<Vec<PlcTokenInfo>, DbError> {
|
||||
|
||||
@@ -117,7 +117,7 @@ fn test_handle(suffix: &str) -> Handle {
|
||||
}
|
||||
|
||||
fn test_cid(seed: u8) -> CidLink {
|
||||
CidLink::from(helpers::make_cid(&[seed]))
|
||||
CidLink::from_cid(&helpers::make_cid(&[seed]))
|
||||
}
|
||||
|
||||
fn test_nsid(name: &str) -> Nsid {
|
||||
@@ -139,7 +139,7 @@ fn test_at_uri(did: &Did, collection: &Nsid, rkey: &Rkey) -> AtUri {
|
||||
}
|
||||
|
||||
async fn seed_user(repos: &PostgresRepositories, did: &Did, handle: &Handle) -> Uuid {
|
||||
let commit_cid = CidLink::from(helpers::make_cid(did.as_str().as_bytes()).to_string());
|
||||
let commit_cid = CidLink::from_cid(&helpers::make_cid(did.as_str().as_bytes()));
|
||||
let input = tranquil_db_traits::CreatePasswordAccountInput {
|
||||
handle: handle.clone(),
|
||||
email: None,
|
||||
@@ -155,7 +155,7 @@ async fn seed_user(repos: &PostgresRepositories, did: &Did, handle: &Handle) ->
|
||||
encryption_version: 0,
|
||||
reserved_key_id: None,
|
||||
commit_cid,
|
||||
repo_rev: Tid::from("rev0".to_string()),
|
||||
repo_rev: Tid::new("3k2aaaaaaaaaa").expect("valid TID"),
|
||||
genesis_block_cids: vec![],
|
||||
invite_code: None,
|
||||
birthdate_pref: None,
|
||||
@@ -190,7 +190,7 @@ async fn seed_records(
|
||||
&collections,
|
||||
&rkeys,
|
||||
&cids,
|
||||
&Tid::from("rev1".to_string()),
|
||||
&Tid::new("3k2aaaaaaaaab").expect("valid TID"),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -1109,15 +1109,11 @@ async fn parity_invite_codes() {
|
||||
let _ = seed_repos(&f, &did, &handle).await;
|
||||
let code = tranquil_types::InviteCode::from(format!("parity-invite-{}", Uuid::new_v4()));
|
||||
|
||||
let pg_created =
|
||||
f.pg.infra
|
||||
.create_invite_code(&code, 5, Some(&did))
|
||||
.await
|
||||
.unwrap();
|
||||
let pg_created = f.pg.infra.create_invite_code(&code, 5, &did).await.unwrap();
|
||||
let store_created = f
|
||||
.store
|
||||
.infra
|
||||
.create_invite_code(&code, 5, Some(&did))
|
||||
.create_invite_code(&code, 5, &did)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(pg_created, store_created);
|
||||
@@ -1359,7 +1355,7 @@ async fn parity_signing_key_reservation() {
|
||||
let f = ParityFixture::new().await;
|
||||
let did = test_did("sigkey");
|
||||
let expires = chrono::Utc::now() + chrono::Duration::hours(1);
|
||||
let pub_key = Did::from(format!("did:key:z6Mk{}", Uuid::new_v4().simple()));
|
||||
let pub_key = Did::new(format!("did:key:z6Mk{}", Uuid::new_v4().simple())).expect("valid DID");
|
||||
let priv_bytes = vec![1u8, 2, 3, 4, 5, 6, 7, 8];
|
||||
|
||||
f.pg.infra
|
||||
@@ -1418,7 +1414,7 @@ async fn parity_repo_root_operations() {
|
||||
assert_eq!(pg_root, store_root);
|
||||
|
||||
let new_root = test_cid(99);
|
||||
let rev1 = Tid::from("rev1".to_string());
|
||||
let rev1 = Tid::new("3k2aaaaaaaaab").expect("valid TID");
|
||||
f.pg.repo
|
||||
.update_repo_root(pg_uid, &new_root, &rev1)
|
||||
.await
|
||||
@@ -1632,7 +1628,7 @@ async fn parity_prune_events_older_than() {
|
||||
blobs: None,
|
||||
blocks: None,
|
||||
prev_data_cid: None,
|
||||
rev: Some(Tid::from("rev0".to_string())),
|
||||
rev: Some(Tid::new("3k2aaaaaaaaaa").expect("valid TID")),
|
||||
};
|
||||
|
||||
let baseline = f.pg.repo.get_max_seq().await.unwrap();
|
||||
|
||||
@@ -1836,14 +1836,14 @@ impl<S: StorageIO + 'static> tranquil_db_traits::InfraRepository for MetastoreCl
|
||||
&self,
|
||||
code: &InviteCode,
|
||||
use_count: i32,
|
||||
for_account: Option<&Did>,
|
||||
for_account: &Did,
|
||||
) -> Result<bool, DbError> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
self.pool
|
||||
.send(MetastoreRequest::Infra(InfraRequest::CreateInviteCode {
|
||||
code: code.clone(),
|
||||
use_count,
|
||||
for_account: for_account.cloned(),
|
||||
for_account: for_account.clone(),
|
||||
tx,
|
||||
}))?;
|
||||
recv(rx).await
|
||||
@@ -1854,7 +1854,7 @@ impl<S: StorageIO + 'static> tranquil_db_traits::InfraRepository for MetastoreCl
|
||||
codes: &[InviteCode],
|
||||
use_count: i32,
|
||||
created_by_user: Uuid,
|
||||
for_account: Option<&Did>,
|
||||
for_account: &Did,
|
||||
) -> Result<(), DbError> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
self.pool.send(MetastoreRequest::Infra(
|
||||
@@ -1862,7 +1862,7 @@ impl<S: StorageIO + 'static> tranquil_db_traits::InfraRepository for MetastoreCl
|
||||
codes: codes.to_vec(),
|
||||
use_count,
|
||||
created_by_user,
|
||||
for_account: for_account.cloned(),
|
||||
for_account: for_account.clone(),
|
||||
tx,
|
||||
},
|
||||
))?;
|
||||
|
||||
@@ -1828,14 +1828,14 @@ pub enum InfraRequest {
|
||||
CreateInviteCode {
|
||||
code: InviteCode,
|
||||
use_count: i32,
|
||||
for_account: Option<Did>,
|
||||
for_account: Did,
|
||||
tx: Tx<bool>,
|
||||
},
|
||||
CreateInviteCodesBatch {
|
||||
codes: Vec<InviteCode>,
|
||||
use_count: i32,
|
||||
created_by_user: Uuid,
|
||||
for_account: Option<Did>,
|
||||
for_account: Did,
|
||||
tx: Tx<()>,
|
||||
},
|
||||
GetInviteCodeAvailableUses {
|
||||
@@ -3911,7 +3911,7 @@ fn dispatch_infra<S: StorageIO>(state: &HandlerState<S>, req: InfraRequest) {
|
||||
let result = state
|
||||
.metastore
|
||||
.infra_ops()
|
||||
.create_invite_code(&code, use_count, for_account.as_ref())
|
||||
.create_invite_code(&code, use_count, &for_account)
|
||||
.map_err(metastore_to_db);
|
||||
let _ = tx.send(result);
|
||||
}
|
||||
@@ -3925,7 +3925,7 @@ fn dispatch_infra<S: StorageIO>(state: &HandlerState<S>, req: InfraRequest) {
|
||||
let result = state
|
||||
.metastore
|
||||
.infra_ops()
|
||||
.create_invite_codes_batch(&codes, use_count, created_by_user, for_account.as_ref())
|
||||
.create_invite_codes_batch(&codes, use_count, created_by_user, &for_account)
|
||||
.map_err(metastore_to_db);
|
||||
let _ = tx.send(result);
|
||||
}
|
||||
@@ -6206,7 +6206,7 @@ mod tests {
|
||||
let owner = Did::new("did:plc:whelk").expect("valid DID");
|
||||
let whelk = InviteCode::new("whelk");
|
||||
|
||||
assert!(infra.create_invite_code(&squid, 1, Some(&owner)).unwrap());
|
||||
assert!(infra.create_invite_code(&squid, 1, &owner).unwrap());
|
||||
|
||||
infra.reserve_invite_code(&squid).unwrap();
|
||||
assert_eq!(
|
||||
@@ -6245,7 +6245,7 @@ mod tests {
|
||||
let owner = Did::new("did:plc:whelk").expect("valid DID");
|
||||
let whelk = InviteCode::new("whelk");
|
||||
|
||||
assert!(infra.create_invite_code(&squid, 1, Some(&owner)).unwrap());
|
||||
assert!(infra.create_invite_code(&squid, 1, &owner).unwrap());
|
||||
|
||||
infra.reserve_invite_code(&squid).unwrap();
|
||||
infra.refund_invite_code(&squid).unwrap();
|
||||
|
||||
@@ -362,7 +362,7 @@ impl InfraOps {
|
||||
&self,
|
||||
code: &InviteCode,
|
||||
use_count: i32,
|
||||
for_account: Option<&Did>,
|
||||
for_account: &Did,
|
||||
) -> Result<bool, MetastoreError> {
|
||||
let key = invite_code_key(code);
|
||||
let existing = self
|
||||
@@ -377,7 +377,7 @@ impl InfraOps {
|
||||
code: code.as_str().to_owned(),
|
||||
available_uses: use_count,
|
||||
disabled: false,
|
||||
for_account: for_account.map(|d| d.to_string()),
|
||||
for_account: Some(for_account.to_string()),
|
||||
created_by: None,
|
||||
created_at_ms: Utc::now().timestamp_millis(),
|
||||
};
|
||||
@@ -393,7 +393,7 @@ impl InfraOps {
|
||||
codes: &[InviteCode],
|
||||
use_count: i32,
|
||||
created_by_user: Uuid,
|
||||
for_account: Option<&Did>,
|
||||
for_account: &Did,
|
||||
) -> Result<(), MetastoreError> {
|
||||
let now_ms = Utc::now().timestamp_millis();
|
||||
let mut batch = self.db.batch();
|
||||
@@ -403,7 +403,7 @@ impl InfraOps {
|
||||
code: code.as_str().to_owned(),
|
||||
available_uses: use_count,
|
||||
disabled: false,
|
||||
for_account: for_account.map(|d| d.to_string()),
|
||||
for_account: Some(for_account.to_string()),
|
||||
created_by: Some(created_by_user),
|
||||
created_at_ms: now_ms,
|
||||
};
|
||||
@@ -1458,14 +1458,19 @@ impl InfraOps {
|
||||
SigningKeyValue::deserialize,
|
||||
"corrupt signing key",
|
||||
)?;
|
||||
Ok(val.map(|v| ReservedSigningKeyFull {
|
||||
id: v.id,
|
||||
did: v.did.and_then(|d| Did::new(d).ok()),
|
||||
public_key_did_key: Did::from(v.public_key_did_key),
|
||||
private_key_bytes: v.private_key_bytes,
|
||||
expires_at: DateTime::from_timestamp_millis(v.expires_at_ms).unwrap_or_default(),
|
||||
used_at: v.used_at_ms.and_then(DateTime::from_timestamp_millis),
|
||||
}))
|
||||
val.map(|v| {
|
||||
Ok(ReservedSigningKeyFull {
|
||||
id: v.id,
|
||||
did: v.did.and_then(|d| Did::new(d).ok()),
|
||||
public_key_did_key: Did::new(v.public_key_did_key).map_err(|_| {
|
||||
MetastoreError::CorruptData("corrupt reserved signing key public_key_did_key")
|
||||
})?,
|
||||
private_key_bytes: v.private_key_bytes,
|
||||
expires_at: DateTime::from_timestamp_millis(v.expires_at_ms).unwrap_or_default(),
|
||||
used_at: v.used_at_ms.and_then(DateTime::from_timestamp_millis),
|
||||
})
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
pub fn get_plc_tokens_for_user(
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
-- The old insert path wrote for_account through without validating it
|
||||
-- so an older row can contain any string at all
|
||||
-- most often a handle or the literal 'admin' the column defaulted to
|
||||
-- where the read path warns and drops whatever the Did newtype won't parse
|
||||
-- so an unconverted row comes back with no for_account at all.
|
||||
-- The first statement resolves the bare handles that still match a user
|
||||
-- and the second covers every 'admin' row, since created_by_user is NOT NULL.
|
||||
-- Nothing else converts
|
||||
-- so a prefixed handle, a handle whose user has renamed since,
|
||||
-- and anything that was never an identifier all stay as they are.
|
||||
UPDATE invite_codes ic
|
||||
SET for_account = u.did
|
||||
FROM users u
|
||||
WHERE LOWER(u.handle) = LOWER(ic.for_account)
|
||||
AND ic.for_account NOT LIKE 'did:%';
|
||||
|
||||
UPDATE invite_codes ic
|
||||
SET for_account = u.did
|
||||
FROM users u
|
||||
WHERE u.id = ic.created_by_user
|
||||
AND ic.for_account = 'admin';
|
||||
Reference in New Issue
Block a user