Skip to content

Commit

Permalink
feat(js): return Session class from auth methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Nuhvi committed Sep 7, 2024
1 parent 3237708 commit db00661
Show file tree
Hide file tree
Showing 12 changed files with 182 additions and 103 deletions.
29 changes: 15 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 9 additions & 25 deletions examples/authz/3rd-party-app/src/pubky-auth-widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,19 @@ export class PubkyAuthWidget extends LitElement {

let [url, promise] = this.pubkyClient.authRequest(this.relay || DEFAULT_HTTP_RELAY, this.caps);

promise.then(x => {
console.log({ x })
promise.then(session => {
console.log({ id: session.pubky().z32(), capabilities: session.capabilities() })
alert(`Successfully signed in to ${session.pubky().z32()} with capabilities: ${session.capabilities().join(",")}`)
}).catch(e => {
console.error(e)
})

// let keypair = pubky.Keypair.random();
// const Homeserver = pubky.PublicKey.from('8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo')
// this.pubkyClient.signup(keypair, Homeserver).then(() => {
// this.pubkyClient.sendAuthToken(keypair, url)
// })

this.authUrl = url
}

Expand Down Expand Up @@ -108,29 +115,6 @@ export class PubkyAuthWidget extends LitElement {
this.open = !this.open
}

async _onCallback(response) {
try {
// Check if the response is ok (status code 200-299)
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

// Convert the response to an ArrayBuffer
const arrayBuffer = await response.arrayBuffer();

// Create a Uint8Array from the ArrayBuffer
const authToken = new Uint8Array(arrayBuffer);

let publicKey = await this.pubkyClient.thirdPartySignin(authToken, this.secret)

let session = await this.pubkyClient.session(publicKey);

alert(`Succssfully signed in as ${publicKey.z32()}`)
} catch (error) {
console.error('PubkyAuthWidget: Failed to read incoming AuthToken', error);
}
}

async _copyToClipboard() {
try {
await navigator.clipboard.writeText(this.authUrl);
Expand Down
22 changes: 16 additions & 6 deletions pubky-common/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ use crate::{auth::AuthToken, capabilities::Capability, timestamp::Timestamp};
// and get more informations from the user-agent.
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
pub struct Session {
pub version: usize,
pub pubky: PublicKey,
pub created_at: u64,
version: usize,
pubky: PublicKey,
created_at: u64,
/// User specified name, defaults to the user-agent.
pub name: String,
pub user_agent: String,
pub capabilities: Vec<Capability>,
name: String,
user_agent: String,
capabilities: Vec<Capability>,
}

impl Session {
Expand All @@ -33,6 +33,16 @@ impl Session {
}
}

// === Getters ===

pub fn pubky(&self) -> &PublicKey {
&self.pubky
}

pub fn capabilities(&self) -> &Vec<Capability> {
&self.capabilities
}

// === Setters ===

pub fn set_user_agent(&mut self, user_agent: String) -> &mut Self {
Expand Down
4 changes: 2 additions & 2 deletions pubky-homeserver/src/routes/public.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ fn authorize(
.get_session(cookies, public_key)?
.ok_or(Error::with_status(StatusCode::UNAUTHORIZED))?;

if session.pubky == *public_key
&& session.capabilities.iter().any(|cap| {
if session.pubky() == public_key
&& session.capabilities().iter().any(|cap| {
path.starts_with(&cap.scope[1..])
&& cap
.abilities
Expand Down
34 changes: 28 additions & 6 deletions pubky/pkg/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ let session = await client.signin(keypair)
- keypair: An instance of [Keypair](#keypair).

Returns:
- session: An instance of [Session](#session).
- An instance of [Session](#session).

#### signout
```js
Expand All @@ -102,8 +102,7 @@ let session = await sessionPromise;
```

Sign in to a user's Homeserver, without access to their [Keypair](#keypair), nor even [PublicKey](#publickey),
instead request permissions (showing the user pubkyauthUrl), and await a Session
after the user consenting to that request.
instead request permissions (showing the user pubkyauthUrl), and await a Session after the user consenting to that request.

- relay: A URL to an [HTTP relay](https://httprelay.io/features/link/) endpoint.
- capabilities: A list of capabilities required for the app for example `/pub/pubky.app/:rw,/pub/example.com/:r`.
Expand All @@ -112,12 +111,21 @@ Returns:
- pubkyauthUrl: A url to show to the user to scan or paste into an Authenticator app holding the user [Keypair](#keypair)
- sessionPromise: A promise that resolves into a [Session](#session) on success.

#### session
#### sendAuthToken
```js
await client.sendAuthToken(keypair, pubkyauthUrl);
```
Consenting to authentication or authorization according to the required capabilities in the `pubkyauthUrl` , and sign and send an auth token to the requester.

- keypair: An instance of [KeyPair](#keypair)
- pubkyauthUrl: A string `pubkyauth://` url

#### session {#session-method}
```js
let session = await client.session(publicKey)
```
- publicKey: An instance of [PublicKey](#publickey).
- Returns: A session object if signed in, or undefined if not.
- Returns: A [Session](#session) object if signed in, or undefined if not.

#### put
```js
Expand Down Expand Up @@ -166,7 +174,7 @@ let keypair = Keypair.fromSecretKey(secretKey)
- Returns: A new Keypair.


#### publicKey
#### publicKey {#publickey-method}
```js
let publicKey = keypair.publicKey()
```
Expand Down Expand Up @@ -194,6 +202,20 @@ let pubky = publicKey.z32();
```
Returns: The z-base-32 encoded string representation of the PublicKey.

### Session

#### pubky
```js
let pubky = session.pubky();
```
Returns an instance of [PublicKey](#publickey)

#### capabilities
```js
let capabilities = session.capabilities();
```
Returns an array of capabilities, for example `["/pub/pubky.app/:rw"]`

### Helper functions

#### createRecoveryFile
Expand Down
39 changes: 34 additions & 5 deletions pubky/pkg/test/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import test from 'tape'

import { PubkyClient, Keypair, PublicKey } from '../index.cjs'

const Homeserver = PublicKey.from('8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo')

test('auth', async (t) => {
const client = PubkyClient.testnet();

const keypair = Keypair.random()
const publicKey = keypair.publicKey()

const homeserver = PublicKey.from('8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo')
await client.signup(keypair, homeserver)
await client.signup(keypair, Homeserver)

const session = await client.session(publicKey)
t.ok(session, "signup")
Expand All @@ -29,6 +30,34 @@ test('auth', async (t) => {
}
})

// TODO: test end to end
// TODO: test invalid inputs
test.skip("3rd party signin")
test("3rd party signin", async (t) => {
let keypair = Keypair.random();
let pubky = keypair.publicKey().z32();

// Third party app side
let capabilities = "/pub/pubky.app/:rw,/pub/foo.bar/file:r";
let client = PubkyClient.testnet();
let [pubkyauth_url, pubkyauthResponse] = client
.authRequest("https://demo.httprelay.io/link", capabilities);

if (globalThis.document) {
// Skip `sendAuthToken` in browser
// TODO: figure out why does it fail in browser unit tests
// but not in real browser (check pubky-auth-widget.js commented part)
return
}

// Authenticator side
{
let client = PubkyClient.testnet();

await client.signup(keypair, Homeserver);

await client.sendAuthToken(keypair, pubkyauth_url)
}

let session = await pubkyauthResponse;

t.is(session.pubky().z32(), pubky)
t.deepEqual(session.capabilities(), capabilities.split(','))
})
22 changes: 8 additions & 14 deletions pubky/pkg/test/public.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import test from 'tape'

import { PubkyClient, Keypair, PublicKey } from '../index.cjs'

const Homeserver = PublicKey.from('8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo');

test('public: put/get', async (t) => {
const client = PubkyClient.testnet();

const keypair = Keypair.random();

const homeserver = PublicKey.from('8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo');
await client.signup(keypair, homeserver);
await client.signup(keypair, Homeserver);

const publicKey = keypair.publicKey();

Expand Down Expand Up @@ -46,8 +47,7 @@ test("not found", async (t) => {

const keypair = Keypair.random();

const homeserver = PublicKey.from('8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo');
await client.signup(keypair, homeserver);
await client.signup(keypair, Homeserver);

const publicKey = keypair.publicKey();

Expand All @@ -64,8 +64,7 @@ test("unauthorized", async (t) => {
const keypair = Keypair.random()
const publicKey = keypair.publicKey()

const homeserver = PublicKey.from('8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo')
await client.signup(keypair, homeserver)
await client.signup(keypair, Homeserver)

const session = await client.session(publicKey)
t.ok(session, "signup")
Expand All @@ -92,8 +91,7 @@ test("forbidden", async (t) => {
const keypair = Keypair.random()
const publicKey = keypair.publicKey()

const homeserver = PublicKey.from('8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo')
await client.signup(keypair, homeserver)
await client.signup(keypair, Homeserver)

const session = await client.session(publicKey)
t.ok(session, "signup")
Expand All @@ -119,8 +117,7 @@ test("list", async (t) => {
const publicKey = keypair.publicKey()
const pubky = publicKey.z32()

const homeserver = PublicKey.from('8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo')
await client.signup(keypair, homeserver)
await client.signup(keypair, Homeserver)



Expand Down Expand Up @@ -251,10 +248,7 @@ test('list shallow', async (t) => {
const publicKey = keypair.publicKey()
const pubky = publicKey.z32()

const homeserver = PublicKey.from('8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo')
await client.signup(keypair, homeserver)


await client.signup(keypair, Homeserver)

let urls = [
`pubky://${pubky}/pub/a.com/a.txt`,
Expand Down
2 changes: 1 addition & 1 deletion pubky/src/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ impl PubkyClient {
///
/// The homeserver is a Pkarr domain name, where the TLD is a Pkarr public key
/// for example "pubky.o4dksfbqk85ogzdb5osziw6befigbuxmuxkuxq8434q89uj56uyy"
pub async fn signup(&self, keypair: &Keypair, homeserver: &PublicKey) -> Result<()> {
pub async fn signup(&self, keypair: &Keypair, homeserver: &PublicKey) -> Result<Session> {
self.inner_signup(keypair, homeserver).await
}

Expand Down
Loading

0 comments on commit db00661

Please sign in to comment.