Don't require wallet address during registration

This commit is contained in:
silverpill 2021-12-24 17:46:01 +00:00
parent c628885c9e
commit 81a260e691
9 changed files with 51 additions and 21 deletions

View file

@ -18,10 +18,19 @@ paths:
type: string type: string
enum: enum:
- password - password
- ethereum
username: username:
description: User name (required if grant type is "password").
type: string type: string
wallet_address:
description: Ethereum wallet address (required if grant type is "ethereum").
type: string
example: null
password: password:
type: string type: string
required:
- grant_type
- password
responses: responses:
200: 200:
description: Successful operation description: Successful operation
@ -59,7 +68,7 @@ paths:
description: The password to be used for login. description: The password to be used for login.
type: string type: string
wallet_address: wallet_address:
description: Ethereum wallet address description: Ethereum wallet address.
type: string type: string
example: '0xd8da6bf...' example: '0xd8da6bf...'
invite_code: invite_code:
@ -69,7 +78,6 @@ paths:
required: required:
- username - username
- password - password
- wallet_address
responses: responses:
201: 201:
description: Successful operation description: Successful operation
@ -193,7 +201,7 @@ paths:
type: string type: string
example: '6a5cb313907cd3...' example: '6a5cb313907cd3...'
403: 403:
description: Post does not belong to user or is not public description: Post does not belong to user or is not public or user's wallet address is not known
404: 404:
description: Post not found description: Post not found
418: 418:
@ -295,6 +303,10 @@ components:
description: The Webfinger account URI. Equal to username for local actors, or username@domain for remote actors. description: The Webfinger account URI. Equal to username for local actors, or username@domain for remote actors.
type: string type: string
example: user@example.com example: user@example.com
wallet_address:
description: Ethereum wallet address.
type: string
example: '0xd8da6bf...'
Status: Status:
type: object type: object
properties: properties:

View file

@ -0,0 +1 @@
ALTER TABLE user_account ALTER COLUMN wallet_address DROP NOT NULL;

View file

@ -22,7 +22,7 @@ CREATE TABLE user_invite_code (
CREATE TABLE user_account ( CREATE TABLE user_account (
id UUID PRIMARY KEY REFERENCES actor_profile (id) ON DELETE CASCADE, id UUID PRIMARY KEY REFERENCES actor_profile (id) ON DELETE CASCADE,
wallet_address VARCHAR(100) UNIQUE NOT NULL, wallet_address VARCHAR(100) UNIQUE,
password_hash VARCHAR(200) NOT NULL, password_hash VARCHAR(200) NOT NULL,
private_key TEXT NOT NULL, private_key TEXT NOT NULL,
invite_code VARCHAR(100) UNIQUE REFERENCES user_invite_code (code) ON DELETE SET NULL, invite_code VARCHAR(100) UNIQUE REFERENCES user_invite_code (code) ON DELETE SET NULL,

View file

@ -87,7 +87,7 @@ impl Account {
}; };
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 = Some(user.wallet_address); account.wallet_address = user.wallet_address;
account account
} }
} }
@ -98,7 +98,7 @@ pub struct AccountCreateData {
username: String, username: String,
password: String, password: String,
wallet_address: String, wallet_address: Option<String>,
invite_code: Option<String>, invite_code: Option<String>,
} }
@ -204,7 +204,7 @@ mod tests {
..Default::default() ..Default::default()
}; };
let user = User { let user = User {
wallet_address: wallet_address.to_string(), wallet_address: Some(wallet_address.to_string()),
profile, profile,
..Default::default() ..Default::default()
}; };

View file

