register logic (bricked) user management !! omikron con wait for
response method !!
This commit is contained in:
parent
d289346c63
commit
0d51dc9ac7
16 changed files with 361 additions and 260 deletions
|
|
@ -1,158 +0,0 @@
|
|||
use crate::CONFIG;
|
||||
use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes};
|
||||
use crate::users::user_profile::UserProfile;
|
||||
use json::JsonValue;
|
||||
use json::number::Number;
|
||||
use reqwest::header::CONTENT_TYPE;
|
||||
use reqwest::{Client, Response};
|
||||
use std::time::Duration;
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AuthUser {
|
||||
pub created_at: i64,
|
||||
pub username: String,
|
||||
pub display: String,
|
||||
pub avatar: String,
|
||||
pub about: String,
|
||||
pub status: String,
|
||||
pub public_key: String,
|
||||
pub sub_level: i32,
|
||||
pub sub_end: i32,
|
||||
}
|
||||
|
||||
fn client() -> Client {
|
||||
Client::builder()
|
||||
.connect_timeout(Duration::from_secs(100))
|
||||
.timeout(Duration::from_secs(150))
|
||||
.build()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub async fn unregister_user(user_id: i64, reset_token: &str) -> Option<bool> {
|
||||
let url = format!("https:/auth.tensamin.net/api/delete/{}", user_id);
|
||||
let client = client();
|
||||
|
||||
let mut payload = JsonValue::new_object();
|
||||
payload["reset_token"] = reset_token.into();
|
||||
|
||||
let res = client
|
||||
.post(&url)
|
||||
.header(CONTENT_TYPE, "application/json")
|
||||
.body(payload.dump())
|
||||
.send()
|
||||
.await
|
||||
.ok()?;
|
||||
let json = res.text().await.ok()?;
|
||||
let cv = CommunicationValue::from_json(&json);
|
||||
Option::from(cv.is_type(CommunicationType::success))
|
||||
}
|
||||
|
||||
pub async fn get_user(user_id: i64) -> Option<AuthUser> {
|
||||
let url = format!("https://auth.tensamin.net/api/get/{}", user_id);
|
||||
let client = client();
|
||||
let res = client.get(&url).send().await.ok()?;
|
||||
let json = res.text().await.ok()?;
|
||||
|
||||
let cv = CommunicationValue::from_json(&json);
|
||||
if cv.comm_type != CommunicationType::success {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(AuthUser {
|
||||
created_at: cv
|
||||
.get_data(DataTypes::created_at)
|
||||
.unwrap()
|
||||
.to_string()
|
||||
.parse::<i64>()
|
||||
.unwrap_or(-1),
|
||||
username: cv.get_data(DataTypes::username).unwrap().to_string(),
|
||||
display: cv.get_data(DataTypes::display).unwrap().to_string(),
|
||||
avatar: cv.get_data(DataTypes::avatar).unwrap().to_string(),
|
||||
about: cv.get_data(DataTypes::about).unwrap().to_string(),
|
||||
status: cv.get_data(DataTypes::status).unwrap().to_string(),
|
||||
public_key: cv.get_data(DataTypes::public_key).unwrap().to_string(),
|
||||
sub_level: cv
|
||||
.get_data(DataTypes::sub_level)
|
||||
.unwrap()
|
||||
.to_string()
|
||||
.parse::<i32>()
|
||||
.unwrap_or(-1),
|
||||
sub_end: cv
|
||||
.get_data(DataTypes::sub_end)
|
||||
.unwrap()
|
||||
.to_string()
|
||||
.parse::<i32>()
|
||||
.unwrap_or(-1),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn get_register() -> Option<i64> {
|
||||
let url = "https://auth.tensamin.net/api/register/init".to_string();
|
||||
let client = client();
|
||||
let res = client.get(&url).send().await.ok()?;
|
||||
let json = res.text().await.ok()?;
|
||||
|
||||
let cv = CommunicationValue::from_json(&json);
|
||||
cv.get_data(DataTypes::user_id)
|
||||
.unwrap_or(&json::JsonValue::Number(Number::from(0)))
|
||||
.as_i64()
|
||||
}
|
||||
|
||||
pub async fn complete_register(user_profile: &UserProfile, iota_id: &str) -> bool {
|
||||
let url = "https://auth.tensamin.net/api/register/complete";
|
||||
let client = client();
|
||||
|
||||
let mut payload = JsonValue::new_object();
|
||||
payload["id"] = user_profile.user_id.into();
|
||||
payload["public_key"] = user_profile.public_key.clone().into();
|
||||
payload["private_key_hash"] = user_profile.private_key_hash.clone().into();
|
||||
payload["username"] = user_profile.username.clone().into();
|
||||
payload["iota_id"] = iota_id.into();
|
||||
payload["reset_token"] = user_profile.reset_token.clone().into();
|
||||
|
||||
let res = client
|
||||
.post(url)
|
||||
.header(CONTENT_TYPE, "application/json")
|
||||
.body(payload.to_string())
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let body = res.text().await.unwrap();
|
||||
|
||||
CommunicationValue::from_json(&body).is_type(CommunicationType::success)
|
||||
}
|
||||
|
||||
pub async fn migrate_user(user_profile: &mut UserProfile) -> bool {
|
||||
let url = format!(
|
||||
"https://auth.tensamin.net/api/change/iota-id/{}",
|
||||
user_profile.user_id
|
||||
);
|
||||
let client = client();
|
||||
|
||||
let mut payload = JsonValue::new_object();
|
||||
payload["iota_id"] = JsonValue::String(CONFIG.read().await.get_iota_id().to_string());
|
||||
payload["reset_token"] = user_profile.reset_token.clone().into();
|
||||
payload["new_token"] = user_profile.randomize_reset_token().into();
|
||||
|
||||
let res = client
|
||||
.post(url)
|
||||
.header(CONTENT_TYPE, "application/json")
|
||||
.body(payload.dump())
|
||||
.send()
|
||||
.await;
|
||||
|
||||
match res {
|
||||
Ok(resp) => handle_response(resp).await,
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_response(resp: Response) -> bool {
|
||||
match resp.text().await {
|
||||
Ok(text) => {
|
||||
let cv = CommunicationValue::from_json(&text.to_string());
|
||||
cv.comm_type == CommunicationType::success
|
||||
}
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
18
src/auth/auth_user.rs
Normal file
18
src/auth/auth_user.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct AuthUser {
|
||||
pub id: i64,
|
||||
pub username: String,
|
||||
pub password_hash: String,
|
||||
pub public_key: String,
|
||||
}
|
||||
|
||||
impl AuthUser {
|
||||
pub fn new(id: i64, username: String, password_hash: String, public_key: String) -> Self {
|
||||
AuthUser {
|
||||
id,
|
||||
username,
|
||||
password_hash,
|
||||
public_key,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
use aes_gcm::{
|
||||
Aes256Gcm, Nonce,
|
||||
aead::{Aead, KeyInit, OsRng},
|
||||
};
|
||||
use base64::{Engine as _, engine::general_purpose::STANDARD};
|
||||
use rand_core::RngCore;
|
||||
use sha2::{Digest, Sha256};
|
||||
use x448::{PublicKey, Secret, SharedSecret};
|
||||
|
||||
/// Errors for crypto operations
|
||||
#[derive(Debug)]
|
||||
pub enum CryptoError {
|
||||
Base64Decode(base64::DecodeError),
|
||||
InvalidKey,
|
||||
AgreementError,
|
||||
EncryptionError(aes_gcm::Error),
|
||||
DecryptionError(aes_gcm::Error),
|
||||
}
|
||||
|
||||
impl From<base64::DecodeError> for CryptoError {
|
||||
fn from(err: base64::DecodeError) -> Self {
|
||||
CryptoError::Base64Decode(err)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct KeyPair {
|
||||
pub secret: Secret,
|
||||
pub public: PublicKey,
|
||||
}
|
||||
|
||||
pub fn generate_keypair() -> KeyPair {
|
||||
let mut buf = [0u8; 56];
|
||||
let mut rng = OsRng;
|
||||
rng.fill_bytes(&mut buf);
|
||||
let secret = Secret::from_bytes(&buf).unwrap();
|
||||
let public = PublicKey::from(&secret);
|
||||
KeyPair { secret, public }
|
||||
}
|
||||
|
||||
pub fn public_key_to_base64(pubkey: &PublicKey) -> String {
|
||||
STANDARD.encode(pubkey.as_bytes().as_ref())
|
||||
}
|
||||
|
||||
pub fn secret_key_to_base64(secret: &Secret) -> String {
|
||||
STANDARD.encode(secret.as_bytes().as_ref())
|
||||
}
|
||||
|
||||
pub fn load_public_key(base64_pub: &str) -> Option<PublicKey> {
|
||||
let bytes = STANDARD.decode(base64_pub).unwrap();
|
||||
PublicKey::from_bytes(&bytes)
|
||||
}
|
||||
|
||||
pub fn load_secret_key(base64_secret: &str) -> Option<Secret> {
|
||||
let bytes = STANDARD.decode(base64_secret).unwrap();
|
||||
Secret::from_bytes(&bytes)
|
||||
}
|
||||
|
||||
fn derive_aes_key(shared: &SharedSecret) -> [u8; 32] {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(shared.as_bytes());
|
||||
let result = hasher.finalize();
|
||||
let mut key = [0u8; 32];
|
||||
key.copy_from_slice(&result[..32]);
|
||||
key
|
||||
}
|
||||
|
||||
pub fn encrypt(
|
||||
base64_secret: &str,
|
||||
base64_peer_pub: &str,
|
||||
plaintext: &str,
|
||||
) -> Result<String, CryptoError> {
|
||||
let secret = load_secret_key(base64_secret).unwrap();
|
||||
let peer_pub = load_public_key(base64_peer_pub).unwrap();
|
||||
let shared = secret
|
||||
.to_diffie_hellman(&peer_pub)
|
||||
.ok_or(CryptoError::AgreementError)?;
|
||||
let key_bytes = derive_aes_key(&shared);
|
||||
let cipher = Aes256Gcm::new_from_slice(&key_bytes).expect("Key length should be correct");
|
||||
let mut nonce_bytes = [0u8; 12];
|
||||
OsRng.fill_bytes(&mut nonce_bytes);
|
||||
let nonce = Nonce::from_slice(&nonce_bytes);
|
||||
let ciphertext = cipher
|
||||
.encrypt(nonce, plaintext.as_bytes())
|
||||
.map_err(CryptoError::EncryptionError)?;
|
||||
// prefix nonce to ciphertext
|
||||
let mut out = Vec::with_capacity(nonce_bytes.len() + ciphertext.len());
|
||||
out.extend_from_slice(&nonce_bytes);
|
||||
out.extend_from_slice(&ciphertext);
|
||||
Ok(STANDARD.encode(&out))
|
||||
}
|
||||
|
||||
pub fn decrypt(
|
||||
base64_secret: &str,
|
||||
base64_peer_pub: &str,
|
||||
encrypted_base64: &str,
|
||||
) -> Result<String, CryptoError> {
|
||||
let secret = load_secret_key(base64_secret).unwrap();
|
||||
let peer_pub = load_public_key(base64_peer_pub).unwrap();
|
||||
let shared = secret
|
||||
.to_diffie_hellman(&peer_pub)
|
||||
.ok_or(CryptoError::AgreementError)?;
|
||||
let key_bytes = derive_aes_key(&shared);
|
||||
let cipher = Aes256Gcm::new_from_slice(&key_bytes).expect("Key length should be correct");
|
||||
|
||||
let encrypted = STANDARD.decode(encrypted_base64)?;
|
||||
if encrypted.len() < 12 {
|
||||
return Err(CryptoError::DecryptionError(aes_gcm::Error));
|
||||
}
|
||||
let nonce_bytes = &encrypted[..12];
|
||||
let ciphertext = &encrypted[12..];
|
||||
let nonce = Nonce::from_slice(nonce_bytes);
|
||||
let plaintext_bytes = cipher
|
||||
.decrypt(nonce, ciphertext)
|
||||
.map_err(CryptoError::DecryptionError)?;
|
||||
let plaintext = String::from_utf8(plaintext_bytes)
|
||||
.map_err(|_| CryptoError::DecryptionError(aes_gcm::Error))?;
|
||||
Ok(plaintext)
|
||||
}
|
||||
|
||||
pub fn hash_it(input: &str) -> Vec<u8> {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(input.as_bytes());
|
||||
hasher.finalize().to_vec()
|
||||
}
|
||||
|
||||
pub fn hex_hash(input: &str) -> String {
|
||||
let digest = hash_it(input);
|
||||
digest.iter().map(|b| format!("{:02x}", b)).collect()
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
use json::JsonValue;
|
||||
|
||||
use crate::util::file_util::load_file;
|
||||
|
||||
// NOT USED AT MOMENT
|
||||
pub fn is_private_key_valid(user_id: &i64, key_hash: &str) -> bool {
|
||||
let file_contents = load_file("", "users.json");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,2 @@
|
|||
pub mod auth_connector;
|
||||
pub mod crypto_helper;
|
||||
pub mod auth_user;
|
||||
pub mod local_auth;
|
||||
|
|
|
|||
Loading…
Reference in a new issue