From 5501ba8b9c0be4393a3afbc1f8b2c72d480fe187 Mon Sep 17 00:00:00 2001 From: TommyLike Date: Mon, 27 Mar 2023 20:05:55 +0800 Subject: [PATCH] Add control-admin cmd for develop purpose --- Cargo.toml | 6 +- Makefile | 10 +- README.md | 45 ++++-- .../20221220070859_initialize-table.down.sql | 4 +- .../20221220070859_initialize-table.up.sql | 18 +-- scripts/initialize-user-and-keys.sh | 36 +++++ src/application/datakey.rs | 10 +- src/application/user.rs | 19 ++- src/control_admin.rs | 138 ++++++++++++++++++ src/domain/datakey/entity.rs | 2 +- src/domain/user/entity.rs | 2 +- src/infra/database/model/datakey/dto.rs | 6 +- src/infra/sign_plugin/openpgp.rs | 17 ++- .../handler/control/datakey_handler.rs | 6 +- .../handler/control/model/datakey/dto.rs | 16 +- .../handler/control/model/user/dto.rs | 17 +-- src/presentation/server/control_server.rs | 58 ++++++-- 17 files changed, 336 insertions(+), 74 deletions(-) create mode 100755 scripts/initialize-user-and-keys.sh create mode 100644 src/control_admin.rs diff --git a/Cargo.toml b/Cargo.toml index 5a16191..fa09f1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ md-5 = "0.10.5" notify = "5.0.0" env_logger = "0.10.0" thiserror = "1.0.38" -sqlx = { version = "0.6", features = ["migrate", "mysql", "runtime-tokio-rustls", "chrono"] } +sqlx = { version = "0.6.3", features = ["migrate", "mysql", "runtime-tokio-rustls", "chrono"] } once_cell = "1.16.0" reqwest = { version = "0.11.13", features=["json"]} serde_json = "1.0.91" @@ -80,5 +80,9 @@ path = "src/data_server_entrypoint.rs" name = "control-server" path = "src/control_server_entrypoint.rs" +[[bin]] +name = "control-admin" +path = "src/control_admin.rs" + [profile.release] strip = "debuginfo" \ No newline at end of file diff --git a/Makefile b/Makefile index b15f46b..7c63609 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,11 @@ GIT_COMMIT=$(shell git rev-parse --verify HEAD) db: ./scripts/initialize-database.sh + +## Prepare basic administrator and keys +init: + ./scripts/initialize-user-and-keys.sh + client-image: docker build -t tommylike/signatrust-client:$(GIT_COMMIT) --build-arg BINARY=client -f Dockerfile . @@ -11,4 +16,7 @@ data-server-image: docker build -t tommylike/signatrust-data-server:$(GIT_COMMIT) --build-arg BINARY=data-server -f Dockerfile . control-server-image: - docker build -t tommylike/signatrust-control-server:$(GIT_COMMIT) --build-arg BINARY=control-server -f Dockerfile . \ No newline at end of file + docker build -t tommylike/signatrust-control-server:$(GIT_COMMIT) --build-arg BINARY=control-server -f Dockerfile . + +control-admin-image: + docker build -t tommylike/signatrust-control-admin:$(GIT_COMMIT) --build-arg BINARY=control-admin -f Dockerfile . \ No newline at end of file diff --git a/README.md b/README.md index f09f6b2..301dcb8 100644 --- a/README.md +++ b/README.md @@ -85,28 +85,53 @@ keep_in_days = 180 algorithm = "aes256gsm" ``` +# Components +This project consists of several binaries: +1. **data-server**: the data server used for handle signing requests and exposes the gRPC for clients. +2. **control-server**: the control server used for handle administration requests and expose http requests for Web UI. +3. **control-admin**: the control-admin is mainly used in develop environment for convenience, i.e. generate administrator and tokens without the integration of external OIDC server. +4. **client**: the client is responsible for handle signing task locally and will exchange signature with data server. + + + # Quick Start Guide ## Local development +Run these command correspondingly to build or run project executable binary: +```shell +# build binary +cargo build --bin control-server/data-server/client/control-admin +# running command +RUST_BACKTRACE=full RUST_LOG=debug ./target/debug/ --config +``` When using memory backend, to ensure the security of sensitive data, Signatrust requires an external KMS system for encryption and decryption. However, -to run the system locally for development purposes, you will need to configure a **dummy** KMS provider +to run the system locally for development purpose, you will need to configure a **dummy** KMS provider ```shell [kms-provider] type = "dummy" ``` -Additionally, we have provided a script to set up the MySQL database in a Docker environment. To use the script, you will +Additionally, we have developed a script to set up the MySQL database in a Docker environment. To use the script, you will need to install the Docker server, the MySQL binary, and the [Sqlx binary](https://github.com/launchbadge/sqlx/blob/main/sqlx-cli/README.md#enable-building-in-offline-mode-with-query). -Once you have these installed, simply run the -command below: +Once you have these installed, simply run the command below to initialize the database. ```shell make db ``` -Run these command correspondingly to build binary or launching server: +In order to develop without the need of setting up the external OIDC server, simple run the prepared script which will generate the default admin&token and the default keys: ```shell -# build binary -cargo build --bin control-server/data-server/client -# running command -RUST_BACKTRACE=full RUST_LOG=debug ./target/debug/ --config +make init +``` +Pay attention to the command output: +```shell +...skipped output +[Result]: Administrator tommylikehu@gmail.com has been successfully created with token XmUICsVV48EjfkWYv3ch1eutRJOQh7mp3bRfmQDL will expire 2023-09-23 11:20:33 UTC +...skipped output +[Result]: Keys 'default-pgp' type pgp has been successfully generated +``` +Now you can use this token to debug the control service API or use the pgp keys for signing rpm packages with client. +```shell +curl -k --header "Authorization:XmUICsVV48EjfkWYv3ch1eutRJOQh7mp3bRfmQDL" -v http(s)://localhost:8080/api/v1/keys/ +``` +```shell +RUST_BACKTRACE=full RUST_LOG=info ./target/debug/client --config add --key-id default-pgp --file-type rpm --key-type pgp .data/simple.rpm ``` - # Contribute diff --git a/migrations/20221220070859_initialize-table.down.sql b/migrations/20221220070859_initialize-table.down.sql index f916422..2f746b9 100644 --- a/migrations/20221220070859_initialize-table.down.sql +++ b/migrations/20221220070859_initialize-table.down.sql @@ -1,5 +1,5 @@ -- Add down migration script here DROP TABLE IF EXISTS cluster_key; DROP TABLE IF EXISTS data_key; -DROP TABLE IF EXISTS user; -DROP TABLE IF EXISTS token; \ No newline at end of file +DROP TABLE IF EXISTS token; +DROP TABLE IF EXISTS user; \ No newline at end of file diff --git a/migrations/20221220070859_initialize-table.up.sql b/migrations/20221220070859_initialize-table.up.sql index 1a09a46..1bed787 100644 --- a/migrations/20221220070859_initialize-table.up.sql +++ b/migrations/20221220070859_initialize-table.up.sql @@ -1,3 +1,9 @@ +CREATE TABLE user ( + id INT AUTO_INCREMENT, + email VARCHAR(60) UNIQUE, + PRIMARY KEY(id) +); + CREATE TABLE cluster_key ( id INT AUTO_INCREMENT, data TEXT NOT NULL, @@ -12,7 +18,7 @@ CREATE TABLE data_key ( id INT AUTO_INCREMENT, name VARCHAR(100) UNIQUE NOT NULL, description VARCHAR(200), - user VARCHAR(40) NOT NULL, + user INT NOT NULL, email VARCHAR(40) NOT NULL, attributes VARCHAR(1000), key_type VARCHAR(10) NOT NULL, @@ -23,16 +29,10 @@ CREATE TABLE data_key ( expire_at DATETIME, key_state VARCHAR(10) NOT NULL, soft_delete BOOLEAN NOT NULL default 0, - PRIMARY KEY(id) -); - -CREATE TABLE user ( - id INT AUTO_INCREMENT, - email VARCHAR(60) UNIQUE, - PRIMARY KEY(id) + PRIMARY KEY(id), + FOREIGN KEY (user) REFERENCES user(id) ); - CREATE TABLE token ( id INT AUTO_INCREMENT, user_id INT NOT NULL, diff --git a/scripts/initialize-user-and-keys.sh b/scripts/initialize-user-and-keys.sh new file mode 100755 index 0000000..48435ad --- /dev/null +++ b/scripts/initialize-user-and-keys.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +function check-binary { + echo "checking control-admin binary" + which ./target/debug/control-admin >/dev/null 2>&1 + if [[ $? -ne 0 ]]; then + echo "control-admin binary not found, please use command 'cargo build --bin control-admin' to build it first, exiting." + exit 1 + else + echo -n "found control-admin binary, " && docker version + fi +} + +function create_default_admin { + echo "start to create default admin with tommylikehu@gmail.com" + RUST_LOG=info ./target/debug/control-admin --config ./config/server.toml create-admin --email tommylikehu@gmail.com +} + +function create_default_openpgp_keys { + echo "start to create default openpgp keys identified with default-pgp" + RUST_LOG=info ./target/debug/control-admin --config ./config/server.toml generate-keys --name default-pgp --description "used for test purpose only" --key-type pgp --email tommylikehu@gmail.com --param-key-type rsa --param-key-size 2048 +} + +echo "Preparing basic keys for signatrust......" + +check-binary + +echo "===========================================" + +create_default_admin + +create_default_openpgp_keys \ No newline at end of file diff --git a/src/application/datakey.rs b/src/application/datakey.rs index 7d09f65..ad936c3 100644 --- a/src/application/datakey.rs +++ b/src/application/datakey.rs @@ -19,14 +19,13 @@ use crate::domain::sign_service::SignBackend; use crate::util::error::{Result}; use async_trait::async_trait; use crate::domain::datakey::entity::{DataKey, KeyState}; -use crate::presentation::handler::control::model::datakey::dto::DataKeyDTO; use crate::util::signer_container::DataKeyContainer; use std::collections::HashMap; #[async_trait] pub trait KeyService: Send + Sync{ - async fn create(&self, data: DataKeyDTO) -> Result; + async fn create(&self, data: &mut DataKey) -> Result; async fn get_all(&self) -> Result>; async fn get_one(&self, id: i32) -> Result; async fn delete_one(&self, id: i32) -> Result<()>; @@ -68,10 +67,9 @@ where R: DatakeyRepository + Clone, S: SignBackend + ?Sized { - async fn create(&self, data: DataKeyDTO) -> Result { - let mut key = DataKey::try_from(data)?; - self.sign_service.generate_keys(&mut key).await?; - self.repository.create(key).await + async fn create(&self, data: &mut DataKey) -> Result { + self.sign_service.generate_keys(data).await?; + self.repository.create(data.clone()).await } async fn get_all(&self) -> Result> { diff --git a/src/application/user.rs b/src/application/user.rs index 4d5d8f1..d6dd392 100644 --- a/src/application/user.rs +++ b/src/application/user.rs @@ -36,8 +36,11 @@ use url::Url; #[async_trait] pub trait UserService: Send + Sync{ - async fn save(&self, u: &User) -> Result; async fn get_token(&self, u: &UserIdentity) -> Result>; + async fn get_token_by_value(&self, token: &str) -> 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) -> Result; async fn get_login_url(&self) -> Result; async fn validate_user(&self, code: &str) -> Result; @@ -148,12 +151,20 @@ where R: UserRepository, T: TokenRepository { + async fn get_token_by_value(&self, token: &str) -> Result { + self.token_repository.get_token_by_value(token).await + } + async fn save(&self, u: &User) -> Result { return self.user_repository.create(u).await } async fn get_token(&self, user: &UserIdentity) -> Result> { - return self.token_repository.get_token_by_user_id(user.id).await + self.token_repository.get_token_by_user_id(user.id).await + } + + async fn get_by_email(&self, email: &str) -> Result { + self.user_repository.get_by_email(email).await } async fn generate_token(&self, u: &UserIdentity) -> Result { @@ -182,4 +193,8 @@ where } } } + + async fn get_user_by_id(&self, id: i32) -> Result { + self.user_repository.get_by_id(id).await + } } diff --git a/src/control_admin.rs b/src/control_admin.rs new file mode 100644 index 0000000..169d89e --- /dev/null +++ b/src/control_admin.rs @@ -0,0 +1,138 @@ +/* + * + * * // 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. + * + */ + +#![allow(dead_code)] + +use std::collections::HashMap; +use std::env; +use chrono::{Duration, Utc}; +use crate::util::error::{Result}; +use clap::{Parser, Subcommand}; +use clap::{Args}; +use crate::client::sign_identity; +use crate::client::cmd::traits::SignCommand; +use crate::domain::datakey::entity::{DataKey}; +use crate::domain::user::entity::User; +use crate::presentation::handler::control::model::datakey::dto::DataKeyDTO; +use crate::presentation::handler::control::model::user::dto::UserIdentity; + +mod util; +mod client; +mod infra; +mod domain; +mod application; +mod presentation; + + +#[macro_use] +extern crate log; +#[macro_use] +extern crate lazy_static; + +#[derive(Parser)] +#[command(name = "signatrust-admin")] +#[command(author = "TommyLike ")] +#[command(version = "0.10")] +#[command(about = "Administrator command for signatrust server", long_about = None)] +pub struct App { + #[arg(short, long)] + #[arg( + help = "path of configuration file, './client.toml' relative to working directory be used in default" + )] + config: Option, + #[command(subcommand)] + command: Option, +} + +#[derive(Subcommand)] +enum Commands { + #[command(about = "Create default admin and admin token", long_about = None)] + CreateAdmin(CommandAdmin), + #[command(about = "Generate keys for signing", long_about = None)] + GenerateKeys(CommandGenerateKeys), +} + +#[derive(Args)] +pub struct CommandAdmin { + #[arg(long)] + #[arg(help = "specify the email of admin")] + email: String, +} + +#[derive(Args)] +pub struct CommandGenerateKeys { + #[arg(long)] + #[arg(help = "specify the name of this key pairs")] + name: String, + #[arg(long)] + #[arg(help = "specify the the description of this key pairs")] + description: String, + #[arg(long)] + #[arg(help = "specify the type of internal key used for this key pairs, ie, rsa")] + param_key_type: String, + #[arg(long)] + #[arg(help = "specify the type of internal key size used for this key pairs, ie, 1024")] + param_key_size: String, + #[arg(long)] + #[arg(help = "specify the email of admin which this key bounds to")] + email: String, + #[arg(long)] + #[arg(value_enum)] + #[arg(help = "specify the key type for generating")] + key_type: sign_identity::KeyType, +} + +#[tokio::main] +async fn main() -> Result<()> { + //prepare config and logger + env_logger::init(); + let app = App::parse(); + let path = app.config.unwrap_or(format!("{}/{}", env::current_dir().expect("current dir not found").display(), + "config/server.toml")); + let server_config = util::config::ServerConfig::new(path); + let control_server = presentation::server::control_server::ControlServer::new(server_config.config).await?; + //handle commands + match app.command { + Some(Commands::CreateAdmin(create_admin)) => { + 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)) => { + let user = control_server.get_user_by_email(&generate_keys.email).await?; + let mut attributes = HashMap::new(); + attributes.insert("key_type".to_string(), generate_keys.param_key_type); + attributes.insert("key_length".to_string(), generate_keys.param_key_size); + let now = Utc::now(); + let key = DataKeyDTO { + id: 0, + name: generate_keys.name, + description: generate_keys.description, + user: user.id, + email: user.email.clone(), + attributes, + key_type: generate_keys.key_type.to_string(), + create_at: format!("{}", now), + expire_at: format!("{}", now + Duration::days(30)), + key_state: Default::default(), + }; + + let keys = control_server.create_keys(&mut DataKey::convert_from(key, UserIdentity::from(user))?).await?; + info!("[Result]: Keys {} type {} has been successfully generated", &keys.name, &generate_keys.key_type) + } + None => {} + }; + Ok(()) +} diff --git a/src/domain/datakey/entity.rs b/src/domain/datakey/entity.rs index 53304b4..7a1a981 100644 --- a/src/domain/datakey/entity.rs +++ b/src/domain/datakey/entity.rs @@ -93,7 +93,7 @@ pub struct DataKey { pub id: i32, pub name: String, pub description: String, - pub user: String, + pub user: i32, pub email: String, pub attributes: HashMap, pub key_type: KeyType, diff --git a/src/domain/user/entity.rs b/src/domain/user/entity.rs index 526f596..aa9653c 100644 --- a/src/domain/user/entity.rs +++ b/src/domain/user/entity.rs @@ -19,7 +19,7 @@ use std::fmt::{Display, Formatter}; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct User { pub id: i32, pub email: String diff --git a/src/infra/database/model/datakey/dto.rs b/src/infra/database/model/datakey/dto.rs index fba9f13..7ffa431 100644 --- a/src/infra/database/model/datakey/dto.rs +++ b/src/infra/database/model/datakey/dto.rs @@ -32,7 +32,7 @@ pub(super) struct DataKeyDTO { pub id: i32, pub name: String, pub description: String, - pub user: String, + pub user: i32, pub email: String, pub attributes: String, pub key_type: String, @@ -54,7 +54,7 @@ impl TryFrom for DataKey { id: dto.id, name: dto.name.clone(), description: dto.description.clone(), - user: dto.user.clone(), + user: dto.user, email: dto.email.clone(), attributes: serde_json::from_str(dto.attributes.as_str())?, key_type: KeyType::from_str(&dto.key_type)?, @@ -77,7 +77,7 @@ impl TryFrom for DataKeyDTO { id: data_key.id, name: data_key.name.clone(), description: data_key.description.clone(), - user: data_key.user.clone(), + user: data_key.user, email: data_key.email.clone(), attributes: data_key.serialize_attributes()?, key_type: data_key.key_type.to_string(), diff --git a/src/infra/sign_plugin/openpgp.rs b/src/infra/sign_plugin/openpgp.rs index 84c13d8..11b8b19 100644 --- a/src/infra/sign_plugin/openpgp.rs +++ b/src/infra/sign_plugin/openpgp.rs @@ -54,7 +54,7 @@ pub struct PgpKeyGenerationParameter { key_length: String, #[validate(custom(function = "validate_utc_time", message="invalid openpgp attribute 'created_at'"))] create_at: String, - #[validate(custom(function= "validate_utc_time", message="invalid openpgp attribute 'expire_at'"))] + #[validate(custom(function= "validate_utc_time_not_expire", message="invalid openpgp attribute 'expire_at'"))] expire_at: String, } @@ -89,19 +89,30 @@ fn validate_key_size(key_size: &str) -> std::result::Result<(), ValidationError> Ok(()) } -fn validate_utc_time(expire: &str) -> std::result::Result<(), ValidationError> { +fn validate_utc_time_not_expire(expire: &str) -> std::result::Result<(), ValidationError> { let now = Utc::now(); match expire.parse::>() { Ok(expire) => { if expire <= now { return Err(ValidationError::new("expire time less than current time")) } + Ok(()) }, Err(_e) => { return Err(ValidationError::new("failed to parse time string to utc")); } } - Ok(()) +} + +fn validate_utc_time(expire: &str) -> std::result::Result<(), ValidationError> { + match expire.parse::>() { + Ok(_) => { + Ok(()) + }, + Err(_) => { + return Err(ValidationError::new("failed to parse time string to utc")); + } + } } pub struct OpenPGPPlugin { diff --git a/src/presentation/handler/control/datakey_handler.rs b/src/presentation/handler/control/datakey_handler.rs index dd668ac..c8b4c9b 100644 --- a/src/presentation/handler/control/datakey_handler.rs +++ b/src/presentation/handler/control/datakey_handler.rs @@ -23,12 +23,14 @@ use crate::presentation::handler::control::model::datakey::dto::{DataKeyDTO, Exp use crate::util::error::Error; use validator::Validate; use crate::application::datakey::KeyService; +use crate::domain::datakey::entity::DataKey; use super::model::user::dto::UserIdentity; -async fn create_data_key(_user: UserIdentity, key_service: web::Data, datakey: web::Json,) -> Result { +async fn create_data_key(user: UserIdentity, key_service: web::Data, datakey: web::Json,) -> Result { datakey.validate()?; - Ok(HttpResponse::Created().json(DataKeyDTO::try_from(key_service.into_inner().create(datakey.0).await?)?)) + let mut key = DataKey::convert_from(datakey.0, user)?; + Ok(HttpResponse::Created().json(DataKeyDTO::try_from(key_service.into_inner().create(&mut key).await?)?)) } async fn list_data_key(_user: UserIdentity, key_service: web::Data) -> Result { diff --git a/src/presentation/handler/control/model/datakey/dto.rs b/src/presentation/handler/control/model/datakey/dto.rs index 3d4f378..03cff0a 100644 --- a/src/presentation/handler/control/model/datakey/dto.rs +++ b/src/presentation/handler/control/model/datakey/dto.rs @@ -16,6 +16,7 @@ use validator::{Validate, ValidationError}; use std::collections::HashMap; use crate::util::error::Error; use serde::{Deserialize, Serialize}; +use crate::presentation::handler::control::model::user::dto::UserIdentity; #[derive(Deserialize, Serialize)] pub struct ExportKey { @@ -40,11 +41,12 @@ pub struct DataKeyDTO { pub id: i32, #[validate(length(min = 4, max = 20))] pub name: String, - #[validate(email)] + #[serde(skip_deserializing)] pub email: String, #[validate(length(min = 0, max = 100))] pub description: String, - pub user: String, + #[serde(skip_deserializing)] + pub user: i32, pub attributes: HashMap, pub key_type: String, #[validate(custom = "validate_utc_time")] @@ -62,10 +64,8 @@ fn validate_utc_time(expire: &str) -> std::result::Result<(), ValidationError> { Ok(()) } -impl TryFrom for DataKey { - type Error = Error; - - fn try_from(dto: DataKeyDTO) -> Result { +impl DataKey { + pub fn convert_from(dto: DataKeyDTO, identity: UserIdentity) -> Result { let mut combined_attributes = dto.attributes.clone(); combined_attributes.insert("name".to_string(), dto.name.clone()); combined_attributes.insert("email".to_string(), dto.email.clone()); @@ -75,8 +75,8 @@ impl TryFrom for DataKey { id: dto.id, name: dto.name, description: dto.description, - user: dto.user, - email: dto.email, + user: identity.id, + email: identity.email, attributes: combined_attributes, key_type: KeyType::from_str(dto.key_type.as_str())?, private_key: vec![], diff --git a/src/presentation/handler/control/model/user/dto.rs b/src/presentation/handler/control/model/user/dto.rs index 175b0fb..06b7f0a 100644 --- a/src/presentation/handler/control/model/user/dto.rs +++ b/src/presentation/handler/control/model/user/dto.rs @@ -8,11 +8,8 @@ use futures::Future; use serde::{Deserialize, Serialize}; use std::convert::From; use chrono::{Utc}; -use crate::infra::database::model::token::repository::TokenRepository; -use crate::infra::database::model::user::repository::UserRepository; -use crate::domain::token::repository::Repository as tokenRepository; +use crate::application::user::UserService; use crate::domain::user::entity::User; -use crate::domain::user::repository::Repository as userRepository; #[derive(Debug, Deserialize, Serialize)] pub struct UserIdentity { @@ -40,16 +37,12 @@ impl FromRequest for UserIdentity { //fetch valid token None => { if let Some(value) = req.clone().headers().get("Authorization") { - if let Some(tk_repo) = req.clone().app_data::>() { - if let Ok(token) = tk_repo.get_ref().get_token_by_value(value.to_str().unwrap()).await { + if let Some(user_service) = req.clone().app_data::>() { + if let Ok(token) = user_service.get_ref().get_token_by_value(value.to_str().unwrap()).await { //token exists and valid if token.expire_at.gt(&Utc::now()) { - if let Some(us_repo) = req.clone().app_data::>() { - if let Ok(user) = us_repo.get_ref().get_by_id(token.user_id).await { - return Ok(UserIdentity::from(user)); - } - } else { - warn!("unable to find token's user info"); + if let Ok(user) = user_service.get_ref().get_user_by_id(token.user_id).await { + return Ok(UserIdentity::from(user)); } } else { warn!("token expired"); diff --git a/src/presentation/server/control_server.rs b/src/presentation/server/control_server.rs index 2d4cf17..6baefe1 100644 --- a/src/presentation/server/control_server.rs +++ b/src/presentation/server/control_server.rs @@ -37,16 +37,42 @@ use crate::infra::database::model::token::repository::TokenRepository; use crate::infra::database::model::user::repository::UserRepository; use crate::infra::sign_backend::factory::SignBackendFactory; use crate::application::user::{DBUserService, UserService}; +use crate::domain::datakey::entity::DataKey; +use crate::domain::token::entity::Token; +use crate::domain::user::entity::User; +use crate::presentation::handler::control::model::user::dto::UserIdentity; pub struct ControlServer { server_config: Arc>, + user_service: Arc, + key_service: Arc, + } impl ControlServer { pub async fn new(server_config: Arc>) -> Result { let database = server_config.read()?.get_table("database")?; create_pool(&database).await?; + let data_repository = datakeyRepository::DataKeyRepository::new( + get_db_pool()?, + ); + let sign_backend = SignBackendFactory::new_engine( + server_config.clone(), get_db_pool()?).await?; + //initialize repos + let user_repo = UserRepository::new(get_db_pool()?); + let token_repo = TokenRepository::new(get_db_pool()?); + + //initialize the service + let user_service = Arc::new( + DBUserService::new( + user_repo.clone(), token_repo, + server_config.clone())?) as Arc; + let key_service = Arc::new( + DBKeyService::new( + data_repository, sign_backend)) as Arc; let server = ControlServer { + user_service, + key_service, server_config, }; Ok(server) @@ -69,21 +95,10 @@ impl ControlServer { info!("control server starts"); // Start http server - let data_repository = datakeyRepository::DataKeyRepository::new( - get_db_pool()?, - ); - let sign_backend = SignBackendFactory::new_engine( - self.server_config.clone(), get_db_pool()?).await?; - //initialize repos - let user_repo = UserRepository::new(get_db_pool()?); - let token_repo = TokenRepository::new(get_db_pool()?); - - //initialize the service let user_service = web::Data::from( - Arc::new(DBUserService::new(user_repo.clone(), token_repo, - self.server_config.clone())?) as Arc); + self.user_service.clone()); let key_service = web::Data::from( - Arc::new(DBKeyService::new(data_repository, sign_backend)) as Arc); + self.key_service.clone()); let http_server = HttpServer::new(move || { App::new() @@ -128,4 +143,21 @@ impl ControlServer { } Ok(()) } + + //used for control admin cmd + 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)).await + } + + //used for control admin cmd + pub async fn create_keys(&self, data: &mut DataKey) -> Result { + let key = self.key_service.create(data).await?; + self.key_service.enable(key.id).await?; + Ok(key) + } + + pub async fn get_user_by_email(&self, email: &str) -> Result { + self.user_service.get_by_email(email).await + } } -- Gitee