rsiot/components/cmp_auth/
fn_process.rs1use std::time::Duration;
2
3use tokio::time::sleep;
4use tracing::{info, warn};
5
6use hmac::{Hmac, Mac};
7use jwt::{SignWithKey, VerifyWithKey};
8use sha2::Sha256;
9
10use crate::{
11 executor::CmpInOut,
12 message::{system_messages::*, *},
13};
14
15use super::{token_payload::TokenPayload, Config, ConfigStore, ConfigStoreLocalItem, Error};
16
17pub async fn fn_process<TMsg>(config: Config, in_out: CmpInOut<TMsg>) -> super::Result<()>
18where
19 TMsg: MsgDataBound + 'static,
20{
21 loop {
22 let result = task_main(config.clone(), in_out.clone()).await;
23 warn!("Component error: {:?}", result);
24 info!("Restart");
25 sleep(Duration::from_secs(2)).await;
26 }
27}
28
29async fn task_main<TMsg>(config: Config, mut in_out: CmpInOut<TMsg>) -> super::Result<()>
30where
31 TMsg: MsgDataBound + 'static,
32{
33 while let Ok(msg) = in_out.recv_input().await {
34 let msg_response = match msg.data {
35 MsgData::System(data) => match data {
36 System::AuthRequestByLogin(value) => {
37 process_request_by_login(value, &config, msg.trace.clone()).await
38 }
39 System::AuthRequestByToken(value) => {
40 process_request_by_token(value, &config, msg.trace.clone()).await
41 }
42 _ => continue,
43 },
44 _ => continue,
45 };
46 let msg = match msg_response {
47 Ok(msg) => {
48 info!("Success login: {:?}", msg);
49 msg
50 }
51 Err(err) => {
52 warn!("Wrong login attempt: {}", err);
53 let trace_ids = msg.trace.get_ids();
54 let value = AuthResponseErr {
55 error: err.to_string(),
56 trace_ids,
57 };
58 Message::new(MsgData::System(System::AuthResponseErr(value)))
59 }
60 };
61 in_out.send_output(msg).await.map_err(Error::CmpOutput)?;
62 }
63 Ok(())
64}
65
66async fn process_request_by_token<TMsg>(
68 request_by_login: AuthRequestByToken,
69 config: &Config,
70 msg_trace: MsgTrace,
71) -> super::Result<Message<TMsg>>
72where
73 TMsg: MsgDataBound,
74{
75 let key: Hmac<Sha256> = Hmac::new_from_slice(config.secret_key.as_bytes())?;
76 let claims: TokenPayload = request_by_login.token.verify_with_key(&key)?;
77
78 let trace_ids = msg_trace.get_ids();
79 let value = AuthResponseOk {
80 token: request_by_login.token,
81 perm: claims.role,
82 trace_ids,
83 login: claims.login,
84 };
85 let msg = Message::new(MsgData::System(System::AuthResponseOk(value)));
86 Ok(msg)
87}
88
89async fn process_request_by_login<TMsg>(
91 request_by_login: AuthRequestByLogin,
92 config: &Config,
93 msg_trace: MsgTrace,
94) -> super::Result<Message<TMsg>>
95where
96 TMsg: MsgDataBound,
97{
98 info!("Request: {request_by_login:?}");
99 let valid_password = get_credentials(&request_by_login.login, config).await?;
100
101 let valid_password = valid_password.ok_or(Error::ProcessRequest("Unknown user".into()))?;
103
104 if valid_password.password != request_by_login.password {
106 return Err(Error::ProcessRequest("Wrong password".into()));
107 }
108
109 let key: Hmac<Sha256> = Hmac::new_from_slice(config.secret_key.as_bytes())?;
111 let claims = TokenPayload {
112 login: request_by_login.login.clone(),
113 role: valid_password.role,
114 };
115 let token = claims.sign_with_key(&key)?;
116
117 let trace_ids = msg_trace.get_ids();
118
119 let value = AuthResponseOk {
120 token,
121 perm: valid_password.role,
122 trace_ids,
123 login: request_by_login.login,
124 };
125 let msg = Message::new(MsgData::System(System::AuthResponseOk(value)));
126
127 Ok(msg)
128}
129
130async fn get_credentials(
131 login: &str,
132 config: &Config,
133) -> super::Result<Option<ConfigStoreLocalItem>> {
134 match &config.store {
135 ConfigStore::Local(local) => {
136 let item = local.iter().find(|e| e.login == login).cloned();
137 Ok(item)
138 }
139
140 ConfigStore::Surrealdb => todo!(),
141 }
142}