|
@@ -2,11 +2,13 @@ pub mod ext;
|
|
|
|
|
|
extern crate base64;
|
|
|
extern crate openidconnect;
|
|
|
+extern crate time;
|
|
|
extern crate url;
|
|
|
|
|
|
+use std::time::{SystemTime, UNIX_EPOCH, Duration};
|
|
|
+use time::{OffsetDateTime, format_description};
|
|
|
use std::sync::{Arc, Mutex};
|
|
|
use std::thread::{sleep, spawn, JoinHandle};
|
|
|
-use std::time::Duration;
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
use openidconnect::core::{CoreClient, CoreProviderMetadata, CoreResponseType};
|
|
|
use openidconnect::reqwest::http_client;
|
|
@@ -50,6 +52,23 @@ pub struct AuthInfo {
|
|
|
pkce_verifier: Option<PkceCodeVerifier>,
|
|
|
}
|
|
|
|
|
|
+fn systemtime_strftime<T>(dt: T, format: &str) -> String
|
|
|
+ where T: Into<OffsetDateTime>
|
|
|
+{
|
|
|
+ let f = format_description::parse(format);
|
|
|
+ match f {
|
|
|
+ Ok(f) => {
|
|
|
+ match dt.into().format(&f) {
|
|
|
+ Ok(s) => s,
|
|
|
+ Err(_e) => "".to_string(),
|
|
|
+ }
|
|
|
+ },
|
|
|
+ Err(_e) => {
|
|
|
+ "".to_string()
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
impl ZeroIDC {
|
|
|
fn new(
|
|
|
network_id: &str,
|
|
@@ -124,10 +143,84 @@ impl ZeroIDC {
|
|
|
let inner_local = Arc::clone(&self.inner);
|
|
|
(*local.lock().unwrap()).oidc_thread = Some(spawn(move || {
|
|
|
(*inner_local.lock().unwrap()).running = true;
|
|
|
+ let mut running = true;
|
|
|
+
|
|
|
+ while running {
|
|
|
+ let exp = UNIX_EPOCH + Duration::from_secs((*inner_local.lock().unwrap()).exp_time);
|
|
|
+ let now = SystemTime::now();
|
|
|
+
|
|
|
+ println!("refresh token thread tick, now: {}, exp: {}", systemtime_strftime(now, "[year]-[month]-[day] [hour]:[minute]:[second]"), systemtime_strftime(exp, "[year]-[month]-[day] [hour]:[minute]:[second]"));
|
|
|
+ let refresh_token = (*inner_local.lock().unwrap()).refresh_token.clone();
|
|
|
+ if let Some(refresh_token) = refresh_token {
|
|
|
+ if now >= (exp - Duration::from_secs(15)) {
|
|
|
+ let token_response = (*inner_local.lock().unwrap()).oidc_client.as_ref().map(|c| {
|
|
|
+ let res = c.exchange_refresh_token(&refresh_token)
|
|
|
+ .request(http_client);
|
|
|
+
|
|
|
+ res
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ if let Some(res) = token_response {
|
|
|
+ if let Ok(res) = res {
|
|
|
+ let id_token = res.id_token();
|
|
|
+
|
|
|
+ if let Some(id_token) = id_token {
|
|
|
+ let params = [("id_token", id_token.to_string()),("state", "refresh".to_string())];
|
|
|
+ let client = reqwest::blocking::Client::new();
|
|
|
+ let r = client.post((*inner_local.lock().unwrap()).auth_endpoint.clone())
|
|
|
+ .form(¶ms)
|
|
|
+ .send();
|
|
|
+
|
|
|
+ match r {
|
|
|
+ Ok(r) => {
|
|
|
+ if r.status().is_success() {
|
|
|
+ println!("hit url: {}", r.url().as_str());
|
|
|
+ println!("status: {}", r.status());
|
|
|
+
|
|
|
+
|
|
|
+ let access_token = res.access_token();
|
|
|
+ let at = access_token.secret();
|
|
|
+ let exp = dangerous_insecure_decode::<Exp>(&at);
|
|
|
+
|
|
|
+ if let Ok(e) = exp {
|
|
|
+ (*inner_local.lock().unwrap()).exp_time = e.claims.exp
|
|
|
+ }
|
|
|
+
|
|
|
+ (*inner_local.lock().unwrap()).access_token = Some(access_token.clone());
|
|
|
+ if let Some(t) = res.refresh_token() {
|
|
|
+ println!("New Refresh Token: {}", t.secret());
|
|
|
+ (*inner_local.lock().unwrap()).refresh_token = Some(t.clone());
|
|
|
+ }
|
|
|
+ println!("Central post succeeded");
|
|
|
+ } else {
|
|
|
+ println!("Central post failed: {}", r.status().to_string());
|
|
|
+ println!("hit url: {}", r.url().as_str());
|
|
|
+ println!("Status: {}", r.status());
|
|
|
+ (*inner_local.lock().unwrap()).exp_time = 0;
|
|
|
+ (*inner_local.lock().unwrap()).running = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ Err(e) => {
|
|
|
+ println!("Central post failed: {}", e.to_string());
|
|
|
+ println!("hit url: {}", e.url().unwrap().as_str());
|
|
|
+ println!("Status: {}", e.status().unwrap());
|
|
|
+ // (*inner_local.lock().unwrap()).exp_time = 0;
|
|
|
+ (*inner_local.lock().unwrap()).running = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ println!("waiting to refresh");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ println!("no refresh token?");
|
|
|
+ }
|
|
|
|
|
|
- while (*inner_local.lock().unwrap()).running {
|
|
|
- println!("tick");
|
|
|
sleep(Duration::from_secs(1));
|
|
|
+ running = (*inner_local.lock().unwrap()).running;
|
|
|
}
|
|
|
|
|
|
println!("thread done!")
|
|
@@ -207,12 +300,14 @@ impl ZeroIDC {
|
|
|
(*self.inner.lock().unwrap()).access_token = Some(tok.access_token().clone());
|
|
|
if let Some(t) = tok.refresh_token() {
|
|
|
(*self.inner.lock().unwrap()).refresh_token = Some(t.clone());
|
|
|
+ self.start();
|
|
|
}
|
|
|
},
|
|
|
Err(res) => {
|
|
|
println!("hit url: {}", res.url().unwrap().as_str());
|
|
|
println!("Status: {}", res.status().unwrap());
|
|
|
println!("Post error: {}", res.to_string());
|
|
|
+ (*self.inner.lock().unwrap()).exp_time = 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -246,7 +341,7 @@ impl ZeroIDC {
|
|
|
.add_extra_param("network_id", network_id)
|
|
|
.url();
|
|
|
|
|
|
- println!("URL: {}", auth_url);
|
|
|
+ // println!("URL: {}", auth_url);
|
|
|
|
|
|
return AuthInfo {
|
|
|
url: auth_url,
|