mirror of
https://github.com/Astatin3/unshell.git
synced 2026-06-09 06:47:59 -06:00
JWT Authentication
This commit is contained in:
Generated
+100
@@ -75,6 +75,15 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
|
checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android_system_properties"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arboard"
|
name = "arboard"
|
||||||
version = "3.6.1"
|
version = "3.6.1"
|
||||||
@@ -292,6 +301,19 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.42"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
|
||||||
|
dependencies = [
|
||||||
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
|
"num-traits",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clipboard-win"
|
name = "clipboard-win"
|
||||||
version = "5.4.1"
|
version = "5.4.1"
|
||||||
@@ -952,6 +974,30 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone"
|
||||||
|
version = "0.1.64"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
|
||||||
|
dependencies = [
|
||||||
|
"android_system_properties",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"iana-time-zone-haiku",
|
||||||
|
"js-sys",
|
||||||
|
"log",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone-haiku"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_collections"
|
name = "icu_collections"
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
@@ -2353,6 +2399,7 @@ checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
|||||||
name = "unshell-gui"
|
name = "unshell-gui"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
"eframe",
|
"eframe",
|
||||||
"egui",
|
"egui",
|
||||||
"egui_extras",
|
"egui_extras",
|
||||||
@@ -2748,12 +2795,65 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-core"
|
||||||
|
version = "0.62.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
|
||||||
|
dependencies = [
|
||||||
|
"windows-implement",
|
||||||
|
"windows-interface",
|
||||||
|
"windows-link",
|
||||||
|
"windows-result",
|
||||||
|
"windows-strings",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-implement"
|
||||||
|
version = "0.60.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-interface"
|
||||||
|
version = "0.59.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-link"
|
name = "windows-link"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-result"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-strings"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.45.0"
|
version = "0.45.0"
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ wasm-bindgen-futures = "0.4.50"
|
|||||||
wasm-bindgen = "0.2.106"
|
wasm-bindgen = "0.2.106"
|
||||||
web-sys = "0.3.70" # to access the DOM (to hide the loading text)
|
web-sys = "0.3.70" # to access the DOM (to hide the loading text)
|
||||||
serde_json = "1.0.145"
|
serde_json = "1.0.145"
|
||||||
|
chrono = "0.4.42"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = 2 # fast and small wasm
|
opt-level = 2 # fast and small wasm
|
||||||
|
|||||||
+26
-15
@@ -31,34 +31,45 @@ self.addEventListener("fetch", function (e) {
|
|||||||
// return xmlHttp.responseText;
|
// return xmlHttp.responseText;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
export function httpGet(theUrl, callback) {
|
function startHttpRequest(callback) {
|
||||||
var xmlHttp = new XMLHttpRequest();
|
var xmlHttp = new XMLHttpRequest();
|
||||||
xmlHttp.onreadystatechange = function () {
|
xmlHttp.onreadystatechange = function () {
|
||||||
if (xmlHttp.readyState !== 4) return;
|
if (xmlHttp.readyState !== 4) return;
|
||||||
|
|
||||||
if (xmlHttp.status == 200) callback(xmlHttp.responseText);
|
if (xmlHttp.status == 200) callback(true, xmlHttp.responseText);
|
||||||
else alert("Error " + xmlHttp.status + ", " + xmlHttp.responseText);
|
else callback(false, xmlHttp.responseText);
|
||||||
};
|
};
|
||||||
|
return xmlHttp;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function httpGet(theUrl, callback) {
|
||||||
|
var xmlHttp = startHttpRequest(callback);
|
||||||
xmlHttp.open("GET", theUrl, true); // true for asynchronous
|
xmlHttp.open("GET", theUrl, true); // true for asynchronous
|
||||||
xmlHttp.setRequestHeader("Content-Type", "application/json");
|
xmlHttp.setRequestHeader("Content-Type", "application/json");
|
||||||
xmlHttp.send(null);
|
xmlHttp.send(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function httpPost(url, body, callback) {
|
export function httpPost(url, body, callback) {
|
||||||
var xmlHttp = new XMLHttpRequest();
|
var xmlHttp = startHttpRequest(callback);
|
||||||
xmlHttp.onreadystatechange = function () {
|
|
||||||
if (xmlHttp.readyState !== 4) return;
|
|
||||||
|
|
||||||
if (xmlHttp.status === 200) {
|
|
||||||
// var json = JSON.parse(xhr.responseText);
|
|
||||||
callback(xmlHttp.responseText);
|
|
||||||
} else {
|
|
||||||
alert("Error " + xmlHttp.status + ", " + xmlHttp.responseText);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
xmlHttp.open("POST", url, true);
|
xmlHttp.open("POST", url, true);
|
||||||
xmlHttp.setRequestHeader("Content-Type", "application/json");
|
xmlHttp.setRequestHeader("Content-Type", "application/json");
|
||||||
// var data = JSON.stringify({ email: "[email protected]", password: "101010" });
|
// var data = JSON.stringify({ email: "[email protected]", password: "101010" });
|
||||||
xmlHttp.send(body);
|
xmlHttp.send(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function httpGetAuth(theUrl, auth, callback) {
|
||||||
|
var xmlHttp = startHttpRequest(callback);
|
||||||
|
xmlHttp.open("GET", theUrl, true); // true for asynchronous
|
||||||
|
xmlHttp.setRequestHeader("Content-Type", "application/json");
|
||||||
|
xmlHttp.setRequestHeader("authorization", auth);
|
||||||
|
xmlHttp.send(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function httpPostAuth(url, auth, body, callback) {
|
||||||
|
var xmlHttp = startHttpRequest(callback);
|
||||||
|
xmlHttp.open("POST", url, true);
|
||||||
|
xmlHttp.setRequestHeader("Content-Type", "application/json");
|
||||||
|
xmlHttp.setRequestHeader("authorization", auth);
|
||||||
|
// var data = JSON.stringify({ email: "[email protected]", password: "101010" });
|
||||||
|
xmlHttp.send(body);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,16 +1,12 @@
|
|||||||
use egui::Frame;
|
use egui::Frame;
|
||||||
use egui_tiles::Tree;
|
use egui_tiles::Tree;
|
||||||
|
|
||||||
use crate::{
|
use crate::app::{AppState, windows::WindowWrapper};
|
||||||
app::{AppState, windows::WindowWrapper},
|
|
||||||
auth::Auth,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// We derive Deserialize/Serialize so we can persist app state on shutdown.
|
/// We derive Deserialize/Serialize so we can persist app state on shutdown.
|
||||||
#[derive(serde::Deserialize, serde::Serialize)]
|
#[derive(serde::Deserialize, serde::Serialize)]
|
||||||
#[serde(default)] // if we add new fields, give them default values when deserializing old state
|
#[serde(default)] // if we add new fields, give them default values when deserializing old state
|
||||||
pub struct TemplateApp {
|
pub struct TemplateApp {
|
||||||
auth: Auth,
|
|
||||||
// tab: Tab,
|
// tab: Tab,
|
||||||
state: AppState,
|
state: AppState,
|
||||||
tree: Tree<WindowWrapper>,
|
tree: Tree<WindowWrapper>,
|
||||||
@@ -19,7 +15,6 @@ pub struct TemplateApp {
|
|||||||
impl Default for TemplateApp {
|
impl Default for TemplateApp {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
auth: Auth::default(),
|
|
||||||
state: AppState::default(),
|
state: AppState::default(),
|
||||||
tree: egui_tiles::Tree::new_horizontal("tree_root", Vec::new()),
|
tree: egui_tiles::Tree::new_horizontal("tree_root", Vec::new()),
|
||||||
}
|
}
|
||||||
@@ -50,10 +45,10 @@ impl eframe::App for TemplateApp {
|
|||||||
|
|
||||||
/// Called each time the UI needs repainting, which may be many times per second.
|
/// Called each time the UI needs repainting, which may be many times per second.
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
if !self.auth.logged_in() {
|
if !self.state.auth.logged_in() {
|
||||||
egui::CentralPanel::default()
|
egui::CentralPanel::default()
|
||||||
.frame(Frame::central_panel(&ctx.style()).inner_margin(0))
|
.frame(Frame::central_panel(&ctx.style()).inner_margin(0))
|
||||||
.show(ctx, |ui| self.auth.update(ui));
|
.show(ctx, |ui| self.state.auth.update(ui));
|
||||||
} else {
|
} else {
|
||||||
egui::TopBottomPanel::top("tab_panel").show(ctx, |ui| {
|
egui::TopBottomPanel::top("tab_panel").show(ctx, |ui| {
|
||||||
// The top panel is often a good place for a menu bar:
|
// The top panel is often a good place for a menu bar:
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ mod windows;
|
|||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{app::windows::WindowWrapper, config::Config, flowchart::FlowChart};
|
use crate::{app::windows::WindowWrapper, auth::Auth, config::Config, flowchart::FlowChart};
|
||||||
pub use app::TemplateApp;
|
pub use app::TemplateApp;
|
||||||
use egui_tiles::{TileId, Tree};
|
use egui_tiles::{TileId, Tree};
|
||||||
|
|
||||||
#[derive(Default, serde::Deserialize, serde::Serialize)]
|
#[derive(Default, serde::Deserialize, serde::Serialize)]
|
||||||
struct AppState {
|
pub struct AppState {
|
||||||
|
pub auth: Auth,
|
||||||
|
|
||||||
pub open_windows: HashMap<AppWindow, TileId>,
|
pub open_windows: HashMap<AppWindow, TileId>,
|
||||||
|
|
||||||
pub flowchart: FlowChart,
|
pub flowchart: FlowChart,
|
||||||
@@ -64,7 +66,7 @@ impl AppState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, serde::Deserialize, serde::Serialize, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, serde::Deserialize, serde::Serialize, PartialEq, Eq, Hash)]
|
||||||
enum AppWindow {
|
pub enum AppWindow {
|
||||||
Flowchart,
|
Flowchart,
|
||||||
Config,
|
Config,
|
||||||
}
|
}
|
||||||
@@ -73,7 +75,7 @@ impl AppWindow {
|
|||||||
fn update(&self, state: &mut AppState, ui: &mut egui::Ui) {
|
fn update(&self, state: &mut AppState, ui: &mut egui::Ui) {
|
||||||
match self {
|
match self {
|
||||||
AppWindow::Flowchart => state.flowchart.paint(ui),
|
AppWindow::Flowchart => state.flowchart.paint(ui),
|
||||||
AppWindow::Config => state.config.update(ui),
|
AppWindow::Config => state.config.update(&mut state.auth, ui),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+81
-39
@@ -1,5 +1,7 @@
|
|||||||
use std::{collections::HashMap, sync::Arc};
|
use serde_json::json;
|
||||||
|
use std::{collections::HashMap, sync::Arc, time::Duration};
|
||||||
|
|
||||||
|
use chrono::Utc;
|
||||||
use egui::{Align2, Area, Frame, Order, Sense, UiKind, Vec2, mutex::Mutex};
|
use egui::{Align2, Area, Frame, Order, Sense, UiKind, Vec2, mutex::Mutex};
|
||||||
use wasm_bindgen::prelude::Closure;
|
use wasm_bindgen::prelude::Closure;
|
||||||
|
|
||||||
@@ -12,18 +14,20 @@ pub struct Auth {
|
|||||||
|
|
||||||
// UI Stuff
|
// UI Stuff
|
||||||
username: String,
|
username: String,
|
||||||
|
#[serde(skip)]
|
||||||
password: String,
|
password: String,
|
||||||
show_password: bool,
|
show_password: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize, PartialEq, Eq)]
|
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, PartialEq, Eq)]
|
||||||
struct Token {
|
struct Token {
|
||||||
access_token: String,
|
expiration: u128,
|
||||||
token_type: String,
|
token: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
enum AuthState {
|
enum AuthState {
|
||||||
|
Unset,
|
||||||
NotLoggedIn,
|
NotLoggedIn,
|
||||||
RequestSent,
|
RequestSent,
|
||||||
Authorised(Token),
|
Authorised(Token),
|
||||||
@@ -32,25 +36,40 @@ enum AuthState {
|
|||||||
|
|
||||||
impl Default for AuthState {
|
impl Default for AuthState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::NotLoggedIn
|
Self::Unset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Auth {
|
impl Auth {
|
||||||
|
/// Refresh the authentication state
|
||||||
pub fn logged_in(&mut self) -> bool {
|
pub fn logged_in(&mut self) -> bool {
|
||||||
if self.token.is_some() {
|
match (self.token.is_some(), &*self.auth_state.lock()) {
|
||||||
true
|
// The client is actually authorized
|
||||||
} else {
|
(true, AuthState::Authorised(_)) => true,
|
||||||
match *self.auth_state.lock() {
|
|
||||||
AuthState::Authorised(ref token) => {
|
|
||||||
self.token = Some(token.clone());
|
|
||||||
true
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// self.auth_state.lock().eq(&AuthState::Authorised)
|
// If the user has just reloaded the session,
|
||||||
|
// the AuthState is not automatically set by any other process
|
||||||
|
(true, AuthState::Unset) => true,
|
||||||
|
|
||||||
|
// If the authentication state has been updated to unauthorized, delete the token
|
||||||
|
(true, _) => {
|
||||||
|
self.token = None;
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the authentication state has been updated to authorized, set the token
|
||||||
|
(false, AuthState::Authorised(token)) => {
|
||||||
|
self.token = Some(token.clone());
|
||||||
|
|
||||||
|
// Also clear the password because it is bad to store it
|
||||||
|
self.password.clear();
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
// The client is actually unauthorized
|
||||||
|
(false, _) => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, ui: &mut egui::Ui) {
|
pub fn update(&mut self, ui: &mut egui::Ui) {
|
||||||
@@ -82,38 +101,61 @@ impl Auth {
|
|||||||
// ui.toggle_value(&mut self.show_password, "Show");
|
// ui.toggle_value(&mut self.show_password, "Show");
|
||||||
});
|
});
|
||||||
|
|
||||||
if ui.button("Login").clicked() {
|
ui.horizontal(|ui| {
|
||||||
let json = serde_json::to_string(&HashMap::from([
|
if ui.button("Login").clicked() {
|
||||||
("client_id", self.username.clone()),
|
// Try to
|
||||||
("client_secret", self.password.clone()),
|
ui.ctx().request_repaint_after(Duration::from_millis(500));
|
||||||
]))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let state = self.auth_state.clone();
|
let state = self.auth_state.clone();
|
||||||
*(state.lock()) = AuthState::RequestSent;
|
|
||||||
|
|
||||||
crate::httpPost(
|
crate::httpPost(
|
||||||
"/auth",
|
"/auth",
|
||||||
&json,
|
&json!({
|
||||||
Closure::once_into_js(move |response: String| {
|
"username": self.username.clone(),
|
||||||
*(state.lock()) =
|
"password": self.password.clone()
|
||||||
if let Ok(token) = serde_json::from_str::<Token>(&response) {
|
})
|
||||||
AuthState::Authorised(token)
|
.to_string(),
|
||||||
|
Closure::once_into_js(move |ok: bool, response: String| {
|
||||||
|
*(state.lock()) = if ok {
|
||||||
|
if let Ok(token) = serde_json::from_str::<Token>(&response)
|
||||||
|
{
|
||||||
|
AuthState::Authorised(token)
|
||||||
|
} else {
|
||||||
|
AuthState::Error("Malformed Response".into())
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
AuthState::Error("Malformed Response".into())
|
AuthState::Error(response)
|
||||||
}
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
// self.logged_in
|
*(self.auth_state.lock()) = AuthState::RequestSent;
|
||||||
// .store(true, std::sync::atomic::Ordering::Relaxed);
|
}
|
||||||
// self.logged_in();
|
|
||||||
}),
|
ui.label(format!("{:?}", self.auth_state.lock()));
|
||||||
);
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// });
|
// });
|
||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn test(&self) {
|
||||||
|
if let Some(ref token) = self.token {
|
||||||
|
let state = self.auth_state.clone();
|
||||||
|
crate::httpGetAuth(
|
||||||
|
"/api/test1234/kjhejwer/kwherjwer/iuwehrhiwer/wiuerhjwer",
|
||||||
|
format!("Bearer {}", token.token),
|
||||||
|
Closure::once_into_js(move |ok: bool, response: String| {
|
||||||
|
if ok {
|
||||||
|
crate::log(&response);
|
||||||
|
} else {
|
||||||
|
*(state.lock()) = AuthState::Error(response);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Auth {
|
impl Default for Auth {
|
||||||
|
|||||||
@@ -1,230 +1,12 @@
|
|||||||
use egui::{TextStyle, Ui};
|
use crate::auth::Auth;
|
||||||
use egui_extras::{Column, TableBuilder};
|
|
||||||
|
|
||||||
#[derive(serde::Deserialize, serde::Serialize)]
|
#[derive(Default, serde::Deserialize, serde::Serialize)]
|
||||||
pub struct Config {
|
pub struct Config {}
|
||||||
state: ConfigState,
|
|
||||||
current_payloads: Vec<PayloadConfig>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(serde::Deserialize, serde::Serialize)]
|
|
||||||
enum ConfigState {
|
|
||||||
Base,
|
|
||||||
NewConfig(PayloadConfig),
|
|
||||||
EditConfig(usize, PayloadConfig),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Config {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
state: ConfigState::Base,
|
|
||||||
current_payloads: vec![PayloadConfig {
|
|
||||||
name: "Test".to_string(),
|
|
||||||
components: vec!["server".to_string()],
|
|
||||||
// runtimes: Vec::new(),
|
|
||||||
}],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
// pub fn title(&self) -> &str {
|
pub fn update(&mut self, auth: &mut Auth, ui: &mut egui::Ui) {
|
||||||
// match self.state {
|
if ui.button("Test").clicked() {
|
||||||
// ConfigState::Base => "Config",
|
auth.test();
|
||||||
// ConfigState::NewConfig(..) => "Config/New",
|
|
||||||
// ConfigState::EditConfig(..) => "Config/Edit",
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn update(&mut self, ui: &mut Ui) {
|
|
||||||
match &mut self.state {
|
|
||||||
ConfigState::Base => self.table_ui(ui),
|
|
||||||
ConfigState::EditConfig(_, config) => {
|
|
||||||
ui.heading("Edit Payload");
|
|
||||||
match Self::edit_ui(ui, config) {
|
|
||||||
Some(true) => {
|
|
||||||
if let ConfigState::EditConfig(n, config) =
|
|
||||||
std::mem::replace(&mut self.state, ConfigState::Base)
|
|
||||||
{
|
|
||||||
self.current_payloads[n] = config;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(false) => {
|
|
||||||
self.state = ConfigState::Base;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ConfigState::NewConfig(config) => {
|
|
||||||
ui.heading("Edit Payload");
|
|
||||||
match Self::edit_ui(ui, config) {
|
|
||||||
Some(true) => {
|
|
||||||
if let ConfigState::NewConfig(config) =
|
|
||||||
std::mem::replace(&mut self.state, ConfigState::Base)
|
|
||||||
{
|
|
||||||
self.current_payloads.push(config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(false) => {
|
|
||||||
self.state = ConfigState::Base;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn table_ui(&mut self, ui: &mut Ui) {
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.heading("Payloads");
|
|
||||||
|
|
||||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
|
||||||
if ui.button("New").clicked() {
|
|
||||||
self.state = ConfigState::NewConfig(PayloadConfig::new());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let body_text_size = TextStyle::Body.resolve(ui.style()).size;
|
|
||||||
use egui_extras::{Size, StripBuilder};
|
|
||||||
StripBuilder::new(ui)
|
|
||||||
.size(Size::remainder().at_least(100.0)) // for the table
|
|
||||||
.size(Size::exact(body_text_size)) // for the source code link
|
|
||||||
.vertical(|mut strip| {
|
|
||||||
strip.cell(|ui| {
|
|
||||||
egui::ScrollArea::horizontal().show(ui, |ui| {
|
|
||||||
let table = TableBuilder::new(ui)
|
|
||||||
.striped(true)
|
|
||||||
.resizable(true)
|
|
||||||
.cell_layout(egui::Layout::left_to_right(egui::Align::Center))
|
|
||||||
.column(Column::auto().resizable(false))
|
|
||||||
.column(Column::remainder())
|
|
||||||
.column(Column::remainder())
|
|
||||||
.column(Column::remainder())
|
|
||||||
.column(Column::auto().resizable(false))
|
|
||||||
.min_scrolled_height(0.0)
|
|
||||||
.sense(egui::Sense::click());
|
|
||||||
|
|
||||||
table
|
|
||||||
.header(20., |mut header| {
|
|
||||||
header.col(|ui| {
|
|
||||||
ui.strong("#");
|
|
||||||
});
|
|
||||||
header.col(|ui| {
|
|
||||||
ui.strong("Name");
|
|
||||||
});
|
|
||||||
header.col(|ui| {
|
|
||||||
ui.strong("Components");
|
|
||||||
});
|
|
||||||
header.col(|ui| {
|
|
||||||
ui.strong("Runtimes");
|
|
||||||
});
|
|
||||||
header.col(|_| {});
|
|
||||||
})
|
|
||||||
.body(|mut body| {
|
|
||||||
for i in 0..self.current_payloads.len() {
|
|
||||||
// let runtime = self.current_runtimes
|
|
||||||
|
|
||||||
body.row(18., |mut row| {
|
|
||||||
row.col(|ui| {
|
|
||||||
ui.label(i.to_string());
|
|
||||||
});
|
|
||||||
row.col(|ui| {
|
|
||||||
ui.label(self.current_payloads[i].name.clone());
|
|
||||||
});
|
|
||||||
row.col(|ui| {
|
|
||||||
ui.label(format!(
|
|
||||||
"{:?}",
|
|
||||||
self.current_payloads[i].components.clone()
|
|
||||||
));
|
|
||||||
});
|
|
||||||
row.col(|ui| {
|
|
||||||
ui.label("A");
|
|
||||||
});
|
|
||||||
row.col(|ui| {
|
|
||||||
if ui.button("Edit").clicked() {
|
|
||||||
self.state = ConfigState::EditConfig(
|
|
||||||
i,
|
|
||||||
self.current_payloads[i].clone(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// if ui.button("Delete").clicked() {
|
|
||||||
// self.state = ConfigState::EditConfig(
|
|
||||||
// i,
|
|
||||||
// self.current_payloads[i].clone(),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
});
|
|
||||||
|
|
||||||
if row.response().clicked() {
|
|
||||||
self.state = ConfigState::EditConfig(
|
|
||||||
i,
|
|
||||||
self.current_payloads[i].clone(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn edit_ui(ui: &mut Ui, config: &mut PayloadConfig) -> Option<bool> {
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.label("Name");
|
|
||||||
ui.text_edit_singleline(&mut config.name);
|
|
||||||
});
|
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.label("Components: ");
|
|
||||||
|
|
||||||
for component in vec!["client", "server"] {
|
|
||||||
let enabled = config
|
|
||||||
.components
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.find(|s| s.1.eq(component));
|
|
||||||
if ui.selectable_label(enabled.is_some(), component).clicked() {
|
|
||||||
if let Some((i, _)) = enabled {
|
|
||||||
let _ = config.components.remove(i);
|
|
||||||
} else {
|
|
||||||
config.components.push(component.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut ret = None;
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ret = if ui.button("Back").clicked() {
|
|
||||||
Some(false)
|
|
||||||
} else if ui.button("Save").clicked() {
|
|
||||||
Some(true)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
ret
|
|
||||||
|
|
||||||
// return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, serde::Deserialize, serde::Serialize)]
|
|
||||||
struct PayloadConfig {
|
|
||||||
name: String,
|
|
||||||
components: Vec<String>,
|
|
||||||
// runtimes: Vec<RuntimeConfig>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PayloadConfig {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
name: "New Payload".to_string(),
|
|
||||||
components: Vec::new(),
|
|
||||||
// runtimes: Vec::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,230 @@
|
|||||||
|
use egui::{TextStyle, Ui};
|
||||||
|
use egui_extras::{Column, TableBuilder};
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize, serde::Serialize)]
|
||||||
|
pub struct Config {
|
||||||
|
state: ConfigState,
|
||||||
|
current_payloads: Vec<PayloadConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize, serde::Serialize)]
|
||||||
|
enum ConfigState {
|
||||||
|
Base,
|
||||||
|
NewConfig(PayloadConfig),
|
||||||
|
EditConfig(usize, PayloadConfig),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Config {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
state: ConfigState::Base,
|
||||||
|
current_payloads: vec![PayloadConfig {
|
||||||
|
name: "Test".to_string(),
|
||||||
|
components: vec!["server".to_string()],
|
||||||
|
// runtimes: Vec::new(),
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
// pub fn title(&self) -> &str {
|
||||||
|
// match self.state {
|
||||||
|
// ConfigState::Base => "Config",
|
||||||
|
// ConfigState::NewConfig(..) => "Config/New",
|
||||||
|
// ConfigState::EditConfig(..) => "Config/Edit",
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub fn update(&mut self, ui: &mut Ui) {
|
||||||
|
match &mut self.state {
|
||||||
|
ConfigState::Base => self.table_ui(ui),
|
||||||
|
ConfigState::EditConfig(_, config) => {
|
||||||
|
ui.heading("Edit Payload");
|
||||||
|
match Self::edit_ui(ui, config) {
|
||||||
|
Some(true) => {
|
||||||
|
if let ConfigState::EditConfig(n, config) =
|
||||||
|
std::mem::replace(&mut self.state, ConfigState::Base)
|
||||||
|
{
|
||||||
|
self.current_payloads[n] = config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(false) => {
|
||||||
|
self.state = ConfigState::Base;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConfigState::NewConfig(config) => {
|
||||||
|
ui.heading("Edit Payload");
|
||||||
|
match Self::edit_ui(ui, config) {
|
||||||
|
Some(true) => {
|
||||||
|
if let ConfigState::NewConfig(config) =
|
||||||
|
std::mem::replace(&mut self.state, ConfigState::Base)
|
||||||
|
{
|
||||||
|
self.current_payloads.push(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(false) => {
|
||||||
|
self.state = ConfigState::Base;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn table_ui(&mut self, ui: &mut Ui) {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.heading("Payloads");
|
||||||
|
|
||||||
|
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||||
|
if ui.button("New").clicked() {
|
||||||
|
self.state = ConfigState::NewConfig(PayloadConfig::new());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let body_text_size = TextStyle::Body.resolve(ui.style()).size;
|
||||||
|
use egui_extras::{Size, StripBuilder};
|
||||||
|
StripBuilder::new(ui)
|
||||||
|
.size(Size::remainder().at_least(100.0)) // for the table
|
||||||
|
.size(Size::exact(body_text_size)) // for the source code link
|
||||||
|
.vertical(|mut strip| {
|
||||||
|
strip.cell(|ui| {
|
||||||
|
egui::ScrollArea::horizontal().show(ui, |ui| {
|
||||||
|
let table = TableBuilder::new(ui)
|
||||||
|
.striped(true)
|
||||||
|
.resizable(true)
|
||||||
|
.cell_layout(egui::Layout::left_to_right(egui::Align::Center))
|
||||||
|
.column(Column::auto().resizable(false))
|
||||||
|
.column(Column::remainder())
|
||||||
|
.column(Column::remainder())
|
||||||
|
.column(Column::remainder())
|
||||||
|
.column(Column::auto().resizable(false))
|
||||||
|
.min_scrolled_height(0.0)
|
||||||
|
.sense(egui::Sense::click());
|
||||||
|
|
||||||
|
table
|
||||||
|
.header(20., |mut header| {
|
||||||
|
header.col(|ui| {
|
||||||
|
ui.strong("#");
|
||||||
|
});
|
||||||
|
header.col(|ui| {
|
||||||
|
ui.strong("Name");
|
||||||
|
});
|
||||||
|
header.col(|ui| {
|
||||||
|
ui.strong("Components");
|
||||||
|
});
|
||||||
|
header.col(|ui| {
|
||||||
|
ui.strong("Runtimes");
|
||||||
|
});
|
||||||
|
header.col(|_| {});
|
||||||
|
})
|
||||||
|
.body(|mut body| {
|
||||||
|
for i in 0..self.current_payloads.len() {
|
||||||
|
// let runtime = self.current_runtimes
|
||||||
|
|
||||||
|
body.row(18., |mut row| {
|
||||||
|
row.col(|ui| {
|
||||||
|
ui.label(i.to_string());
|
||||||
|
});
|
||||||
|
row.col(|ui| {
|
||||||
|
ui.label(self.current_payloads[i].name.clone());
|
||||||
|
});
|
||||||
|
row.col(|ui| {
|
||||||
|
ui.label(format!(
|
||||||
|
"{:?}",
|
||||||
|
self.current_payloads[i].components.clone()
|
||||||
|
));
|
||||||
|
});
|
||||||
|
row.col(|ui| {
|
||||||
|
ui.label("A");
|
||||||
|
});
|
||||||
|
row.col(|ui| {
|
||||||
|
if ui.button("Edit").clicked() {
|
||||||
|
self.state = ConfigState::EditConfig(
|
||||||
|
i,
|
||||||
|
self.current_payloads[i].clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// if ui.button("Delete").clicked() {
|
||||||
|
// self.state = ConfigState::EditConfig(
|
||||||
|
// i,
|
||||||
|
// self.current_payloads[i].clone(),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
});
|
||||||
|
|
||||||
|
if row.response().clicked() {
|
||||||
|
self.state = ConfigState::EditConfig(
|
||||||
|
i,
|
||||||
|
self.current_payloads[i].clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn edit_ui(ui: &mut Ui, config: &mut PayloadConfig) -> Option<bool> {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label("Name");
|
||||||
|
ui.text_edit_singleline(&mut config.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label("Components: ");
|
||||||
|
|
||||||
|
for component in vec!["client", "server"] {
|
||||||
|
let enabled = config
|
||||||
|
.components
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find(|s| s.1.eq(component));
|
||||||
|
if ui.selectable_label(enabled.is_some(), component).clicked() {
|
||||||
|
if let Some((i, _)) = enabled {
|
||||||
|
let _ = config.components.remove(i);
|
||||||
|
} else {
|
||||||
|
config.components.push(component.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut ret = None;
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ret = if ui.button("Back").clicked() {
|
||||||
|
Some(false)
|
||||||
|
} else if ui.button("Save").clicked() {
|
||||||
|
Some(true)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
// return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, serde::Deserialize, serde::Serialize)]
|
||||||
|
struct PayloadConfig {
|
||||||
|
name: String,
|
||||||
|
components: Vec<String>,
|
||||||
|
// runtimes: Vec<RuntimeConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PayloadConfig {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
name: "New Payload".to_string(),
|
||||||
|
components: Vec::new(),
|
||||||
|
// runtimes: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -93,6 +93,12 @@ impl FlowChart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn paint(&mut self, ui: &mut Ui) {
|
pub fn paint(&mut self, ui: &mut Ui) {
|
||||||
|
if ui.button("Arrange").clicked() {
|
||||||
|
for _ in 0..1_000 {
|
||||||
|
self.force(0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let scene = Scene::new()
|
let scene = Scene::new()
|
||||||
// .max_inner_size([350.0, 1000.0])
|
// .max_inner_size([350.0, 1000.0])
|
||||||
.zoom_range(0.1..=2.0);
|
.zoom_range(0.1..=2.0);
|
||||||
@@ -135,11 +141,5 @@ impl FlowChart {
|
|||||||
if response.double_clicked() {
|
if response.double_clicked() {
|
||||||
self.scene_rect = inner_rect;
|
self.scene_rect = inner_rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ui.button("Arrange").clicked() {
|
|
||||||
for _ in 0..1_000 {
|
|
||||||
self.force(0.1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,10 @@ extern "C" {
|
|||||||
|
|
||||||
#[wasm_bindgen(module = "/assets/sw.js")]
|
#[wasm_bindgen(module = "/assets/sw.js")]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn httpGet(url: &str, callback: JsValue);
|
pub fn httpGet(url: &str, ok_callback: JsValue);
|
||||||
pub fn httpPost(url: &str, data: &str, callback: JsValue);
|
pub fn httpPost(url: &str, data: &str, ok_callback: JsValue);
|
||||||
|
pub fn httpGetAuth(url: &str, auth: String, ok_callback: JsValue);
|
||||||
|
pub fn httpPostAuth(url: &str, auth: String, data: &str, ok_callback: JsValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// }
|
// }
|
||||||
|
|||||||
Generated
+478
-90
@@ -2,6 +2,17 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aes"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cipher",
|
||||||
|
"cpufeatures",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.4"
|
version = "1.1.4"
|
||||||
@@ -11,6 +22,15 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android_system_properties"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atomic-waker"
|
name = "atomic-waker"
|
||||||
version = "1.1.2"
|
version = "1.1.2"
|
||||||
@@ -126,6 +146,45 @@ version = "0.22.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bcrypt"
|
||||||
|
version = "0.17.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "abaf6da45c74385272ddf00e1ac074c7d8a6c1a1dda376902bd6a427522a8b2c"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"blowfish",
|
||||||
|
"getrandom 0.3.4",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bincode"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
|
||||||
|
dependencies = [
|
||||||
|
"bincode_derive",
|
||||||
|
"serde",
|
||||||
|
"unty",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bincode_derive"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09"
|
||||||
|
dependencies = [
|
||||||
|
"virtue",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.10.0"
|
version = "2.10.0"
|
||||||
@@ -141,18 +200,61 @@ dependencies = [
|
|||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-padding"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-padding"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "710f1dd022ef4e93f8a438b4ba958de7f64308434fa6a87104481645cc30068b"
|
||||||
|
dependencies = [
|
||||||
|
"hybrid-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blowfish"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"cipher",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.19.0"
|
version = "3.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.11.0"
|
version = "1.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
|
checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cbc"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6"
|
||||||
|
dependencies = [
|
||||||
|
"cipher",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.48"
|
version = "1.2.48"
|
||||||
@@ -171,6 +273,41 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg_aliases"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg_aliases"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.42"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
|
||||||
|
dependencies = [
|
||||||
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
|
"num-traits",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cipher"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"inout",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cmake"
|
name = "cmake"
|
||||||
version = "0.1.54"
|
version = "0.1.54"
|
||||||
@@ -180,6 +317,12 @@ dependencies = [
|
|||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation-sys"
|
||||||
|
version = "0.8.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
@@ -189,6 +332,21 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-channel"
|
||||||
|
version = "0.5.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-common"
|
name = "crypto-common"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
@@ -335,6 +493,18 @@ dependencies = [
|
|||||||
"http",
|
"http",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex-literal"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e712f64ec3850b98572bffac52e2c6f282b29fe6c5fa6d42334b30be438d95c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@@ -380,6 +550,15 @@ version = "1.0.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hybrid-array"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f471e0a81b2f90ffc0cb2f951ae04da57de8baa46fa99112b062a5173a5088d0"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.8.1"
|
version = "1.8.1"
|
||||||
@@ -417,6 +596,40 @@ dependencies = [
|
|||||||
"tower-service",
|
"tower-service",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone"
|
||||||
|
version = "0.1.64"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
|
||||||
|
dependencies = [
|
||||||
|
"android_system_properties",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"iana-time-zone-haiku",
|
||||||
|
"js-sys",
|
||||||
|
"log",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone-haiku"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inout"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
|
||||||
|
dependencies = [
|
||||||
|
"block-padding 0.3.3",
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.15"
|
version = "1.0.15"
|
||||||
@@ -460,18 +673,22 @@ dependencies = [
|
|||||||
"simple_asn1",
|
"simple_asn1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lazy_static"
|
|
||||||
version = "1.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.177"
|
version = "0.2.177"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libloading"
|
||||||
|
version = "0.8.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.14"
|
version = "0.4.14"
|
||||||
@@ -487,15 +704,6 @@ version = "0.4.28"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "matchers"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
|
|
||||||
dependencies = [
|
|
||||||
"regex-automata",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matchit"
|
name = "matchit"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
@@ -525,15 +733,6 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nu-ansi-term"
|
|
||||||
version = "0.50.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
|
||||||
dependencies = [
|
|
||||||
"windows-sys 0.61.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint"
|
name = "num-bigint"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
@@ -631,6 +830,15 @@ version = "0.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.103"
|
version = "1.0.103"
|
||||||
@@ -655,6 +863,26 @@ version = "5.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||||
|
dependencies = [
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core 0.9.3",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core 0.9.3",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_core"
|
name = "rand_core"
|
||||||
version = "0.6.4"
|
version = "0.6.4"
|
||||||
@@ -664,13 +892,34 @@ dependencies = [
|
|||||||
"getrandom 0.2.16",
|
"getrandom 0.2.16",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.3.4",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.18"
|
version = "0.5.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags 2.10.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.12.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -735,7 +984,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.111",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -786,12 +1035,14 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sharded-slab"
|
name = "sha2"
|
||||||
version = "0.1.7"
|
version = "0.10.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -815,7 +1066,7 @@ version = "2.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -846,6 +1097,51 @@ dependencies = [
|
|||||||
"windows-sys 0.60.2",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "static_init"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8bae1df58c5fea7502e8e352ec26b5579f6178e1fdb311e088580c980dee25ed"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"cfg_aliases 0.2.1",
|
||||||
|
"libc",
|
||||||
|
"parking_lot",
|
||||||
|
"parking_lot_core",
|
||||||
|
"static_init_macro",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "static_init_macro"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1389c88ddd739ec6d3f8f83343764a0e944cd23cfbf126a9796a714b0b6edd6f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg_aliases 0.1.1",
|
||||||
|
"memchr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.109"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.111"
|
version = "2.0.111"
|
||||||
@@ -880,16 +1176,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.111",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thread_local"
|
|
||||||
version = "1.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -948,7 +1235,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.111",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -987,21 +1274,9 @@ checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"tracing-attributes",
|
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing-attributes"
|
|
||||||
version = "0.1.31"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-core"
|
name = "tracing-core"
|
||||||
version = "0.1.35"
|
version = "0.1.35"
|
||||||
@@ -1009,36 +1284,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c"
|
checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"valuable",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing-log"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"once_cell",
|
|
||||||
"tracing-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing-subscriber"
|
|
||||||
version = "0.3.22"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
|
|
||||||
dependencies = [
|
|
||||||
"matchers",
|
|
||||||
"nu-ansi-term",
|
|
||||||
"once_cell",
|
|
||||||
"regex-automata",
|
|
||||||
"sharded-slab",
|
|
||||||
"smallvec",
|
|
||||||
"thread_local",
|
|
||||||
"tracing",
|
|
||||||
"tracing-core",
|
|
||||||
"tracing-log",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1053,18 +1298,60 @@ version = "1.0.22"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unshell-crypt"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"aes",
|
||||||
|
"block-padding 0.4.2",
|
||||||
|
"cbc",
|
||||||
|
"getrandom 0.3.4",
|
||||||
|
"hex",
|
||||||
|
"hex-literal",
|
||||||
|
"regex",
|
||||||
|
"sha2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unshell-lib"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"bincode",
|
||||||
|
"chrono",
|
||||||
|
"crossbeam-channel",
|
||||||
|
"libc",
|
||||||
|
"libloading",
|
||||||
|
"rand",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"unshell-obfuscate",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unshell-obfuscate"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.111",
|
||||||
|
"unshell-crypt",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unshell-server"
|
name = "unshell-server"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"axum-extra",
|
"axum-extra",
|
||||||
|
"bcrypt",
|
||||||
|
"chrono",
|
||||||
"jsonwebtoken",
|
"jsonwebtoken",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"static_init",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"unshell-lib",
|
||||||
"tracing-subscriber",
|
"unshell-obfuscate",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1074,10 +1361,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "valuable"
|
name = "unty"
|
||||||
version = "0.1.1"
|
version = "0.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
@@ -1085,6 +1372,12 @@ version = "0.9.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "virtue"
|
||||||
|
version = "0.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.1+wasi-snapshot-preview1"
|
version = "0.11.1+wasi-snapshot-preview1"
|
||||||
@@ -1132,7 +1425,7 @@ dependencies = [
|
|||||||
"bumpalo",
|
"bumpalo",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.111",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1145,12 +1438,87 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-core"
|
||||||
|
version = "0.62.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
|
||||||
|
dependencies = [
|
||||||
|
"windows-implement",
|
||||||
|
"windows-interface",
|
||||||
|
"windows-link",
|
||||||
|
"windows-result",
|
||||||
|
"windows-strings",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-implement"
|
||||||
|
version = "0.60.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.111",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-interface"
|
||||||
|
version = "0.59.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.111",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-link"
|
name = "windows-link"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-result"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-strings"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.60.2"
|
version = "0.60.2"
|
||||||
@@ -1240,6 +1608,26 @@ version = "0.46.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.8.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.8.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.111",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zeroize"
|
name = "zeroize"
|
||||||
version = "1.8.2"
|
version = "1.8.2"
|
||||||
|
|||||||
@@ -3,15 +3,30 @@ name = "unshell-server"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
log_debug = []
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
|
unshell-lib = {path = "../unshell-lib"}
|
||||||
|
unshell-obfuscate = {path = "../unshell-obfuscate"}
|
||||||
|
|
||||||
axum = "0.8.7"
|
axum = "0.8.7"
|
||||||
axum-extra = {version="0.12.2", features = ["typed-header"]}
|
axum-extra = {version="0.12.2", features = ["typed-header"]}
|
||||||
jsonwebtoken = {version = "10.2.0", features = ["aws_lc_rs"]}
|
jsonwebtoken = {version = "10.2.0", features = ["aws_lc_rs"]}
|
||||||
serde = {version = "1.0.228", features = ["derive"]}
|
serde = {version = "1.0.228", features = ["derive"]}
|
||||||
serde_json = "1.0.145"
|
serde_json = "1.0.145"
|
||||||
tokio = {version="1.48.0", features = ["full"] }
|
tokio = {version="1.48.0", features = ["full"] }
|
||||||
tracing = "0.1.43"
|
bcrypt = "0.17.1"
|
||||||
tracing-subscriber = {version="0.3.22", features = ["env-filter"] }
|
chrono = "0.4.42"
|
||||||
|
static_init = "1.0.4"
|
||||||
|
|
||||||
|
# tracing = "0.1.43"
|
||||||
|
# tracing-subscriber = {version="0.3.22", features = ["env-filter"] }
|
||||||
|
|
||||||
|
|
||||||
# async-trait = "0.1.89"
|
# async-trait = "0.1.89"
|
||||||
# axum = "0.8.7"
|
# axum = "0.8.7"
|
||||||
# axum-extra = "0.12.2"
|
# axum-extra = "0.12.2"
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
use crate::{auth, structs::CurrentUser};
|
||||||
|
use axum::{
|
||||||
|
Extension, Router,
|
||||||
|
extract::Path,
|
||||||
|
middleware,
|
||||||
|
response::IntoResponse,
|
||||||
|
routing::{get, post},
|
||||||
|
};
|
||||||
|
use unshell_lib::info;
|
||||||
|
|
||||||
|
pub async fn app() -> Router {
|
||||||
|
Router::new().route("/auth", post(auth::sign_in)).route(
|
||||||
|
"/api/{*path}",
|
||||||
|
get(protected).layer(middleware::from_fn(auth::authorize)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn protected(
|
||||||
|
Path(path): Path<String>,
|
||||||
|
Extension(currentUser): Extension<CurrentUser>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
info!("{}", path);
|
||||||
|
// Json(UserResponse {
|
||||||
|
// email: currentUser.email,
|
||||||
|
// first_name: currentUser.first_name,
|
||||||
|
// last_name: currentUser.last_name,
|
||||||
|
// })
|
||||||
|
"Test"
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
use axum::{
|
||||||
|
body::Body,
|
||||||
|
extract::{Json, Request},
|
||||||
|
http::{self, Response, StatusCode},
|
||||||
|
middleware::Next,
|
||||||
|
};
|
||||||
|
use bcrypt::{DEFAULT_COST, hash, verify};
|
||||||
|
use chrono::Utc;
|
||||||
|
use jsonwebtoken::{Header, TokenData, Validation, decode, encode};
|
||||||
|
use serde_json::{Value, json};
|
||||||
|
use unshell_lib::info;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
EXPIRE_DURATION, JWT_DECODING_KEY, JWT_ENCODING_KEY,
|
||||||
|
structs::{AuthError, Cliams, CurrentUser, SignInData},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn hash_password(password: &str) -> Result<String, bcrypt::BcryptError> {
|
||||||
|
let hash = hash(password, DEFAULT_COST)?;
|
||||||
|
Ok(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encode_jwt(email: String) -> Result<(String, usize), StatusCode> {
|
||||||
|
let now = Utc::now();
|
||||||
|
let exp = (now + EXPIRE_DURATION).timestamp() as usize;
|
||||||
|
let iat = now.timestamp() as usize;
|
||||||
|
|
||||||
|
let claim = Cliams { iat, exp, email };
|
||||||
|
|
||||||
|
let token = encode(&Header::default(), &claim, &JWT_ENCODING_KEY)
|
||||||
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
|
|
||||||
|
Ok((token, exp))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode_jwt(jwt: String) -> Result<TokenData<Cliams>, StatusCode> {
|
||||||
|
decode(&jwt, &JWT_DECODING_KEY, &Validation::default())
|
||||||
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn authorize(mut req: Request, next: Next) -> Result<Response<Body>, AuthError> {
|
||||||
|
let auth_header = req.headers_mut().get(http::header::AUTHORIZATION);
|
||||||
|
|
||||||
|
let auth_header = match auth_header {
|
||||||
|
Some(header) => header.to_str().map_err(|_| AuthError {
|
||||||
|
message: "Empty header is not allowed".to_string(),
|
||||||
|
status_code: StatusCode::FORBIDDEN,
|
||||||
|
})?,
|
||||||
|
None => {
|
||||||
|
return Err(AuthError {
|
||||||
|
message: "Please add the JWT token to the header".to_string(),
|
||||||
|
status_code: StatusCode::FORBIDDEN,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut header = auth_header.split_whitespace();
|
||||||
|
|
||||||
|
let (_, token) = (header.next(), header.next());
|
||||||
|
|
||||||
|
let token_data = match decode_jwt(token.unwrap().to_string()) {
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(_) => {
|
||||||
|
return Err(AuthError {
|
||||||
|
message: "Invalid Session".to_string(),
|
||||||
|
status_code: StatusCode::UNAUTHORIZED,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fetch the user details from the database
|
||||||
|
let current_user = match retrieve_user_by_email(&token_data.claims.email) {
|
||||||
|
Some(user) => user,
|
||||||
|
None => {
|
||||||
|
return Err(AuthError {
|
||||||
|
message: "Unauthorized".to_string(),
|
||||||
|
status_code: StatusCode::UNAUTHORIZED,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
req.extensions_mut().insert(current_user);
|
||||||
|
Ok(next.run(req).await)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn sign_in(Json(user_data): Json<SignInData>) -> Result<Json<Value>, StatusCode> {
|
||||||
|
// 1. Retrieve user from the database
|
||||||
|
let user = match retrieve_user_by_email(&user_data.username) {
|
||||||
|
Some(user) => user,
|
||||||
|
None => return Err(StatusCode::UNAUTHORIZED), // User not found
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. Compare the password
|
||||||
|
if !verify(&user_data.password, &user.password_hash)
|
||||||
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||||
|
// Handle bcrypt errors
|
||||||
|
{
|
||||||
|
return Err(StatusCode::UNAUTHORIZED); // Wrong password
|
||||||
|
}
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"Authenticated user {} for {}",
|
||||||
|
user_data.username, EXPIRE_DURATION
|
||||||
|
);
|
||||||
|
|
||||||
|
// 3. Generate JWT
|
||||||
|
let (token, experation) =
|
||||||
|
encode_jwt(user.email).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
|
|
||||||
|
// 4. Return the token
|
||||||
|
Ok(Json(json!({
|
||||||
|
"token": token,
|
||||||
|
"expiration": experation,
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn retrieve_user_by_email(_email: &str) -> Option<CurrentUser> {
|
||||||
|
let current_user: CurrentUser = CurrentUser {
|
||||||
|
email: "foo".to_string(),
|
||||||
|
first_name: "Eze".to_string(),
|
||||||
|
last_name: "Sunday".to_string(),
|
||||||
|
password_hash: hash_password("bar").unwrap(),
|
||||||
|
};
|
||||||
|
Some(current_user)
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#![macro_use]
|
||||||
|
|
||||||
|
use chrono::Duration;
|
||||||
|
use jsonwebtoken::{DecodingKey, EncodingKey};
|
||||||
|
use static_init::dynamic;
|
||||||
|
extern crate unshell_lib;
|
||||||
|
|
||||||
|
pub mod app;
|
||||||
|
mod auth;
|
||||||
|
mod structs;
|
||||||
|
mod userdata;
|
||||||
|
|
||||||
|
static EXPIRE_DURATION: Duration = Duration::seconds(10);
|
||||||
|
|
||||||
|
#[dynamic]
|
||||||
|
static JWT_SECRET: String = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set");
|
||||||
|
|
||||||
|
#[dynamic]
|
||||||
|
static JWT_ENCODING_KEY: EncodingKey = EncodingKey::from_secret(JWT_SECRET.as_bytes());
|
||||||
|
#[dynamic]
|
||||||
|
static JWT_DECODING_KEY: DecodingKey = DecodingKey::from_secret(JWT_SECRET.as_bytes());
|
||||||
+15
-193
@@ -1,200 +1,22 @@
|
|||||||
//! Example JWT authorization/authentication.
|
use axum;
|
||||||
//!
|
use tokio::net::TcpListener;
|
||||||
//! Run with
|
use unshell_lib::info;
|
||||||
//!
|
|
||||||
//! ```not_rust
|
|
||||||
//! JWT_SECRET=secret cargo run -p example-jwt
|
|
||||||
//! ```
|
|
||||||
|
|
||||||
use axum::{
|
use unshell_server::app;
|
||||||
Json, RequestPartsExt, Router,
|
|
||||||
extract::FromRequestParts,
|
|
||||||
http::{StatusCode, request::Parts},
|
|
||||||
response::{IntoResponse, Response},
|
|
||||||
routing::{get, post},
|
|
||||||
};
|
|
||||||
use axum_extra::{
|
|
||||||
TypedHeader,
|
|
||||||
headers::{Authorization, authorization::Bearer},
|
|
||||||
};
|
|
||||||
use jsonwebtoken::{DecodingKey, EncodingKey, Header, Validation, decode, encode};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use serde_json::json;
|
|
||||||
use std::fmt::Display;
|
|
||||||
use std::sync::LazyLock;
|
|
||||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
|
||||||
|
|
||||||
// Quick instructions
|
|
||||||
//
|
|
||||||
// - get an authorization token:
|
|
||||||
//
|
|
||||||
// curl -s \
|
|
||||||
// -w '\n' \
|
|
||||||
// -H 'Content-Type: application/json' \
|
|
||||||
// -d '{"client_id":"foo","client_secret":"bar"}' \
|
|
||||||
// http://localhost:3000/authorize
|
|
||||||
//
|
|
||||||
// - visit the protected area using the authorized token
|
|
||||||
//
|
|
||||||
// curl -s \
|
|
||||||
// -w '\n' \
|
|
||||||
// -H 'Content-Type: application/json' \
|
|
||||||
// -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUiLCJleHAiOjEwMDAwMDAwMDAwfQ.M3LAZmrzUkXDC1q5mSzFAs_kJrwuKz3jOoDmjJ0G4gM' \
|
|
||||||
// http://localhost:3000/protected
|
|
||||||
//
|
|
||||||
// - try to visit the protected area using an invalid token
|
|
||||||
//
|
|
||||||
// curl -s \
|
|
||||||
// -w '\n' \
|
|
||||||
// -H 'Content-Type: application/json' \
|
|
||||||
// -H 'Authorization: Bearer blahblahblah' \
|
|
||||||
// http://localhost:3000/protected
|
|
||||||
|
|
||||||
static KEYS: LazyLock<Keys> = LazyLock::new(|| {
|
|
||||||
let secret = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set");
|
|
||||||
Keys::new(secret.as_bytes())
|
|
||||||
});
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
tracing_subscriber::registry()
|
unshell_lib::logger::PrettyLogger::init();
|
||||||
.with(
|
|
||||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
|
||||||
.unwrap_or_else(|_| format!("{}=debug", env!("CARGO_CRATE_NAME")).into()),
|
|
||||||
)
|
|
||||||
.with(tracing_subscriber::fmt::layer())
|
|
||||||
.init();
|
|
||||||
|
|
||||||
let app = Router::new()
|
let listener = TcpListener::bind("127.0.0.1:3000")
|
||||||
.route("/auth", post(authorize))
|
|
||||||
.route("/protected", get(protected));
|
|
||||||
|
|
||||||
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
|
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.expect("Unable to start listener");
|
||||||
tracing::debug!("listening on {}", listener.local_addr().unwrap());
|
|
||||||
axum::serve(listener, app).await.unwrap();
|
info!("Listening on {}", listener.local_addr().unwrap());
|
||||||
}
|
|
||||||
|
let app = app::app().await;
|
||||||
async fn protected(claims: Claims) -> Result<String, AuthError> {
|
|
||||||
// Send the protected data to the user
|
axum::serve(listener, app)
|
||||||
Ok(format!(
|
.await
|
||||||
"Welcome to the protected area :)\nYour data:\n{claims}",
|
.expect("Error serving application");
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn authorize(Json(payload): Json<AuthPayload>) -> Result<Json<AuthBody>, AuthError> {
|
|
||||||
println!("EEE");
|
|
||||||
|
|
||||||
// Check if the user sent the credentials
|
|
||||||
if payload.client_id.is_empty() || payload.client_secret.is_empty() {
|
|
||||||
return Err(AuthError::MissingCredentials);
|
|
||||||
}
|
|
||||||
// Here you can check the user credentials from a database
|
|
||||||
if payload.client_id != "foo" || payload.client_secret != "bar" {
|
|
||||||
return Err(AuthError::WrongCredentials);
|
|
||||||
}
|
|
||||||
let claims = Claims {
|
|
||||||
sub: "b@b.com".to_owned(),
|
|
||||||
company: "ACME".to_owned(),
|
|
||||||
// Mandatory expiry time as UTC timestamp
|
|
||||||
exp: 2000000000, // May 2033
|
|
||||||
};
|
|
||||||
// Create the authorization token
|
|
||||||
let token = encode(&Header::default(), &claims, &KEYS.encoding)
|
|
||||||
.map_err(|_| AuthError::TokenCreation)?;
|
|
||||||
|
|
||||||
// Send the authorized token
|
|
||||||
Ok(Json(AuthBody::new(token)))
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Claims {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "Email: {}\nCompany: {}", self.sub, self.company)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AuthBody {
|
|
||||||
fn new(access_token: String) -> Self {
|
|
||||||
Self {
|
|
||||||
access_token,
|
|
||||||
token_type: "Bearer".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> FromRequestParts<S> for Claims
|
|
||||||
where
|
|
||||||
S: Send + Sync,
|
|
||||||
{
|
|
||||||
type Rejection = AuthError;
|
|
||||||
|
|
||||||
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
|
|
||||||
// Extract the token from the authorization header
|
|
||||||
let TypedHeader(Authorization(bearer)) = parts
|
|
||||||
.extract::<TypedHeader<Authorization<Bearer>>>()
|
|
||||||
.await
|
|
||||||
.map_err(|_| AuthError::InvalidToken)?;
|
|
||||||
// Decode the user data
|
|
||||||
let token_data = decode::<Claims>(bearer.token(), &KEYS.decoding, &Validation::default())
|
|
||||||
.map_err(|_| AuthError::InvalidToken)?;
|
|
||||||
|
|
||||||
Ok(token_data.claims)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoResponse for AuthError {
|
|
||||||
fn into_response(self) -> Response {
|
|
||||||
let (status, error_message) = match self {
|
|
||||||
AuthError::WrongCredentials => (StatusCode::UNAUTHORIZED, "Wrong credentials"),
|
|
||||||
AuthError::MissingCredentials => (StatusCode::BAD_REQUEST, "Missing credentials"),
|
|
||||||
AuthError::TokenCreation => (StatusCode::INTERNAL_SERVER_ERROR, "Token creation error"),
|
|
||||||
AuthError::InvalidToken => (StatusCode::BAD_REQUEST, "Invalid token"),
|
|
||||||
};
|
|
||||||
let body = Json(json!({
|
|
||||||
"error": error_message,
|
|
||||||
}));
|
|
||||||
(status, body).into_response()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Keys {
|
|
||||||
encoding: EncodingKey,
|
|
||||||
decoding: DecodingKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Keys {
|
|
||||||
fn new(secret: &[u8]) -> Self {
|
|
||||||
Self {
|
|
||||||
encoding: EncodingKey::from_secret(secret),
|
|
||||||
decoding: DecodingKey::from_secret(secret),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
struct Claims {
|
|
||||||
sub: String,
|
|
||||||
company: String,
|
|
||||||
exp: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
|
||||||
struct AuthBody {
|
|
||||||
access_token: String,
|
|
||||||
token_type: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
struct AuthPayload {
|
|
||||||
client_id: String,
|
|
||||||
client_secret: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum AuthError {
|
|
||||||
WrongCredentials,
|
|
||||||
MissingCredentials,
|
|
||||||
TokenCreation,
|
|
||||||
InvalidToken,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
use axum::{
|
||||||
|
Json,
|
||||||
|
body::Body,
|
||||||
|
http::{Response, StatusCode},
|
||||||
|
response::IntoResponse,
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct SignInData {
|
||||||
|
pub username: String,
|
||||||
|
pub password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct CurrentUser {
|
||||||
|
pub email: String,
|
||||||
|
pub first_name: String,
|
||||||
|
pub last_name: String,
|
||||||
|
pub password_hash: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct Cliams {
|
||||||
|
// pub exp: u128,
|
||||||
|
// pub iat: u128,
|
||||||
|
//
|
||||||
|
pub exp: usize,
|
||||||
|
pub iat: usize,
|
||||||
|
pub email: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AuthError {
|
||||||
|
pub message: String,
|
||||||
|
pub status_code: StatusCode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoResponse for AuthError {
|
||||||
|
fn into_response(self) -> Response<Body> {
|
||||||
|
let body = Json(json!({
|
||||||
|
"error": self.message,
|
||||||
|
}));
|
||||||
|
|
||||||
|
(self.status_code, body).into_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
pub struct UserData {
|
||||||
|
username: String,
|
||||||
|
hash: Vec<u8>,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user