Allow users of password auth to use subscriptions

This commit is contained in:
silverpill 2022-08-15 19:25:31 +00:00
parent 596871e6e3
commit a80c11b99c
5 changed files with 26 additions and 27 deletions

View file

@ -159,7 +159,7 @@ paths:
description: User's wallet address is not known or not verified description: User's wallet address is not known or not verified
418: 418:
description: Blockchain integration is not enabled description: Blockchain integration is not enabled
/api/v1/accounts/subscription_enabled: /api/v1/accounts/subscriptions_enabled:
post: post:
summary: Notify server about subscription setup summary: Notify server about subscription setup
responses: responses:
@ -792,11 +792,6 @@ components:
type: array type: array
items: items:
$ref: '#/components/schemas/Field' $ref: '#/components/schemas/Field'
wallet_address:
description: Ethereum wallet address (visibile only to the current user).
type: string
nullable: true
example: '0xd8da6bf...'
subscription_page_url: subscription_page_url:
description: Subscription page URL description: Subscription page URL
type: string type: string

View file

@ -57,7 +57,6 @@ pub struct Account {
pub source: Option<Source>, pub source: Option<Source>,
pub wallet_address: Option<String>,
pub subscription_page_url: Option<String>, pub subscription_page_url: Option<String>,
} }
@ -122,7 +121,6 @@ impl Account {
following_count: profile.following_count, following_count: profile.following_count,
statuses_count: profile.post_count, statuses_count: profile.post_count,
source: None, source: None,
wallet_address: None,
subscription_page_url, subscription_page_url,
} }
} }
@ -140,11 +138,8 @@ impl Account {
note: user.profile.bio_source.clone(), note: user.profile.bio_source.clone(),
fields: fields_sources, fields: fields_sources,
}; };
// Expose login address only if it's verified
let wallet_address = user.public_wallet_address();
let mut account = Self::from_profile(user.profile, instance_url); let mut account = Self::from_profile(user.profile, instance_url);
account.source = Some(source); account.source = Some(source);
account.wallet_address = wallet_address;
account account
} }
} }
@ -388,7 +383,6 @@ mod tests {
format!("{}/media/test", INSTANCE_URL), format!("{}/media/test", INSTANCE_URL),
); );
assert!(account.source.is_none()); assert!(account.source.is_none());
assert!(account.wallet_address.is_none());
} }
#[test] #[test]
@ -410,6 +404,5 @@ mod tests {
account.source.unwrap().note.unwrap(), account.source.unwrap().note.unwrap(),
bio_source, bio_source,
); );
assert_eq!(account.wallet_address, None);
} }
} }

View file

@ -300,9 +300,11 @@ async fn authorize_subscription(
.ok_or(HttpError::NotSupported)? .ok_or(HttpError::NotSupported)?
.ethereum_config() .ethereum_config()
.ok_or(HttpError::NotSupported)?; .ok_or(HttpError::NotSupported)?;
// Wallet address must be public, because subscribers should be able // The user must have a public wallet address,
// because subscribers should be able
// to verify that payments are actually sent to the recipient. // to verify that payments are actually sent to the recipient.
let wallet_address = current_user.public_wallet_address() let wallet_address = current_user
.public_wallet_address(&config.default_currency())
.ok_or(HttpError::PermissionError)?; .ok_or(HttpError::PermissionError)?;
let signature = create_subscription_signature( let signature = create_subscription_signature(
ethereum_config, ethereum_config,
@ -323,7 +325,8 @@ async fn subscriptions_enabled(
let mut current_user = get_current_user(db_client, auth.token()).await?; let mut current_user = get_current_user(db_client, auth.token()).await?;
let contract_set = maybe_blockchain.as_ref().as_ref() let contract_set = maybe_blockchain.as_ref().as_ref()
.ok_or(HttpError::NotSupported)?; .ok_or(HttpError::NotSupported)?;
let wallet_address = current_user.public_wallet_address() let wallet_address = current_user
.public_wallet_address(&config.default_currency())
.ok_or(HttpError::PermissionError)?; .ok_or(HttpError::PermissionError)?;
let is_registered = is_registered_recipient(contract_set, &wallet_address) let is_registered = is_registered_recipient(contract_set, &wallet_address)
.await.map_err(|_| HttpError::InternalError)?; .await.map_err(|_| HttpError::InternalError)?;

View file

@ -429,8 +429,9 @@ async fn get_signature(
.ok_or(HttpError::NotSupported)? .ok_or(HttpError::NotSupported)?
.ethereum_config() .ethereum_config()
.ok_or(HttpError::NotSupported)?; .ok_or(HttpError::NotSupported)?;
// Wallet address must be public because minting exposes it // User must have a public wallet address
let wallet_address = current_user.public_wallet_address() let wallet_address = current_user
.public_wallet_address(&config.default_currency())
.ok_or(HttpError::PermissionError)?; .ok_or(HttpError::PermissionError)?;
let post = get_post_by_id(db_client, &status_id).await?; let post = get_post_by_id(db_client, &status_id).await?;
if post.author.id != current_user.id || !post.is_public() || post.repost_of_id.is_some() { if post.author.id != current_user.id || !post.is_public() || post.repost_of_id.is_some() {

View file

@ -5,6 +5,7 @@ use uuid::Uuid;
use crate::errors::ValidationError; use crate::errors::ValidationError;
use crate::models::profiles::types::DbActorProfile; use crate::models::profiles::types::DbActorProfile;
use crate::utils::currencies::Currency;
#[allow(dead_code)] #[allow(dead_code)]
#[derive(FromSql)] #[derive(FromSql)]
@ -23,7 +24,7 @@ pub struct DbUser {
#[cfg_attr(test, derive(Default))] #[cfg_attr(test, derive(Default))]
pub struct User { pub struct User {
pub id: Uuid, pub id: Uuid,
pub wallet_address: Option<String>, pub wallet_address: Option<String>, // login address
pub password_hash: Option<String>, pub password_hash: Option<String>,
pub private_key: String, pub private_key: String,
pub profile: DbActorProfile, pub profile: DbActorProfile,
@ -44,12 +45,17 @@ impl User {
} }
} }
/// Returns login address if it is verified /// Returns wallet address if it is verified
pub fn public_wallet_address(&self) -> Option<String> { pub fn public_wallet_address(&self, currency: &Currency) -> Option<String> {
let wallet_address = self.wallet_address.clone()?; for proof in self.profile.identity_proofs.clone().into_inner() {
let is_verified = self.profile.identity_proofs.clone().into_inner().iter() // Return first match (it's safe if user is local)
.any(|proof| proof.issuer.address == wallet_address); if let Some(ref address_currency) = proof.issuer.currency() {
if is_verified { Some(wallet_address) } else { None } if address_currency == currency {
return Some(proof.issuer.address);
};
};
};
None
} }
} }
@ -76,12 +82,13 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn test_public_wallet_address_hidden_by_default() { fn test_public_wallet_address_login_address_not_exposed() {
let user = User { let user = User {
wallet_address: Some("0x1234".to_string()), wallet_address: Some("0x1234".to_string()),
..Default::default() ..Default::default()
}; };
assert_eq!(user.public_wallet_address(), None); let ethereum = Currency::Ethereum;
assert_eq!(user.public_wallet_address(&ethereum), None);
} }
#[test] #[test]