login implemented
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,6 +8,7 @@ rust_dist
|
|||||||
deno_dist
|
deno_dist
|
||||||
node_modules
|
node_modules
|
||||||
.env
|
.env
|
||||||
|
mize_config.toml
|
||||||
|
|
||||||
# I put testing stuff for this projekt that I don't want to push to github into a folder called gitignore
|
# I put testing stuff for this projekt that I don't want to push to github into a folder called gitignore
|
||||||
gitignore
|
gitignore
|
||||||
|
|||||||
1425
Cargo.lock
generated
1425
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,5 @@ members = [
|
|||||||
"packages/marts",
|
"packages/marts",
|
||||||
"packages/mize",
|
"packages/mize",
|
||||||
"packages/ppc",
|
"packages/ppc",
|
||||||
"test", "test",
|
|
||||||
]
|
]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ mize = { path = "../mize/", default-features = false }
|
|||||||
tokio = "1.49.0"
|
tokio = "1.49.0"
|
||||||
# https://github.com/rscarson/rustyscript/pull/415
|
# https://github.com/rscarson/rustyscript/pull/415
|
||||||
rustyscript = { git = 'https://github.com/rscarson/rustyscript', rev = 'e39529eac2c5d37cfcbb7d7d63da7264d7a5afdb', optional = true }
|
rustyscript = { git = 'https://github.com/rscarson/rustyscript', rev = 'e39529eac2c5d37cfcbb7d7d63da7264d7a5afdb', optional = true }
|
||||||
deno_core = { version = "0.380.1", optional = true }
|
#deno_core = { version = "0.380.1", optional = true }
|
||||||
chrono = "0.4.44"
|
chrono = "0.4.44"
|
||||||
reqwest = { version = "0.13.2", features = ["blocking", "json"] }
|
reqwest = { version = "0.13.2", features = ["blocking", "json"] }
|
||||||
serde = "1.0.228"
|
serde = "1.0.228"
|
||||||
@@ -21,7 +21,7 @@ rusqlite = { version = "0.31", features = ["bundled"], optional = true }
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["target-os"]
|
default = ["target-os"]
|
||||||
target-os = [ "clap", "mize/target-os", "deno_core", "rustyscript", "rusqlite" ]
|
target-os = [ "clap", "mize/target-os", "rustyscript", "rusqlite" ]
|
||||||
target-wasm = [ "mize/target-wasm" ]
|
target-wasm = [ "mize/target-wasm" ]
|
||||||
clap = ["dep:clap"]
|
clap = ["dep:clap"]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use mize::{mize_err, mize_part, Mize, MizeError, MizePart, MizeResult};
|
use mize::{mize_err, mize_part, Mize, MizeError, MizePart, MizeResult};
|
||||||
use reqwest::{blocking::Client, blocking::RequestBuilder, blocking::Response, header, Method};
|
use reqwest::{blocking::Client, blocking::Response, header, Method};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
use mize::MizeResult;
|
use mize::MizeResult;
|
||||||
|
|
||||||
#[cfg(feature = "target-os")]
|
#[cfg(feature = "target-os")]
|
||||||
@@ -15,5 +16,7 @@ pub mod c2vi;
|
|||||||
#[cfg(feature = "target-os")]
|
#[cfg(feature = "target-os")]
|
||||||
pub use c2vi::*;
|
pub use c2vi::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "target-os")]
|
||||||
pub mod js;
|
pub mod js;
|
||||||
|
#[cfg(feature = "target-os")]
|
||||||
pub use js::*;
|
pub use js::*;
|
||||||
|
|||||||
@@ -267,6 +267,10 @@ rec {
|
|||||||
################# dev Shels ###################
|
################# dev Shels ###################
|
||||||
|
|
||||||
mkMizeRustShell = attrs: mkMizeModuleShell (attrs // {
|
mkMizeRustShell = attrs: mkMizeModuleShell (attrs // {
|
||||||
|
shellHook = ''
|
||||||
|
mize_project_root=$(${lib.getExe pkgs.git} rev-parse --show-toplevel)
|
||||||
|
export MIZE_CONFIG_FILES=$mize_project_root/mize_config.toml
|
||||||
|
'';
|
||||||
#_shell_type = "rust";
|
#_shell_type = "rust";
|
||||||
nativeBuildInputs = attrs.nativeBuildInputs or [] ++ [
|
nativeBuildInputs = attrs.nativeBuildInputs or [] ++ [
|
||||||
pkgs.wasm-pack
|
pkgs.wasm-pack
|
||||||
@@ -274,6 +278,10 @@ rec {
|
|||||||
pkgs.spacetimedb
|
pkgs.spacetimedb
|
||||||
pkgs.deno
|
pkgs.deno
|
||||||
pkgs.pkg-config
|
pkgs.pkg-config
|
||||||
|
pkgs.gobject-introspection
|
||||||
|
pkgs.gobject-introspection.dev
|
||||||
|
|
||||||
|
# thanks to: https://github.com/NixOS/nixpkgs/pull/496279/changes
|
||||||
(pkgs.buildWasmBindgenCli rec {
|
(pkgs.buildWasmBindgenCli rec {
|
||||||
src = pkgs.fetchCrate {
|
src = pkgs.fetchCrate {
|
||||||
pname = "wasm-bindgen-cli";
|
pname = "wasm-bindgen-cli";
|
||||||
@@ -307,8 +315,38 @@ rec {
|
|||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
buildInputs = [
|
buildInputs = with pkgs; [
|
||||||
pkgsCross.openssl
|
at-spi2-atk
|
||||||
|
atkmm
|
||||||
|
cairo
|
||||||
|
gdk-pixbuf
|
||||||
|
glib
|
||||||
|
gtk3
|
||||||
|
harfbuzz
|
||||||
|
librsvg
|
||||||
|
libsoup_3
|
||||||
|
pango
|
||||||
|
webkitgtk_4_1
|
||||||
|
openssl
|
||||||
|
wasm-bindgen-cli
|
||||||
|
lld_20
|
||||||
|
xdotool
|
||||||
|
];
|
||||||
|
|
||||||
|
LD_LIBRARY_PATH = with pkgs; pkgs.lib.makeLibraryPath [
|
||||||
|
xdotool
|
||||||
|
webkitgtk_4_1
|
||||||
|
pango
|
||||||
|
openssl
|
||||||
|
at-spi2-atk
|
||||||
|
atkmm
|
||||||
|
cairo
|
||||||
|
gdk-pixbuf
|
||||||
|
glib
|
||||||
|
gtk3
|
||||||
|
harfbuzz
|
||||||
|
librsvg
|
||||||
|
libsoup_3
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
use crate::mize_err;
|
||||||
use crate::MizeResult;
|
use crate::MizeResult;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::env;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use crate::item::ItemData;
|
use crate::item::ItemData;
|
||||||
use crate::Mize;
|
use crate::Mize;
|
||||||
|
use crate::MizeError;
|
||||||
|
|
||||||
type ConfigThunk = Box<dyn Fn() -> ItemData + Send + Sync>;
|
type ConfigThunk = Box<dyn Fn() -> ItemData + Send + Sync>;
|
||||||
|
|
||||||
@@ -42,5 +45,34 @@ pub fn gather_config(mize: &mut Mize) -> MizeResult<()> {
|
|||||||
part.as_deref().unwrap().opts(&mut mize.clone());
|
part.as_deref().unwrap().opts(&mut mize.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// populate values from config files
|
||||||
|
let config_file_paths = env::var("MIZE_CONFIG_FILES")?;
|
||||||
|
for config_file_path in config_file_paths.split(":") {
|
||||||
|
println!("reading config file: {config_file_path}");
|
||||||
|
let content = std::fs::read_to_string(config_file_path)?;
|
||||||
|
let mut data = ItemData::from_toml(content.as_str())?;
|
||||||
|
println!("config data: {data}");
|
||||||
|
for path in data.get_paths_recursive()? {
|
||||||
|
let conf_name = path.replace("/", ".");
|
||||||
|
println!("adding config {conf_name} from config file {config_file_path}");
|
||||||
|
let val = data.get_path(path.split("/").collect::<Vec<&str>>())?;
|
||||||
|
match config_opts.get_mut(&conf_name) {
|
||||||
|
Some(opt) => {
|
||||||
|
opt.val = Some(val);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
config_opts.insert(
|
||||||
|
conf_name.clone(),
|
||||||
|
ConfigOpt {
|
||||||
|
name: conf_name,
|
||||||
|
val: Some(val),
|
||||||
|
thunk: None,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ impl Mize {
|
|||||||
|
|
||||||
let mut instance = Mize::empty()?;
|
let mut instance = Mize::empty()?;
|
||||||
|
|
||||||
instance.init();
|
instance.init()?;
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"instance inited with config: {}",
|
"instance inited with config: {}",
|
||||||
@@ -868,6 +868,7 @@ impl Mize {
|
|||||||
|
|
||||||
// get the cached value
|
// get the cached value
|
||||||
if let Some(val) = opt.val.clone() {
|
if let Some(val) = opt.val.clone() {
|
||||||
|
println!("get_config: {name} has cached value: {val}");
|
||||||
return Ok(val);
|
return Ok(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -886,12 +887,17 @@ impl Mize {
|
|||||||
|
|
||||||
pub fn new_opt(&mut self, name: &str) -> ConfigOptNameAndMize {
|
pub fn new_opt(&mut self, name: &str) -> ConfigOptNameAndMize {
|
||||||
let mut config_opts = self.config_opts.lock().unwrap();
|
let mut config_opts = self.config_opts.lock().unwrap();
|
||||||
|
match config_opts.get_mut(name) {
|
||||||
|
Some(opt) => {}
|
||||||
|
None => {
|
||||||
let opt = ConfigOpt {
|
let opt = ConfigOpt {
|
||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
val: None,
|
val: None,
|
||||||
thunk: None,
|
thunk: None,
|
||||||
};
|
};
|
||||||
config_opts.insert(name.to_string(), opt);
|
config_opts.insert(name.to_string(), opt);
|
||||||
|
}
|
||||||
|
}
|
||||||
ConfigOptNameAndMize {
|
ConfigOptNameAndMize {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
mize: self.clone(),
|
mize: self.clone(),
|
||||||
|
|||||||
@@ -286,6 +286,46 @@ impl ItemData {
|
|||||||
.to_owned()
|
.to_owned()
|
||||||
.into_item_data())
|
.into_item_data())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_paths_recursive(&mut self) -> MizeResult<Vec<String>> {
|
||||||
|
let mut paths = Vec::new();
|
||||||
|
let mut path_accu = Vec::new();
|
||||||
|
get_paths(&mut self.0, &mut paths, &mut path_accu, true)?;
|
||||||
|
Ok(paths)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_paths(&mut self) -> MizeResult<Vec<String>> {
|
||||||
|
let mut paths = Vec::new();
|
||||||
|
let mut path_accu = Vec::new();
|
||||||
|
get_paths(&mut self.0, &mut paths, &mut path_accu, false)?;
|
||||||
|
Ok(paths)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_paths(
|
||||||
|
val: &mut CborValue,
|
||||||
|
paths: &mut Vec<String>,
|
||||||
|
path_accu: &mut Vec<String>,
|
||||||
|
recurse: bool,
|
||||||
|
) -> MizeResult<()> {
|
||||||
|
let map = val
|
||||||
|
.as_map_mut()
|
||||||
|
.ok_or(mize_err!("ItemData is not map... when calling get_paths"))?;
|
||||||
|
for (key, val) in map {
|
||||||
|
let text = key
|
||||||
|
.as_text()
|
||||||
|
.ok_or(mize_err!("ItemData::get_paths but key is not of type text"))?
|
||||||
|
.to_owned();
|
||||||
|
if recurse && val.is_map() {
|
||||||
|
let mut path_accu = path_accu.clone();
|
||||||
|
path_accu.push(text);
|
||||||
|
get_paths(val, paths, &mut path_accu, recurse)?;
|
||||||
|
} else {
|
||||||
|
let path = path_accu.join("/") + "/" + text.as_str();
|
||||||
|
paths.push(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ItemData {
|
impl Default for ItemData {
|
||||||
|
|||||||
10223
packages/ppc/Cargo.lock
generated
Normal file
10223
packages/ppc/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,26 @@ clap = { version = "4.5.59", optional = true }
|
|||||||
js-sys = { version = "0.3.85", optional = true }
|
js-sys = { version = "0.3.85", optional = true }
|
||||||
wasm-bindgen = { version = "0.2.108", optional = true }
|
wasm-bindgen = { version = "0.2.108", optional = true }
|
||||||
|
|
||||||
|
# server deps
|
||||||
|
axum = { version = "0.8.0", optional = true }
|
||||||
|
axum-extra = { version = "0.10.3", features = ["cookie-private"], optional = true }
|
||||||
|
openidconnect = { version = "4", features = ["reqwest", "rustls-tls"], optional = true }
|
||||||
|
serde = { version = "1.0", features = ["derive"], optional = true }
|
||||||
|
serde_json = { version = "1.0", optional = true }
|
||||||
|
reqwest = { version = "0.11", features = ["rustls-tls"], optional = true }
|
||||||
|
rand = { version = "0.8", optional = true }
|
||||||
|
url = { version = "2", optional = true }
|
||||||
|
time = { version = "0.3", optional = true }
|
||||||
|
tokio = { version = "1.0", features = ["full"], optional = true }
|
||||||
|
dioxus = { version = "0.7.1", features = ["router", "fullstack", "web", "desktop", "mobile", "server", "ssr"], optional = true }
|
||||||
|
dioxus-ssr = { version = "0.5", optional = true }
|
||||||
|
html-escape = { version = "0.2.13", optional = true }
|
||||||
|
axum-oidc = { version = "1.0.0-dev-1", optional = true }
|
||||||
|
tracing = { version = "0.1.44", optional = true }
|
||||||
|
tower = { version = "0.5", optional = true }
|
||||||
|
tower-sessions = { version = "0.14.0", optional = true }
|
||||||
|
tower-http = { version = "0.6.8", features = ["trace"] }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "ppc"
|
name = "ppc"
|
||||||
path = "platform/os/main.rs"
|
path = "platform/os/main.rs"
|
||||||
@@ -21,8 +41,10 @@ name = "ppc"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["target-os"]
|
default = ["target-os"]
|
||||||
target-os = [ "clap", "mize/target-os", "marts/target-os" ]
|
target-os = [ "clap", "mize/target-os", "marts/target-os", "server", "tracing" ]
|
||||||
target-obsidian = [ "js-sys", "wasm-bindgen", "mize/target-wasm", "marts/target-wasm" ]
|
target-obsidian = [ "js-sys", "wasm-bindgen", "mize/target-wasm", "marts/target-wasm" ]
|
||||||
|
server = [ "axum", "axum-extra", "openidconnect", "serde", "serde_json", "reqwest", "rand", "url", "time", "tokio", "dioxus", "dioxus-ssr", "html-escape", "axum-oidc", "tower", "tower-sessions" ]
|
||||||
|
|
||||||
|
|
||||||
[package.metadata.wasm-pack.profile.release]
|
[package.metadata.wasm-pack.profile.release]
|
||||||
wasm-opt = false
|
wasm-opt = false
|
||||||
|
|||||||
@@ -1,4 +1,18 @@
|
|||||||
mod platform {
|
mod platform {
|
||||||
#[cfg(feature = "target-obsidian")]
|
#[cfg(feature = "target-obsidian")]
|
||||||
mod obsidian;
|
pub mod obsidian;
|
||||||
|
|
||||||
|
#[cfg(feature = "target-os")]
|
||||||
|
pub mod os {
|
||||||
|
pub mod server;
|
||||||
|
pub mod ui;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "target-os")]
|
||||||
|
mod website;
|
||||||
|
|
||||||
|
#[cfg(feature = "target-os")]
|
||||||
|
pub use platform::os::server::server;
|
||||||
|
#[cfg(feature = "target-os")]
|
||||||
|
pub use platform::os::ui;
|
||||||
|
|||||||
@@ -5,12 +5,14 @@ use clap::crate_version;
|
|||||||
use mize::{Mize, MizeResult};
|
use mize::{Mize, MizeResult};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut mize = Mize::new().expect("failed to create mize instance");
|
let mut mize = Mize::new().expect("failed to create mize");
|
||||||
|
|
||||||
#[cfg(feature = "target-os")]
|
#[cfg(feature = "target-os")]
|
||||||
os_main(&mut mize);
|
let result = os_main(&mut mize);
|
||||||
|
|
||||||
mize.run();
|
if let Err(err) = result {
|
||||||
|
println!("EER: {:?}", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "target-os")]
|
#[cfg(feature = "target-os")]
|
||||||
@@ -19,6 +21,7 @@ fn os_main(mize: &mut Mize) -> MizeResult<()> {
|
|||||||
//marts::js(mize)?;
|
//marts::js(mize)?;
|
||||||
marts::habitica(mize)?;
|
marts::habitica(mize)?;
|
||||||
marts::c2vi(mize)?;
|
marts::c2vi(mize)?;
|
||||||
|
ppc::server(mize)?;
|
||||||
|
|
||||||
let mut cli = mize.get_part_native::<marts::CliPart>("cli")?;
|
let mut cli = mize.get_part_native::<marts::CliPart>("cli")?;
|
||||||
|
|
||||||
@@ -34,5 +37,12 @@ fn os_main(mize: &mut Mize) -> MizeResult<()> {
|
|||||||
println!("test ppc...");
|
println!("test ppc...");
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
|
cli.subcommand(Command::new("gui"), |_, _| {
|
||||||
|
ppc::ui::launch_desktop_app();
|
||||||
Ok(())
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
|
drop(cli);
|
||||||
|
mize.run()
|
||||||
}
|
}
|
||||||
|
|||||||
138
packages/ppc/platform/os/server.rs
Normal file
138
packages/ppc/platform/os/server.rs
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use axum::{
|
||||||
|
Router,
|
||||||
|
error_handling::HandleErrorLayer,
|
||||||
|
http::Uri,
|
||||||
|
response::IntoResponse,
|
||||||
|
routing::{any, get},
|
||||||
|
};
|
||||||
|
use axum_oidc::handle_oidc_redirect;
|
||||||
|
use axum_oidc::{
|
||||||
|
EmptyAdditionalClaims, OidcAuthLayer, OidcClaims, OidcClient, OidcLoginLayer,
|
||||||
|
OidcRpInitiatedLogout, error::MiddlewareError,
|
||||||
|
};
|
||||||
|
use clap::Command;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
use mize::Mize;
|
||||||
|
use mize::MizeResult;
|
||||||
|
use openidconnect::Scope;
|
||||||
|
use openidconnect::{ClientId, ClientSecret, IssuerUrl};
|
||||||
|
use tower::ServiceBuilder;
|
||||||
|
use tower_sessions::{
|
||||||
|
Expiry, MemoryStore, SessionManagerLayer,
|
||||||
|
cookie::{SameSite, time::Duration},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn server(mize: &mut Mize) -> MizeResult<()> {
|
||||||
|
let mut cli = mize.get_part_native::<marts::CliPart>("cli")?;
|
||||||
|
mize.add_name_only_part("ppc.server");
|
||||||
|
|
||||||
|
mize.new_opt("auth.issuer");
|
||||||
|
mize.new_opt("auth.client_id");
|
||||||
|
mize.new_opt("auth.client_secret");
|
||||||
|
mize.new_opt("auth.redirect");
|
||||||
|
mize.new_opt("auth.cookie_key");
|
||||||
|
|
||||||
|
let mut mize = mize.clone();
|
||||||
|
cli.subcommand(Command::new("server"), move |_, _| {
|
||||||
|
// Create tokio runtime for async server
|
||||||
|
let rt = tokio::runtime::Runtime::new()?;
|
||||||
|
rt.block_on(async { start_server(&mut mize).await })?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn start_server(mize: &mut Mize) -> MizeResult<()> {
|
||||||
|
dioxus::logger::initialize_default();
|
||||||
|
|
||||||
|
let issuer = mize.get_config("auth.issuer")?.value_string()?;
|
||||||
|
let client_id = mize.get_config("auth.client_id")?.value_string()?;
|
||||||
|
let client_secret = mize.get_config("auth.client_secret")?.value_string()?;
|
||||||
|
let url = mize.get_config("web.url")?.value_string()?;
|
||||||
|
let redirect_url = format!("{url}/oidc");
|
||||||
|
|
||||||
|
let session_store = MemoryStore::default();
|
||||||
|
let session_layer = SessionManagerLayer::new(session_store)
|
||||||
|
.with_secure(false)
|
||||||
|
.with_same_site(SameSite::Lax)
|
||||||
|
.with_expiry(Expiry::OnInactivity(Duration::seconds(120)));
|
||||||
|
|
||||||
|
let oidc_login_service = ServiceBuilder::new()
|
||||||
|
.layer(HandleErrorLayer::new(|e: MiddlewareError| async {
|
||||||
|
dbg!(&e);
|
||||||
|
e.into_response()
|
||||||
|
}))
|
||||||
|
.layer(OidcLoginLayer::<EmptyAdditionalClaims>::new());
|
||||||
|
|
||||||
|
let oidc_client = OidcClient::<EmptyAdditionalClaims>::builder()
|
||||||
|
.with_default_http_client()
|
||||||
|
.with_redirect_url(Uri::from_str(redirect_url.as_str())?)
|
||||||
|
.with_client_id(ClientId::new(client_id))
|
||||||
|
.add_scope(Scope::new("profile".into()))
|
||||||
|
.add_scope(Scope::new("email".into()))
|
||||||
|
// Optional: add untrusted audiences. If the `aud` claim contains any of these audiences, the token is rejected.
|
||||||
|
//.add_untrusted_audience(Audience::new("123456789".to_string()))
|
||||||
|
.with_client_secret(ClientSecret::new(client_secret))
|
||||||
|
.discover(IssuerUrl::new(issuer.into()).expect("Invalid IssuerUrl"))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let oidc_auth_service = ServiceBuilder::new()
|
||||||
|
.layer(HandleErrorLayer::new(|e: MiddlewareError| async {
|
||||||
|
dbg!(&e);
|
||||||
|
e.into_response()
|
||||||
|
}))
|
||||||
|
.layer(OidcAuthLayer::new(oidc_client));
|
||||||
|
|
||||||
|
let app = Router::new()
|
||||||
|
.route("/foo", get(authenticated))
|
||||||
|
.route("/logout", get(logout))
|
||||||
|
.layer(oidc_login_service)
|
||||||
|
.route("/bar", get(maybe_authenticated))
|
||||||
|
.route("/oidc", any(handle_oidc_redirect::<EmptyAdditionalClaims>))
|
||||||
|
.layer(oidc_auth_service)
|
||||||
|
.layer(session_layer)
|
||||||
|
.layer(tower_http::trace::TraceLayer::new_for_http())
|
||||||
|
// not authenticated routes
|
||||||
|
.route("/", get(ppc_main_page));
|
||||||
|
|
||||||
|
tracing::info!("Running on http://localhost:3000");
|
||||||
|
|
||||||
|
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
||||||
|
axum::serve(listener, app.into_make_service())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn authenticated(claims: OidcClaims<EmptyAdditionalClaims>) -> impl IntoResponse {
|
||||||
|
format!("Hello {}", claims.subject().as_str())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn ppc_main_page() -> impl IntoResponse {
|
||||||
|
"hi"
|
||||||
|
}
|
||||||
|
|
||||||
|
#[axum::debug_handler]
|
||||||
|
async fn maybe_authenticated(
|
||||||
|
claims: Result<OidcClaims<EmptyAdditionalClaims>, axum_oidc::error::ExtractorError>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
if let Ok(claims) = claims {
|
||||||
|
format!(
|
||||||
|
"Hello {}! You are already logged in from another Handler.",
|
||||||
|
claims.subject().as_str()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
"Hello anon!".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn logout(logout: OidcRpInitiatedLogout) -> impl IntoResponse {
|
||||||
|
logout.with_post_logout_redirect(Uri::from_static("https://localhost:3000"))
|
||||||
|
}
|
||||||
17
packages/ppc/platform/os/ui/mod.rs
Normal file
17
packages/ppc/platform/os/ui/mod.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// Minimal cross-platform UI component
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
pub fn hello_world() -> Element {
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
style: "text-align: center; padding: 2rem;",
|
||||||
|
h1 { "Hello from Mize!" }
|
||||||
|
p { "This UI works on Web, Desktop, and Obsidian plugin" }
|
||||||
|
p { "Current platform: {std::env::consts::OS}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn launch_desktop_app() {
|
||||||
|
dioxus::launch(hello_world);
|
||||||
|
}
|
||||||
185
packages/ppc/website/mod.rs
Normal file
185
packages/ppc/website/mod.rs
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
// PPC Website UI Module
|
||||||
|
// This module contains the user interface components for the PPC website
|
||||||
|
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
/// Main PPC website component
|
||||||
|
|
||||||
|
pub fn ppc_website() -> Element {
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
class: "min-h-screen bg-gray-100",
|
||||||
|
|
||||||
|
// Header
|
||||||
|
header {
|
||||||
|
class: "bg-blue-600 text-white py-4",
|
||||||
|
div {
|
||||||
|
class: "container mx-auto px-4",
|
||||||
|
h1 {
|
||||||
|
class: "text-2xl font-bold",
|
||||||
|
"People Corner (PPC)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main content
|
||||||
|
main {
|
||||||
|
class: "container mx-auto px-4 py-8",
|
||||||
|
|
||||||
|
// Hero section
|
||||||
|
section {
|
||||||
|
class: "bg-white rounded-lg shadow-md p-6 mb-8",
|
||||||
|
h2 {
|
||||||
|
class: "text-xl font-semibold mb-4 text-blue-600",
|
||||||
|
"Welcome to People Corner"
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
class: "text-gray-700 mb-4",
|
||||||
|
"PPC is a social platform for intentional people who want to get more out of life together."
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
class: "text-gray-700",
|
||||||
|
"We're building a community-driven social media network that brings people together to do cool things, share resources, and support each other."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mission section
|
||||||
|
section {
|
||||||
|
class: "bg-white rounded-lg shadow-md p-6 mb-8",
|
||||||
|
h2 {
|
||||||
|
class: "text-xl font-semibold mb-4 text-blue-600",
|
||||||
|
"Our Mission"
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
class: "list-disc pl-6 space-y-2",
|
||||||
|
li { "Bring people together to get more out of life" }
|
||||||
|
li { "Create meaningful connections beyond superficial social media" }
|
||||||
|
li { "Support intentional living and personal growth" }
|
||||||
|
li { "Build a platform by people, for people" }
|
||||||
|
li { "Foster real-world meetups and collaborations" }
|
||||||
|
li { "Create a social media for diligent, intentional people" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key concepts section
|
||||||
|
section {
|
||||||
|
class: "bg-white rounded-lg shadow-md p-6",
|
||||||
|
h2 {
|
||||||
|
class: "text-xl font-semibold mb-4 text-blue-600",
|
||||||
|
"Key Concepts"
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
class: "list-disc pl-6 space-y-2",
|
||||||
|
li {
|
||||||
|
strong { "Trust Network: " }
|
||||||
|
"A system for building and maintaining trust between members"
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
strong { "Intentional Communities: " }
|
||||||
|
"Both online and physical spaces for like-minded people"
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
strong { "Resource Sharing: " }
|
||||||
|
"Platform for sharing skills, knowledge, and physical resources"
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
strong { "Real Connections: " }
|
||||||
|
"Focus on meaningful relationships over superficial interactions"
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
strong { "Personal Growth: " }
|
||||||
|
"Support for individuals to achieve their life goals"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Footer
|
||||||
|
footer {
|
||||||
|
class: "bg-blue-600 text-white py-4 mt-8",
|
||||||
|
div {
|
||||||
|
class: "container mx-auto px-4 text-center",
|
||||||
|
p { "© 2024 People Corner. All rights reserved." }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// About page component
|
||||||
|
pub fn about_page() -> Element {
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
class: "container mx-auto px-4 py-8",
|
||||||
|
h1 {
|
||||||
|
class: "text-2xl font-bold mb-4 text-blue-600",
|
||||||
|
"About PPC"
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
class: "text-gray-700 mb-4",
|
||||||
|
"People Corner (PPC) is more than just a social platform - it's a movement to bring intentional people together to create meaningful connections and achieve more in life."
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
class: "text-gray-700",
|
||||||
|
"Our vision is to build a world where people support each other, share resources, and grow together through real-world interactions and digital connections."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contact page component
|
||||||
|
pub fn contact_page() -> Element {
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
class: "container mx-auto px-4 py-8",
|
||||||
|
h1 {
|
||||||
|
class: "text-2xl font-bold mb-4 text-blue-600",
|
||||||
|
"Contact Us"
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
class: "text-gray-700 mb-4",
|
||||||
|
"We'd love to hear from you! Whether you have questions, feedback, or want to get involved, please reach out."
|
||||||
|
}
|
||||||
|
form {
|
||||||
|
class: "max-w-md space-y-4",
|
||||||
|
div {
|
||||||
|
label {
|
||||||
|
class: "block text-gray-700 mb-2",
|
||||||
|
"Name"
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
class: "w-full px-3 py-2 border rounded-lg",
|
||||||
|
r#type: "text",
|
||||||
|
placeholder: "Your name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
label {
|
||||||
|
class: "block text-gray-700 mb-2",
|
||||||
|
"Email"
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
class: "w-full px-3 py-2 border rounded-lg",
|
||||||
|
r#type: "email",
|
||||||
|
placeholder: "Your email"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
label {
|
||||||
|
class: "block text-gray-700 mb-2",
|
||||||
|
"Message"
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
class: "w-full px-3 py-2 border rounded-lg h-32",
|
||||||
|
placeholder: "Your message"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
class: "bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700",
|
||||||
|
r#type: "submit",
|
||||||
|
"Send Message"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user