diff --git a/Cargo.toml b/Cargo.toml index 31df30978437c454ed05fa8cf42921b357fe541d..2ce000d97ce693761931ee5b5584fa54798584f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,9 @@ async-channel = "1.8.0" uuid = { version = "1.3.0", features = ["v4"]} rpm-infra ="0.0.3" dns-lookup = {version="1.0.8"} +#sha1 is used in openpgp signature generation sha1 = "0.10.5" +sha2 = "0.10.6" bincode = "2.0.0-rc.2" secstr = "0.5.1" openssl = "0.10.45" diff --git a/src/application/user.rs b/src/application/user.rs index 1fdc294afc5b4011e05740607c87cb2139192c4d..b873db87a164bce7961fa05afc1727566e0e7812 100644 --- a/src/application/user.rs +++ b/src/application/user.rs @@ -41,7 +41,7 @@ use crate::util::key::{generate_api_token}; pub trait UserService: Send + Sync{ async fn get_token(&self, u: &UserIdentity) -> Result>; async fn get_valid_token(&self, token: &str) -> Result; - async fn save(&self, u: &User) -> Result; + async fn save(&self, u: User) -> Result; async fn get_user_by_id(&self, id: i32) -> Result; async fn get_by_email(&self, email: &str) -> Result; async fn generate_token(&self, u: &UserIdentity, token: TokenDTO) -> Result; @@ -166,7 +166,7 @@ where Err(Error::TokenExpiredError(token.to_string())) } - async fn save(&self, u: &User) -> Result { + async fn save(&self, u: User) -> Result { return self.user_repository.create(u).await } @@ -181,7 +181,8 @@ where async fn generate_token(&self, u: &UserIdentity, token: TokenDTO) -> Result { let real_token = generate_api_token(); let created = Token::new(token.id, u.id, token.description, real_token)?; - self.token_repository.create(&created).await?; + self.token_repository.create(created.clone()).await?; + //return token with un-hashed value Ok(created) } @@ -201,7 +202,7 @@ where match self.get_access_token(&code).await { Ok(token_response) => { let id: User = User::new(self.get_user_info(&token_response.access_token).await?.email)?; - return self.user_repository.create(&id).await + return self.user_repository.create(id).await } Err(err) => { Err(Error::AuthError(format!("failed to get access token {}", err))) diff --git a/src/control_admin_entrypoint.rs b/src/control_admin_entrypoint.rs index 99776d5c57335b4a592b2db3c4b99aa4898250d8..5993714848a4c07b25b36604a03e6866aac0742c 100644 --- a/src/control_admin_entrypoint.rs +++ b/src/control_admin_entrypoint.rs @@ -150,7 +150,7 @@ async fn main() -> Result<()> { //handle commands match app.command { Some(Commands::CreateAdmin(create_admin)) => { - let token = control_server.create_user_token(&User::new(create_admin.email.clone())?).await?; + let token = control_server.create_user_token(User::new(create_admin.email.clone())?).await?; info!("[Result]: Administrator {} has been successfully created with token {} will expire {}", &create_admin.email, &token.token, &token.expire_at) } Some(Commands::GenerateKeys(generate_keys)) => { diff --git a/src/domain/token/entity.rs b/src/domain/token/entity.rs index 24548fe83cccd579d1eae3a6bc9a66154840d5b4..1ff01f2cfab406a0093858d5df3eee74fa15e0a4 100644 --- a/src/domain/token/entity.rs +++ b/src/domain/token/entity.rs @@ -21,7 +21,7 @@ use std::fmt::{Display, Formatter}; const TOKEN_EXPIRE_IN_DAYS: i64 = 180; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Token { pub id: i32, pub user_id: i32, diff --git a/src/domain/token/repository.rs b/src/domain/token/repository.rs index 466a94dabe92db9685895325a156f7d0c1a66c4c..8a6ff30d4bce23d6d210af85984281de74cca56a 100644 --- a/src/domain/token/repository.rs +++ b/src/domain/token/repository.rs @@ -20,7 +20,7 @@ use async_trait::async_trait; #[async_trait] pub trait Repository: Send + Sync { - async fn create(&self, user: &Token) -> Result; + async fn create(&self, user: Token) -> Result; async fn get_token_by_id(&self, id: i32) -> Result; async fn get_token_by_value(&self, token: &str) -> Result; async fn delete_by_id(&self, id: i32) -> Result<()>; diff --git a/src/domain/user/repository.rs b/src/domain/user/repository.rs index bdfd24b77f6ddcd3b301cdb6c44832e7b3a8a4fa..fdc57c312d1cc6a2c53da8912bf5976ca33b2d29 100644 --- a/src/domain/user/repository.rs +++ b/src/domain/user/repository.rs @@ -20,7 +20,7 @@ use async_trait::async_trait; #[async_trait] pub trait Repository: Send + Sync { - async fn create(&self, user: &User) -> Result; + async fn create(&self, user: User) -> Result; async fn get_by_id(&self, id: i32) -> Result; async fn get_by_email(&self, email: &str) -> Result; async fn delete_by_id(&self, id: i32) -> Result<()>; diff --git a/src/infra/cipher/algorithm/aes.rs b/src/infra/cipher/algorithm/aes.rs deleted file mode 100644 index 9705f756dde04dc1f42d6552f73be28a728a7f09..0000000000000000000000000000000000000000 --- a/src/infra/cipher/algorithm/aes.rs +++ /dev/null @@ -1,70 +0,0 @@ -/* - * // Copyright (c) 2023 Huawei Technologies Co.,Ltd. All rights reserved. - * // - * // signatrust is licensed under Mulan PSL v2. - * // You can use this software according to the terms and conditions of the Mulan - * // PSL v2. - * // You may obtain a copy of Mulan PSL v2 at: - * // http://license.coscl.org.cn/MulanPSL2 - * // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY - * // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO - * // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * // See the Mulan PSL v2 for more details. - */ - -use crate::infra::cipher::algorithm::traits::{Algorithm, Encryptor}; -use crate::util::error::Error; -use aes_gcm_siv::{ - aead::{Aead, KeyInit, OsRng}, - Aes256GcmSiv, -}; -use generic_array::GenericArray; -use rand::{thread_rng, Rng}; - -pub const NONCE_LENGTH: usize = 12; - -#[derive(Default)] -pub struct Aes256GcmEncryptor {} - -impl Aes256GcmEncryptor { - fn generate_nonce_bytes(&self) -> [u8; NONCE_LENGTH] { - thread_rng().gen::<[u8; NONCE_LENGTH]>() - } -} - -impl Encryptor for Aes256GcmEncryptor { - fn generate_key(&self) -> Vec { - Aes256GcmSiv::generate_key(&mut OsRng).as_slice().to_vec() - } - - fn algorithm(&self) -> Algorithm { - Algorithm::Aes256GSM - } - - fn encrypt(&self, key: Vec, content: Vec) -> crate::util::error::Result> { - let cipher = Aes256GcmSiv::new(GenericArray::from_slice(&key)); - let random = self.generate_nonce_bytes(); - let nonce = GenericArray::from_slice(&random); - let encrypt_msg = cipher - .encrypt(nonce, content.as_slice()) - .map_err(|e| Error::EncodeError(e.to_string()))?; - let mut encrypted = Vec::new(); - encrypted.extend_from_slice(&random); - encrypted.extend(encrypt_msg); - Ok(encrypted) - } - - fn decrypt(&self, key: Vec, content: Vec) -> crate::util::error::Result> { - if key.len() <= NONCE_LENGTH { - return Err(Error::EncodeError( - "failed to decode cluster key due to incorrect length".to_string(), - )); - } - let cipher = Aes256GcmSiv::new(GenericArray::from_slice(&key)); - let nonce = GenericArray::from_slice(&content[..NONCE_LENGTH]); - let decrypted = cipher - .decrypt(nonce, &content[NONCE_LENGTH..]) - .map_err(|e| Error::EncodeError(e.to_string()))?; - Ok(decrypted) - } -} diff --git a/src/infra/cipher/algorithm/factory.rs b/src/infra/cipher/algorithm/factory.rs deleted file mode 100644 index ce32dfa38da44974d5586e3a1b3ad01f9cfee8cd..0000000000000000000000000000000000000000 --- a/src/infra/cipher/algorithm/factory.rs +++ /dev/null @@ -1,32 +0,0 @@ -/* - * // Copyright (c) 2023 Huawei Technologies Co.,Ltd. All rights reserved. - * // - * // signatrust is licensed under Mulan PSL v2. - * // You can use this software according to the terms and conditions of the Mulan - * // PSL v2. - * // You may obtain a copy of Mulan PSL v2 at: - * // http://license.coscl.org.cn/MulanPSL2 - * // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY - * // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO - * // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * // See the Mulan PSL v2 for more details. - */ - -use crate::infra::cipher::algorithm::aes::Aes256GcmEncryptor; -use crate::infra::cipher::algorithm::traits::{Algorithm, Encryptor}; -use crate::util::error::{Result}; - -use std::str::FromStr; -use std::sync::Arc; - -pub struct AlgorithmFactory {} - -impl AlgorithmFactory { - pub fn new_algorithm(algo: &str) -> Result>> { - let algorithm = Algorithm::from_str(algo)?; - info!("encryption algorithm configured with {:?}", algorithm); - match algorithm { - Algorithm::Aes256GSM => Ok(Arc::new(Box::new(Aes256GcmEncryptor::default()))), - } - } -} diff --git a/src/infra/cipher/algorithm/mod.rs b/src/infra/cipher/algorithm/mod.rs deleted file mode 100644 index 1159bfa1672b5f0e252a06c7b5f233735b2d7ac4..0000000000000000000000000000000000000000 --- a/src/infra/cipher/algorithm/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod aes; -pub mod factory; -pub mod traits; diff --git a/src/infra/cipher/algorithm/traits.rs b/src/infra/cipher/algorithm/traits.rs deleted file mode 100644 index 6d7e9f6668accd3487ff2a55549bda063efac9e9..0000000000000000000000000000000000000000 --- a/src/infra/cipher/algorithm/traits.rs +++ /dev/null @@ -1,50 +0,0 @@ -/* - * // Copyright (c) 2023 Huawei Technologies Co.,Ltd. All rights reserved. - * // - * // signatrust is licensed under Mulan PSL v2. - * // You can use this software according to the terms and conditions of the Mulan - * // PSL v2. - * // You may obtain a copy of Mulan PSL v2 at: - * // http://license.coscl.org.cn/MulanPSL2 - * // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY - * // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO - * // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * // See the Mulan PSL v2 for more details. - */ - -use crate::util::error::{Error, Result}; -use std::fmt; -use std::str::FromStr; - -#[derive(Debug)] -pub enum Algorithm { - Aes256GSM, -} - -impl fmt::Display for Algorithm { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Algorithm::Aes256GSM => write!(f, "Aes256GSM"), - } - } -} - -impl FromStr for Algorithm { - type Err = Error; - fn from_str(s: &str) -> Result { - match s { - "aes256gsm" => Ok(Algorithm::Aes256GSM), - _ => Err(Error::UnsupportedTypeError(format!( - "{} invalid encryption algorithm type", - s - ))), - } - } -} - -pub trait Encryptor: Send + Sync { - fn generate_key(&self) -> Vec; - fn algorithm(&self) -> Algorithm; - fn encrypt(&self, key: Vec, content: Vec) -> Result>; - fn decrypt(&self, key: Vec, content: Vec) -> Result>; -} diff --git a/src/infra/cipher/engine.rs b/src/infra/cipher/engine.rs deleted file mode 100644 index d45b100f878e95d40685b26660be5bb60018902d..0000000000000000000000000000000000000000 --- a/src/infra/cipher/engine.rs +++ /dev/null @@ -1,143 +0,0 @@ -/* - * // Copyright (c) 2023 Huawei Technologies Co.,Ltd. All rights reserved. - * // - * // signatrust is licensed under Mulan PSL v2. - * // You can use this software according to the terms and conditions of the Mulan - * // PSL v2. - * // You may obtain a copy of Mulan PSL v2 at: - * // http://license.coscl.org.cn/MulanPSL2 - * // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY - * // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO - * // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * // See the Mulan PSL v2 for more details. - */ - -use crate::infra::cipher::algorithm::factory::AlgorithmFactory; -use crate::infra::cipher::algorithm::traits::Encryptor; -use crate::model::clusterkey::entity::ClusterKey; -use crate::model::clusterkey::repository::Repository as ClusterKeyRepository; -use crate::util::error::{Error, Result}; -use crate::util::key; -use async_trait::async_trait; -use config::Value; -use std::collections::HashMap; -use std::sync::Arc; - -pub const KEY_SIZE: usize = 2; - -#[async_trait] -pub trait EncryptionEngine: Send + Sync { - async fn initialize(&mut self) -> Result<()>; - async fn encode(&self, content: Vec) -> Result>; - async fn decode(&self, content: Vec) -> Result>; -} - -pub struct EncryptionEngineWithClusterKey { - //cluster key repository - cluster_repository: Arc>, - encryptor: Arc>, - keep_in_days: i64, - latest_cluster_key: Box, -} - -/// considering we have rotated cluster key for safety concern -/// we need append cluster key id to the encrypt data, for example -/// encrypted data 1 in hex string -/// 000A, AB13......BF46, A237.....BA13CC46 -/// |-key id-|--nonce--|---encrypted data--| -/// 1. key id: is the cluster key used for encryption, fixed size -/// 2. nonce: the random bytes used for encryption. fixed size -/// 3. encrypted data: the encrypted content -impl EncryptionEngineWithClusterKey { - pub fn new( - cluster_repository: Arc>, - config: &HashMap, - ) -> Result { - let encryptor = AlgorithmFactory::new_algorithm( - &config - .get("algorithm") - .expect("encryption engine should configured") - .to_string(), - )?; - Ok(EncryptionEngineWithClusterKey { - cluster_repository, - encryptor, - keep_in_days: config - .get("keep_in_days") - .expect("encryption engine should configured") - .to_string() - .parse()?, - latest_cluster_key: Box::new(ClusterKey::default()), - }) - } -} -impl EncryptionEngineWithClusterKey { - fn append_cluster_key_hex(&self, data: &mut Vec) -> Vec { - let mut result = vec![]; - result.append(&mut key::decode_hex_string_to_u8(&format!( - "{:04X}", - self.latest_cluster_key.id - ))); - result.append(data); - result - } - - async fn get_used_cluster_key(&self, data: &[u8]) -> Result { - //convert the cluster back and obtain from database, hard code here. - let cluster_id: i32 = (data[0] as i32) * 256 + data[1] as i32; - self.cluster_repository.get_by_id(cluster_id).await - } -} -#[async_trait] -impl EncryptionEngine for EncryptionEngineWithClusterKey { - async fn initialize(&mut self) -> Result<()> { - //generate new symmetric keys when there is no db record - let key = self - .cluster_repository - .get_latest(&self.encryptor.algorithm().to_string()) - .await?; - match key { - Some(k) => *self.latest_cluster_key = k, - None => { - let cluster_key = ClusterKey::new( - self.encryptor.generate_key(), - self.encryptor.algorithm().to_string(), - self.keep_in_days, - )?; - //insert when no records - self.cluster_repository.create(&cluster_key).await?; - match self - .cluster_repository - .get_latest(&self.encryptor.algorithm().to_string()) - .await? - { - None => { - return Err(Error::ConfigError( - "can't find latest cluster key from database".to_string(), - )) - } - Some(cluster) => *self.latest_cluster_key = cluster, - } - } - } - info!("current cluster key is: {}", self.latest_cluster_key); - Ok(()) - } - async fn encode(&self, content: Vec) -> Result> { - //always use latest cluster key to encode data - let mut secret = self - .encryptor - .encrypt(self.latest_cluster_key.data.unsecure().to_owned(), content)?; - Ok(self.append_cluster_key_hex(&mut secret)) - } - - async fn decode(&self, content: Vec) -> Result> { - //1. obtain cluster key id from content - //2. use cluster key to decrypt data - let cluster_key = self.get_used_cluster_key(&content[0..KEY_SIZE]).await?; - self.encryptor.decrypt( - cluster_key.data.unsecure().to_owned(), - content[KEY_SIZE..].to_vec(), - ) - } -} diff --git a/src/infra/cipher/mod.rs b/src/infra/cipher/mod.rs deleted file mode 100644 index 383cc5978f798043366ed3765201068dfb957024..0000000000000000000000000000000000000000 --- a/src/infra/cipher/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod algorithm; -pub mod engine; diff --git a/src/infra/database/model/token/dto.rs b/src/infra/database/model/token/dto.rs index 1bb74657aadf2bf3ab414824a850b9fdd5707811..88c1389f7b3ae2ed49e114b1d37778c431bc51c0 100644 --- a/src/infra/database/model/token/dto.rs +++ b/src/infra/database/model/token/dto.rs @@ -13,9 +13,6 @@ * * // See the Mulan PSL v2 for more details. * */ - -use crate::util::error::Result; - use sqlx::FromRow; use chrono::{DateTime, Utc}; @@ -32,26 +29,28 @@ pub(super) struct TokenDTO { pub expire_at: DateTime, } -impl TokenDTO { - pub async fn encrypt( - token: &Token) -> Result { - Ok(Self { +impl From for TokenDTO { + fn from(token: Token) -> Self { + Self { id: token.id, user_id: token.user_id, description: token.description.clone(), token: get_token_hash(&token.token), create_at: token.create_at, expire_at: token.expire_at, - }) + } } - pub async fn decrypt(&self) -> Result { - Ok(Token { - id: self.id, - user_id: self.user_id, - description: self.description.clone(), - token: self.token.clone(), - create_at: self.create_at, - expire_at:self.expire_at, - }) +} + +impl From for Token { + fn from(dto: TokenDTO) -> Self { + Self { + id: dto.id, + user_id: dto.user_id, + description: dto.description.clone(), + token: dto.token.clone(), + create_at: dto.create_at, + expire_at:dto.expire_at, + } } } diff --git a/src/infra/database/model/token/repository.rs b/src/infra/database/model/token/repository.rs index 145e1299a7d8e934a1732dff12b38b85bab98070..4d276a3bbddb1f415c3b45dcb9184427a1fdf06b 100644 --- a/src/infra/database/model/token/repository.rs +++ b/src/infra/database/model/token/repository.rs @@ -41,8 +41,8 @@ impl TokenRepository { #[async_trait] impl Repository for TokenRepository { - async fn create(&self, token: &Token) -> Result { - let dto = TokenDTO::encrypt(token).await?; + async fn create(&self, token: Token) -> Result { + let dto = TokenDTO::from(token); let record : u64 = sqlx::query("INSERT INTO token(user_id, description, token, create_at, expire_at) VALUES (?, ?, ?, ?, ?)") .bind(&dto.user_id) .bind(&dto.description) @@ -59,7 +59,7 @@ impl Repository for TokenRepository { .bind(id) .fetch_one(&self.db_pool) .await?; - Ok(selected.decrypt().await?) + Ok(Token::from(selected)) } async fn get_token_by_value(&self, token: &str) -> Result { @@ -67,7 +67,7 @@ impl Repository for TokenRepository { .bind(get_token_hash(token)) .fetch_one(&self.db_pool) .await?; - Ok(selected.decrypt().await?) + Ok(Token::from(selected)) } async fn delete_by_id(&self, id: i32) -> Result<()> { @@ -85,7 +85,7 @@ impl Repository for TokenRepository { .await?; let mut results = vec![]; for dto in dtos.into_iter() { - results.push(dto.decrypt().await?); + results.push(Token::from(dto)); } Ok(results) } diff --git a/src/infra/database/model/user/dto.rs b/src/infra/database/model/user/dto.rs index f4749df6a06076d97de30290ee1e5246be3335a3..c9011aae655c613eb2a2b27a0bf9514a4c721cae 100644 --- a/src/infra/database/model/user/dto.rs +++ b/src/infra/database/model/user/dto.rs @@ -13,8 +13,6 @@ * * // See the Mulan PSL v2 for more details. * */ - -use crate::util::error::Result; use sqlx::FromRow; use crate::domain::user::entity::User; @@ -24,19 +22,20 @@ pub(super) struct UserDTO { pub email: String } -impl UserDTO { - pub async fn encrypt( - user: &User, - ) -> Result { - Ok(Self { +impl From for UserDTO { + fn from(user: User) -> Self { + Self { id: user.id, - email: user.email.clone(), - }) + email: user.email, + } } - pub async fn decrypt(&self) -> Result { - Ok(User { - id: self.id, - email: self.email.clone() - }) +} + +impl From for User { + fn from(dto: UserDTO) -> Self { + Self { + id: dto.id, + email: dto.email + } } } diff --git a/src/infra/database/model/user/repository.rs b/src/infra/database/model/user/repository.rs index 41c82e7c7bde8c951b491f5524bfa3b5d7332f41..4f1775ef8aaa4717ab68d247e905e031c5081f92 100644 --- a/src/infra/database/model/user/repository.rs +++ b/src/infra/database/model/user/repository.rs @@ -39,13 +39,13 @@ impl UserRepository { #[async_trait] impl Repository for UserRepository { - async fn create(&self, user: &User) -> Result { + async fn create(&self, user: User) -> Result { return match self.get_by_email(&user.email).await { Ok(existed) => { Ok(existed) } Err(_err) => { - let dto = UserDTO::encrypt(user).await?; + let dto = UserDTO::from(user); let record : u64 = sqlx::query("INSERT INTO user(email) VALUES (?)") .bind(&dto.email) .execute(&self.db_pool) @@ -60,7 +60,7 @@ impl Repository for UserRepository { .bind(id) .fetch_one(&self.db_pool) .await?; - Ok(selected.decrypt().await?) + Ok(User::from(selected)) } async fn get_by_email(&self, email: &str) -> Result { @@ -68,7 +68,7 @@ impl Repository for UserRepository { .bind(email) .fetch_one(&self.db_pool) .await?; - Ok(selected.decrypt().await?) + Ok(User::from(selected)) } async fn delete_by_id(&self, id: i32) -> Result<()> { diff --git a/src/presentation/server/control_server.rs b/src/presentation/server/control_server.rs index fda1c06c8ce8dbec7cdc32d3107b2a00038e5c4b..a7911fa6730012b123d85b3998eadbb2b23dedcd 100644 --- a/src/presentation/server/control_server.rs +++ b/src/presentation/server/control_server.rs @@ -170,7 +170,7 @@ impl ControlServer { } //used for control admin cmd - pub async fn create_user_token(&self, user: &User) -> Result { + pub async fn create_user_token(&self, user: User) -> Result { let user = self.user_service.save(user).await?; self.user_service.generate_token( &UserIdentity::from(user.clone()), diff --git a/src/util/key.rs b/src/util/key.rs index d183305eab85db1c39eed50797b45fcb9a6aeed5..88369f31137efbcd579ac9fd88433916010d9988 100644 --- a/src/util/key.rs +++ b/src/util/key.rs @@ -19,7 +19,7 @@ use rand::{thread_rng, Rng}; use rand::distributions::Alphanumeric; use serde::{Serialize, Serializer}; use std::collections::{HashMap, BTreeMap}; -use sha1::Digest; +use sha2::{Sha256, Digest}; pub fn encode_u8_to_hex_string(value: &[u8]) -> String { value @@ -37,7 +37,7 @@ pub fn generate_api_token() -> String { } pub fn get_token_hash(real_token: &str) -> String { - let mut hasher = sha1::Sha1::default(); + let mut hasher = Sha256::default(); hasher.update(real_token); let digest = hasher.finalize(); return hex::encode(digest)