mirror of
https://github.com/aljazceru/pubky-core.git
synced 2025-12-31 12:54:35 +01:00
examples(authz): initial authenticator using keyring crate
This commit is contained in:
@@ -9,7 +9,11 @@
|
||||
<script type="module" src="/src/pubky-auth-widget.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pubky-auth-widget relay="https://demo.httprelay.io/link/"></pubky-auth-widget>
|
||||
<pubky-auth-widget
|
||||
relay="https://demo.httprelay.io/link/"
|
||||
caps="/pub/pubky.app/:rw"
|
||||
>
|
||||
</pubky-auth-widget>
|
||||
|
||||
<main>
|
||||
<h1>Third Party app!</h1>
|
||||
|
||||
@@ -19,6 +19,10 @@ export class PubkyAuthWidget extends LitElement {
|
||||
* https://demo.httprelay.io/link
|
||||
*/
|
||||
relay: { type: String },
|
||||
/**
|
||||
* Capabilities requested or this application encoded as a string.
|
||||
*/
|
||||
caps: { type: String },
|
||||
/**
|
||||
* Widget's state (open or closed)
|
||||
*/
|
||||
@@ -50,10 +54,10 @@ export class PubkyAuthWidget extends LitElement {
|
||||
const channel = Math.random().toString(32).slice(2);
|
||||
callbackUrl.pathname = callbackUrl.pathname + "/" + channel
|
||||
|
||||
this.authUrl = `pubky:auth?cb=${callbackUrl.toString()}`;
|
||||
this.authUrl = `pubkyauth:///?cb=${callbackUrl.toString()}&caps=${this.caps}`;
|
||||
|
||||
fetch(callbackUrl)
|
||||
.catch(console.log)
|
||||
.catch(error => console.error("PubkyAuthWidget: Failed to subscribe to http relay channel", error))
|
||||
.then(this._onCallback)
|
||||
}
|
||||
|
||||
@@ -63,17 +67,22 @@ export class PubkyAuthWidget extends LitElement {
|
||||
id="widget"
|
||||
class=${this.open ? "open" : ""}
|
||||
>
|
||||
<button class="header" @click=${this._switchOpen}>Pubky Auth</button>
|
||||
<button class="header" @click=${this._switchOpen}>
|
||||
<svg id="pubky-icon" version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1511 1511"><path fill-rule="evenodd" d="m636.3 1066.7 14.9-59.7c50.5-27.7 90.8-71.7 113.7-124.9-47.3 51.3-115.2 83.4-190.6 83.4-51.9 0-100.1-15.1-140.5-41.2L394 1066.7H193.9L356.4 447H567l-.1.1q3.7-.1 7.4-.1c77.7 0 147.3 34 194.8 88l22-88h202.1l-47 180.9L1130 447h249l-323 332.8 224 286.9H989L872.4 912l-40.3 154.7H636.3z" style="fill:#fff"/></svg>
|
||||
<span class="text">
|
||||
Pubky Auth
|
||||
</span>
|
||||
</button>
|
||||
<div class="line"></div>
|
||||
<div id="widget-content">
|
||||
<p>Scan or copy Pubky auth URL</p>
|
||||
<div class="card">
|
||||
<canvas id="qr" ${ref(this._setQr)}></canvas>
|
||||
</div>
|
||||
<button class="card url" href=${this.authUrl}>
|
||||
<a class="card url" href=${this.authUrl}>
|
||||
<p>${this.authUrl}</p>
|
||||
<svg width="14" height="16" viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="10" height="12" rx="2" fill="white"></rect><rect x="3" y="3" width="10" height="12" rx="2" fill="white" stroke="#3B3B3B"></rect></svg>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
@@ -110,7 +119,7 @@ export class PubkyAuthWidget extends LitElement {
|
||||
|
||||
console.log({ uint8Array })
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch and convert the API response:', error);
|
||||
console.error('PubkyAuthWidget: Failed to read incoming AuthToken', error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +133,11 @@ export class PubkyAuthWidget extends LitElement {
|
||||
--full-width: 22rem;
|
||||
--full-height: 31rem;
|
||||
--header-height: 3rem;
|
||||
--closed-width: 3rem;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
button {
|
||||
@@ -157,7 +171,7 @@ export class PubkyAuthWidget extends LitElement {
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
backdrop-filter: blur(8px);
|
||||
|
||||
width: 7rem;
|
||||
width: var(--closed-width);
|
||||
height: var(--header-height);
|
||||
|
||||
will-change: height,width;
|
||||
@@ -172,13 +186,39 @@ export class PubkyAuthWidget extends LitElement {
|
||||
}
|
||||
|
||||
.header {
|
||||
width: 100%;
|
||||
height: var(--header-height);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#widget
|
||||
.header .text {
|
||||
display: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
#widget.open
|
||||
.header .text {
|
||||
display: block
|
||||
}
|
||||
|
||||
#widget.open
|
||||
.header {
|
||||
width: var(--full-width);
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#pubky-icon {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#widget.open
|
||||
#pubky-icon {
|
||||
width: var(--header-height);
|
||||
height: 74%;
|
||||
}
|
||||
|
||||
#widget-content{
|
||||
width: var(--full-width);
|
||||
padding: 0 1rem
|
||||
|
||||
29
examples/authz/README.md
Normal file
29
examples/authz/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Pubky Auth Example
|
||||
|
||||
This example shows 3rd party authorization in Pubky.
|
||||
|
||||
It consists of 2 parts:
|
||||
|
||||
1. [3rd party app](./3rd-party-app): A web component showing the how to implement a Pubky Auth widget.
|
||||
2. [Authenticator CLI](./authenticator): A CLI showing the authenticator (key chain) asking user for consent and generating the AuthToken.
|
||||
|
||||
## Usage
|
||||
|
||||
First you need to be running a local testnet Homeserver, in the root of this repo run
|
||||
|
||||
```bash
|
||||
cargo run --bin pubky_homeserver -- --testnet
|
||||
```
|
||||
|
||||
Run the frontend of the 3rd party app
|
||||
|
||||
```bash
|
||||
cd ./3rd-party-app
|
||||
npm start
|
||||
```
|
||||
|
||||
Copy the Pubky Auth URL from the frontend.
|
||||
|
||||
Finally run the CLI to paste the Pubky Auth in.
|
||||
|
||||
You should see the frontend reacting by showing the success of authorization and session details.
|
||||
1906
examples/authz/authenticator/Cargo.lock
generated
Normal file
1906
examples/authz/authenticator/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
13
examples/authz/authenticator/Cargo.toml
Normal file
13
examples/authz/authenticator/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "authenticator"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.86"
|
||||
keyring = { version = "3.2.0", features = ["linux-native", "apple-native", "windows-native"] }
|
||||
pubky = { version = "0.1.0", path = "../../../pubky" }
|
||||
pubky-common = { version = "0.1.0", path = "../../../pubky-common" }
|
||||
rpassword = "7.3.1"
|
||||
|
||||
[workspace]
|
||||
91
examples/authz/authenticator/src/main.rs
Normal file
91
examples/authz/authenticator/src/main.rs
Normal file
@@ -0,0 +1,91 @@
|
||||
use std::io;
|
||||
|
||||
use keyring::Entry;
|
||||
use pubky_common::crypto::Keypair;
|
||||
|
||||
const SERVICE_NAME: &str = "pubky";
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
println!("Enter the alias for your keypair in your operating system secure storage:");
|
||||
let mut name = String::new();
|
||||
io::stdin().read_line(&mut name)?;
|
||||
name = name.trim_end().to_lowercase();
|
||||
|
||||
let entry = Entry::new(SERVICE_NAME, &name)?;
|
||||
|
||||
let keypair = match entry.get_secret() {
|
||||
Ok(secret_key) => {
|
||||
let secret_key: &[u8; 32] = secret_key
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.expect("Invalid secret_key");
|
||||
let keypair = Keypair::from_secret_key(&secret_key);
|
||||
|
||||
println!("\nFound secret_key for Pubky {}", keypair.public_key());
|
||||
|
||||
keypair
|
||||
}
|
||||
Err(error) => {
|
||||
let keypair = Keypair::random();
|
||||
|
||||
println!(
|
||||
"\n{}\nGenerated new Pubky {}",
|
||||
error.to_string(),
|
||||
keypair.public_key()
|
||||
);
|
||||
|
||||
loop {
|
||||
println!("\nStore the new Pubky keypair in operating system secure storage?[y/n]");
|
||||
let mut choice = String::new();
|
||||
io::stdin().read_line(&mut choice)?;
|
||||
|
||||
match choice.as_str() {
|
||||
"y\n" => {
|
||||
entry.set_secret(&keypair.secret_key())?;
|
||||
|
||||
break;
|
||||
}
|
||||
"n\n" => {
|
||||
return Ok(());
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
keypair
|
||||
}
|
||||
};
|
||||
dbg!(keypair);
|
||||
|
||||
// entry.set_password("topS3cr3tP4$$w0rd")?;
|
||||
// let password = entry.get_password()?;
|
||||
// println!("My password is '{}'", password);
|
||||
// entry.delete_credential()?;
|
||||
// Ok(())
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// fn read_file_content<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
|
||||
// let mut file = File::open(path)?;
|
||||
// let mut content = Vec::new();
|
||||
// file.read_to_end(&mut content)?;
|
||||
// Ok(content)
|
||||
// }
|
||||
|
||||
// fn decrypt_content(content: &[u8], password: &str) -> Result<String, &'static str> {
|
||||
// // Create a key and IV (Initialization Vector) from the password
|
||||
// let key = GenericArray::from_slice(password.as_bytes()); // Example key derivation
|
||||
// let iv = GenericArray::from_slice(b"unique_iv_16bytes"); // Replace with proper IV derivation
|
||||
//
|
||||
// let cipher = Aes256::new(key, iv);
|
||||
//
|
||||
// // Decrypt the content using the cipher
|
||||
// let mut buffer = content.to_vec();
|
||||
// cipher
|
||||
// .decrypt_padded_mut::<Pkcs7>(&mut buffer)
|
||||
// .map_err(|_| "Decryption failed")?;
|
||||
//
|
||||
// // Convert decrypted bytes to string
|
||||
// String::from_utf8(buffer).map_err(|_| "Failed to convert decrypted content to string")
|
||||
// }
|
||||
Reference in New Issue
Block a user