diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 1da1471..a932a59 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -101,6 +101,14 @@ paths: /api/v1/accounts/identity_proof: get: summary: Get unsigned data for identity proof. + parameters: + - name: did + in: query + description: Identifier (DID) + required: true + schema: + type: string + example: 'did:pkh:eip155:1:0xb9c5714089478a327f09197987f16f9e5d936e8a' responses: 200: description: Successful operation @@ -113,8 +121,8 @@ paths: description: Identity claim serialized as compact JSON. type: string example: '{"id":"https://example.com/users/1","ownerOf":"did:pkh:eip155:1:0xb9c5714089478a327f09197987f16f9e5d936e8a"}' - 403: - description: User's wallet address is not known + 400: + description: Invalid request parameters post: summary: Submit identity proof. requestBody: @@ -123,6 +131,10 @@ paths: schema: type: object properties: + did: + description: Identifier (DID) + type: string + example: 'did:pkh:eip155:1:0xb9c5714089478a327f09197987f16f9e5d936e8a' signature: description: Signature value. type: string @@ -135,9 +147,7 @@ paths: schema: $ref: '#/components/schemas/Account' 400: - description: Invalid signature. - 403: - description: User's wallet address is not known + description: Invalid proof data. /api/v1/accounts/authorize_subscription: get: summary: Get authorization for setting up paid subscription. diff --git a/src/mastodon_api/accounts/types.rs b/src/mastodon_api/accounts/types.rs index 9d2c01b..57aa86c 100644 --- a/src/mastodon_api/accounts/types.rs +++ b/src/mastodon_api/accounts/types.rs @@ -235,6 +235,11 @@ impl AccountUpdateData { } } +#[derive(Deserialize)] +pub struct IdentityClaimQueryParams { + pub did: String, +} + #[derive(Serialize)] pub struct IdentityClaim { pub claim: String, @@ -242,6 +247,7 @@ pub struct IdentityClaim { #[derive(Deserialize)] pub struct IdentityProofData { + pub did: String, pub signature: String, } diff --git a/src/mastodon_api/accounts/views.rs b/src/mastodon_api/accounts/views.rs index 98049e0..60237d0 100644 --- a/src/mastodon_api/accounts/views.rs +++ b/src/mastodon_api/accounts/views.rs @@ -72,6 +72,7 @@ use super::types::{ FollowData, FollowListQueryParams, IdentityClaim, + IdentityClaimQueryParams, IdentityProofData, RelationshipQueryParams, SearchDidQueryParams, @@ -224,13 +225,13 @@ async fn get_identity_claim( auth: BearerAuth, config: web::Data, db_pool: web::Data, + query_params: web::Query, ) -> Result { let db_client = &**get_database_client(&db_pool).await?; let current_user = get_current_user(db_client, auth.token()).await?; let actor_id = current_user.profile.actor_id(&config.instance_url()); - let wallet_address = current_user.wallet_address.as_ref() - .ok_or(HttpError::PermissionError)?; - let did = DidPkh::from_address(&config.default_currency(), wallet_address); + let did = query_params.did.parse::() + .map_err(|_| ValidationError("invalid DID"))?; let claim = create_identity_claim(&actor_id, &did) .map_err(|_| HttpError::InternalError)?; let response = IdentityClaim { claim }; @@ -247,9 +248,18 @@ async fn create_identity_proof( let db_client = &**get_database_client(&db_pool).await?; let mut current_user = get_current_user(db_client, auth.token()).await?; let actor_id = current_user.profile.actor_id(&config.instance_url()); - let wallet_address = current_user.wallet_address.as_ref() - .ok_or(HttpError::PermissionError)?; - let did = DidPkh::from_address(&config.default_currency(), wallet_address); + let did = proof_data.did.parse::() + .map_err(|_| ValidationError("invalid DID"))?; + if did.currency() != Some(config.default_currency()) { + return Err(ValidationError("unsupported chain ID").into()); + }; + let maybe_public_address = + current_user.public_wallet_address(&config.default_currency()); + if let Some(address) = maybe_public_address { + if did.address != address { + return Err(ValidationError("DID doesn't match current identity").into()); + }; + }; verify_identity_proof( &actor_id, &did, diff --git a/src/models/users/types.rs b/src/models/users/types.rs index b989369..a5eacd1 100644 --- a/src/models/users/types.rs +++ b/src/models/users/types.rs @@ -48,7 +48,8 @@ impl User { /// Returns wallet address if it is verified pub fn public_wallet_address(&self, currency: &Currency) -> Option { for proof in self.profile.identity_proofs.clone().into_inner() { - // Return first match (it's safe if user is local) + // Return the first matching address, because only + // one proof per currency is allowed. if let Some(ref address_currency) = proof.issuer.currency() { if address_currency == currency { return Some(proof.issuer.address);