Skip to content

Commit

Permalink
Major refactoring
Browse files Browse the repository at this point in the history
TODO

- Documentation
- lib.rs samples
  • Loading branch information
tuxuser committed Dec 15, 2023
1 parent a49c793 commit 63cfb65
Show file tree
Hide file tree
Showing 20 changed files with 3,367 additions and 1,181 deletions.
22 changes: 20 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,20 @@
/target
/Cargo.lock
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

# Temporary json files
*.json

# Environment file
env
37 changes: 15 additions & 22 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,28 @@ homepage = "https://openxbox.org"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
async-trait = "0.1.74"
reqwest = { version = "0.11", features = ["json"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
cvlib = "0.1.2"
filetime_type = "0.1"
base64 = "0.13.0"
chrono = "0.4"
josekit = "0.8"
uuid = { version = "1", features = ["v4"] }
oauth2 = "4.3"

# common for bins
tokio = { version = "1", features = ["full"], optional = true }

# auth_webview
tauri = { version = "1.1.1", optional = true }
wry = { version = "0.21.1", optional = true }
uuid = { version = "1", features = ["v4", "serde"] }
thiserror = "1.0.37"
url = "2.3.1"
http = "0.2.9"
log = "0.4.20"
p256 = "0.13.2"
base64ct = { version = "1.6.0", features = ["std"] }
sha2 = "0.10.8"
rand = "0.8.5"
oauth2 = "4.4.2"

[dev-dependencies]
hex-literal = "0.3.4"

[features]
webview = ["dep:tauri", "dep:wry"]
tokio = ["dep:tokio"]

[[bin]]
name = "auth-cli"
required-features = ["tokio"]

[[bin]]
name = "auth-webview"
required-features = ["webview"]
[workspace]
members = [
"examples"
]
36 changes: 36 additions & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[package]
name = "xal_examples"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
xal = { path = ".." }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
async-trait = "0.1.74"
env_logger = "0.10.1"
log = "0.4.20"
clap = { version = "4.4.8", features = ["derive"] }
chrono = "0.4.31"

# Optional dependencies
tokio = { version = "1", features = ["full"], optional = true }
wry = { version = "0.34.2", optional = true }

[features]
webview = ["dep:wry"]
tokio = ["dep:tokio"]

[[bin]]
name = "auth_cli"
required-features = ["tokio"]

[[bin]]
name = "auth_azure"
required-features = ["tokio"]

[[bin]]
name = "auth_webview"
required-features = ["webview","tokio"]
72 changes: 72 additions & 0 deletions examples/src/bin/auth_azure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use std::str::from_utf8;

use async_trait::async_trait;
use tokio::{net::TcpListener, io::{AsyncReadExt, AsyncWriteExt}};
use xal::{
flows::{AuthPromptCallback, AuthPromptData},
url::Url,
Error, client_params::CLIENT_ANDROID, Constants, XalAppParameters, oauth2::{Scope, RedirectUrl, ResourceOwnerUsername, ResourceOwnerPassword}, XalAuthenticator,
};
use xal_examples::auth_main;

pub struct HttpCallbackHandler {
bind_host: String,
redirect_url_base: String,
}

#[async_trait]
impl AuthPromptCallback for HttpCallbackHandler {
async fn call(
&self,
cb_data: AuthPromptData,
) -> Result<Option<Url>, Box<dyn std::error::Error>> {
let prompt = cb_data.prompt();
println!("{prompt}\n");

let listener = TcpListener::bind(&self.bind_host).await?;
println!("HTTP Server listening, waiting for connection...");

let (mut socket, addr) = listener.accept().await?;
println!("Connection received from {addr:?}");

let mut buf = [0u8; 1024];

if socket.read(&mut buf).await? == 0 {
return Err("Failed reading http request".into());
}

socket.write_all(b"HTTP/1.1 200 OK\n\r\n\r").await?;

let http_req = from_utf8(&buf)?;
println!("HTTP REQ: {http_req}");

let path = http_req.split(" ").nth(1).unwrap();
println!("Path: {path}");

Ok(Some(Url::parse(&format!("{}{}", self.redirect_url_base, path))?))
}
}

#[tokio::main]
async fn main() -> Result<(), Error> {
auth_main(
XalAppParameters {
app_id: "388ea51c-0b25-4029-aae2-17df49d23905".into(),
title_id: None,
auth_scopes: vec![
Scope::new("Xboxlive.signin".into()), Scope::new("Xboxlive.offline_access".into())
],
redirect_uri: Some(
RedirectUrl::new("http://localhost:8080/auth/callback".into()).unwrap(),
),
},
CLIENT_ANDROID(),
"RETAIL".into(),
Constants::RELYING_PARTY_XBOXLIVE.into(),
xal::AccessTokenPrefix::D,
HttpCallbackHandler {
bind_host: "127.0.0.1:8080".into(),
redirect_url_base: "http://localhost:8080".into(),
}
).await
}
10 changes: 10 additions & 0 deletions examples/src/bin/auth_cli.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use xal::{flows, AccessTokenPrefix, Error};
use xal_examples::auth_main_default;

#[tokio::main]
async fn main() -> Result<(), Error> {
auth_main_default(
AccessTokenPrefix::None,
flows::CliCallbackHandler
).await
}
115 changes: 115 additions & 0 deletions examples/src/bin/auth_webview.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Copyright 2020-2022 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use async_trait::async_trait;
use tokio::sync::mpsc::channel;
use wry::{
application::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoopBuilder},
platform::run_return::EventLoopExtRunReturn,
window::WindowBuilder,
},
webview::WebViewBuilder,
};
use xal::{
flows::{AuthPromptCallback, AuthPromptData},
url::Url,
Error, XalAuthenticator, AccessTokenPrefix,
};
use xal_examples::auth_main_default;