@ -58,7 +58,10 @@ pub async fn create_account(
} }
} }
if config.ethereum_contract.is_some() { if config.ethereum_contract.is_some() {
let is_allowed = is_allowed_user(&config, &user_data.wallet_address).await // Wallet address is required only if ethereum integration is enabled
let wallet_address = user_data.wallet_address.as_ref()
.ok_or(ValidationError("wallet address is required"))?;
let is_allowed = is_allowed_user(&config, wallet_address).await
.map_err(|_| HttpError::InternalError)?; .map_err(|_| HttpError::InternalError)?;
if !is_allowed { if !is_allowed {
return Err(ValidationError("not allowed to sign up").into()); return Err(ValidationError("not allowed to sign up").into());

View file

@ -3,7 +3,8 @@ use serde::{Deserialize, Serialize};
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct TokenRequest { pub struct TokenRequest {
pub grant_type: String, pub grant_type: String,
pub username: String, // wallet address pub username: Option<String>,
pub wallet_address: Option<String>,
pub password: String, pub password: String,
} }

View file

@ -4,7 +4,10 @@ use chrono::{Duration, Utc};
use crate::database::{Pool, get_database_client}; use crate::database::{Pool, get_database_client};
use crate::errors::{HttpError, ValidationError}; use crate::errors::{HttpError, ValidationError};
use crate::models::oauth::queries::save_oauth_token; use crate::models::oauth::queries::save_oauth_token;
use crate::models::users::queries::get_user_by_wallet_address; use crate::models::users::queries::{
get_user_by_name,
get_user_by_wallet_address,
};
use crate::utils::crypto::verify_password; use crate::utils::crypto::verify_password;
use super::types::{TokenRequest, TokenResponse}; use super::types::{TokenRequest, TokenResponse};
use super::utils::generate_access_token; use super::utils::generate_access_token;
@ -18,14 +21,22 @@ async fn token_view(
db_pool: web::Data<Pool>, db_pool: web::Data<Pool>,
request_data: web::Json<TokenRequest>, request_data: web::Json<TokenRequest>,
) -> Result<HttpResponse, HttpError> { ) -> Result<HttpResponse, HttpError> {
if &request_data.grant_type != "password" {
return Err(ValidationError("unsupported grant type").into());
}
let db_client = &**get_database_client(&db_pool).await?; let db_client = &**get_database_client(&db_pool).await?;
let user = get_user_by_wallet_address( let user = match request_data.grant_type.as_str() {
db_client, "password" => {
&request_data.username, let username = request_data.username.as_ref()
).await?; .ok_or(ValidationError("username is required"))?;
get_user_by_name(db_client, username).await?
},
"ethereum" => {
let wallet_address = request_data.wallet_address.as_ref()
.ok_or(ValidationError("wallet address is required"))?;
get_user_by_wallet_address(db_client, wallet_address).await?
},
_ => {
return Err(ValidationError("unsupported grant type").into());
},
};
let password_correct = verify_password( let password_correct = verify_password(
&user.password_hash, &user.password_hash,
&request_data.password, &request_data.password,

View file

@ -477,6 +477,8 @@ async fn get_signature(
let current_user = get_current_user(db_client, auth.token()).await?; let current_user = get_current_user(db_client, auth.token()).await?;
let contract_config = config.ethereum_contract.as_ref() let contract_config = config.ethereum_contract.as_ref()
.ok_or(HttpError::NotSupported)?; .ok_or(HttpError::NotSupported)?;
let wallet_address = current_user.wallet_address
.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() { if post.author.id != current_user.id || !post.is_public() {
// Users can only tokenize their own public posts // Users can only tokenize their own public posts
@ -488,7 +490,7 @@ async fn get_signature(
let token_uri = get_ipfs_url(&ipfs_cid); let token_uri = get_ipfs_url(&ipfs_cid);
let signature = create_mint_signature( let signature = create_mint_signature(
contract_config, contract_config,
&current_user.wallet_address, &wallet_address,
&token_uri, &token_uri,
).map_err(|_| HttpError::InternalError)?; ).map_err(|_| HttpError::InternalError)?;
Ok(HttpResponse::Ok().json(signature)) Ok(HttpResponse::Ok().json(signature))

View file

@ -11,7 +11,7 @@ use crate::models::profiles::types::DbActorProfile;
#[postgres(name = "user_account")] #[postgres(name = "user_account")]
pub struct DbUser { pub struct DbUser {
pub id: Uuid, pub id: Uuid,
pub wallet_address: String, pub wallet_address: Option<String>,
pub password_hash: String, pub password_hash: String,
pub private_key: String, pub private_key: String,
pub invite_code: Option<String>, pub invite_code: Option<String>,
@ -23,7 +23,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: String, pub wallet_address: Option<String>,
pub password_hash: String, pub password_hash: String,
pub private_key: String, pub private_key: String,
pub profile: DbActorProfile, pub profile: DbActorProfile,
@ -49,7 +49,7 @@ impl User {
pub struct UserCreateData { pub struct UserCreateData {
pub username: String, pub username: String,
pub password: String, pub password: String,
pub wallet_address: String, pub wallet_address: Option<String>,
pub invite_code: Option<String>, pub invite_code: Option<String>,
} }