#[derive(Debug)]
enum UserEvent {
Exit,
}

struct WebviewCallbackHandler {
redirect_url_schema: String,
}

#[async_trait]
impl AuthPromptCallback for WebviewCallbackHandler {
async fn call(
&self,
cb_data: AuthPromptData,
) -> Result<Option<Url>, Box<dyn std::error::Error>> {
let authentication_url = cb_data.authentication_url();
let does_expect_url = cb_data.expect_url();

let redirect_url_schema = self.redirect_url_schema.clone();

let mut event_loop = EventLoopBuilder::with_user_event().build();
let event_proxy = event_loop.create_proxy();
let window = WindowBuilder::new()
.with_title("XAL Webview")
.build(&event_loop)
.unwrap();

let (sender, mut receiver) = channel::<Url>(1);

let _webview = WebViewBuilder::new(window)?
// tell the webview to load the custom protocol
.with_navigation_handler(move |url| {
if does_expect_url {
// Callback wants a redirect URL (with either authorization code or implicit tokens)
let parsed_url = Url::parse(&url).expect("Failed to parse navigation URL");
if parsed_url.scheme() == redirect_url_schema {
sender
.try_send(parsed_url)
.expect("Failed to send redirect URL over channel");

event_proxy.send_event(UserEvent::Exit).unwrap();
return false;
}
}

true
})
.with_url(authentication_url.as_str())?
.build()?;

let _ = event_loop.run_return(|event, _, control_flow| {
*control_flow = ControlFlow::Wait;

match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
}
| Event::UserEvent(_) => {
*control_flow = ControlFlow::Exit;
}
_ => {}
}
});

let retval = {
if does_expect_url {
Some(receiver.try_recv()?)
} else {
None
}
};

Ok(retval)
}
}

#[tokio::main]
async fn main() -> Result<(), Error> {
let authenticator = XalAuthenticator::default();

let callback_handler = WebviewCallbackHandler {
redirect_url_schema: authenticator
.get_redirect_uri()
.ok_or(Error::GeneralError(
"Failure! Authenticator not configured with redirect URL".to_string(),
))?
.scheme()
.to_owned(),
};

auth_main_default(AccessTokenPrefix::None, callback_handler).await
}
Loading

0 comments on commit 63cfb65

Please sign in to comment.