Skip to content

Commit 536c537

Browse files
committed
merge: galactic supermassive rewrites
2 parents ca35f74 + 360fbd5 commit 536c537

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+532
-625
lines changed

changelog.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,20 @@
77

88
<br/>
99

10-
--------
10+
## v0.2
11+
12+
### v0.2.0
13+
- 🧐 authduo doesn't have any users yet so i'm still in a mode of breaking things with impunity
14+
- 🟥 tokens reworked, we now have `Keys`, `Proof`, and `Claim` tokens
15+
- 🟥 auth.login has a new Login type with a somewhat different signature
16+
- 🟥 breaking changes to the fed api (api between the popup and your app)
17+
- all calls are now namespaced under v1
18+
- this will make it easier to avoid breaking changes in the future
19+
- i also changed the names of the LoginTokens that get returned
20+
- 🟥 moved the passport's `name` from Keys to Proof
21+
- 🔶 tweaked authfile format, but its versioned and so should not cause breakage
22+
- 🍏 renamed `JsonWebToken` facility to simply `Token`
23+
- 🍏 on the passport edit page, i added a text input for copying the thumbprint
1124

1225
## v0.1
1326

package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,6 @@
88
"x",
99
"s"
1010
],
11-
"exports": {
12-
".": {
13-
"node": "./x/server.js",
14-
"deno": "./x/server.js",
15-
"browser": "./x/index.js",
16-
"default": "./x/index.js"
17-
}
18-
},
1911
"scripts": {
2012
"build": "rm -rf x && run-s build-code build-ssg links",
2113
"build-code": "turtle build --out=x",
@@ -26,11 +18,12 @@
2618
"links": "run-s links-s links-assets",
2719
"links-s": "ln -s \"$(realpath s)\" x/s",
2820
"links-assets": "ln -s \"$(realpath assets)\" x/assets",
21+
"devlinks-slate": "rm -rf node_modules/@benev/slate && ln -s \"$(realpath ../../@benev/slate)\" node_modules/@benev/slate",
2922
"test": "cynic node x/tests.test.js"
3023
},
3124
"dependencies": {
32-
"@benev/slate": "^0.2.8",
33-
"renraku": "^0.3.0-0"
25+
"@benev/slate": "^0.2.17",
26+
"renraku": "^0.4.2"
3427
},
3528
"devDependencies": {
3629
"@benev/turtle": "^0.6.3",

readme.md

Lines changed: 43 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ Try out the login button at the [Federated Test Page](https://authduo.org/federa
4545
- Customize that second script to handle logins/logouts your way.
4646
- When the user logs in, the `login` object looks like this:
4747
```js
48-
login.name // Kaylim Bojrumaj
49-
login.thumbprint // "4e77bccf..."
50-
login.expiry // 1729381451374
48+
login.name // Cetdok Pizafoaba
49+
login.thumbprint // "0d196fc3..."
50+
login.expiry // 1731740481065
5151
```
5252
- When the user logs out, `login` is `null`.
5353
1. **Put this button in your `<body>`:**
@@ -67,10 +67,12 @@ Try out the login button at the [Federated Test Page](https://authduo.org/federa
6767
```
6868
1. **Register components and listen for auth changes.** `main.ts`
6969
```ts
70-
import {auth, components, register_to_dom} from "@authduo/authduo"
70+
import {Auth, components, register_to_dom} from "@authduo/authduo"
7171

7272
register_to_dom(components)
7373

74+
const auth = Auth.get()
75+
7476
auth.onChange(login => {
7577
if (login) console.log("logged in", login)
7678
else console.log("logged out")
@@ -124,62 +126,66 @@ Try out the login button at the [Federated Test Page](https://authduo.org/federa
124126

125127
### Understanding the Authduo flow and tokens
126128

127-
![](https://i.imgur.com/eLa130k.png)
129+
![](https://i.imgur.com/18xwaeU.png)
130+
131+
- When a user on your app clicks to login, this opens an Authduo.org popup for them to login.
132+
- The authduo signs some tokens with your user's passport keypair, and sends them back to your application.
133+
- Your app receives a `Login` object, which has some useful things:
134+
- `login.proof.token` -- this is a `Proof` token and it's public, so you can send it around anywhere so your user can prove their identity
135+
- `login.keys.signClaimToken(~)` -- you can use this to sign arbitrary data into a token, which is verifiably signed on behalf of the user's passport
128136

129-
- When your user logs in, you receive a *Login* object (a verified *login token*).
130-
- Don't pass this around, anybody with the login token can impersonate your user.
131-
- Instead of passing the login token around, you can use the login object to *sign* your own *challenge tokens*.
132-
- Let's consider an example: you're making a player-hosted multiplayer game.
133-
- Your user logs in, and you get a *Login* object.
134-
- You want to send your user's identity to the host of the game, so they can verify it, and nobody can impersonate your user.
135-
- So you use your *Login* object to sign a fresh *challenge token* containing your user's name and other info.
136-
- You send this *challenge token* along with your *login.proof.token* to the game host.
137-
- The game host receives your `challengeToken` and `proofToken`, and now can verify that your challenge was authentically signed on behalf of the user's passport.
137+
#### Example of signing and verifying claim tokens
138138

139-
### `Login`, `Proof`, and `Challenge` tokens
140-
- **Sign a fresh challenge token.**
139+
- **Sign a fresh claim token.**
141140
```js
142-
import {FromNow} from "@authduo/authduo"
141+
import {Future} from "@authduo/authduo"
143142

144-
const challengeToken = await login.signChallengeToken({
145-
expiry: FromNow.hours(24),
143+
const idToken = await login.keys.signClaimToken({
144+
expiresAt: Future.hours(24),
146145

147146
// you can pack any abitrary data you want into this token
148147
data: {
149148
username: "Rec Doamge",
149+
avatarId: "d15aea1a",
150150

151-
// we've scoped this token to this game session,
152-
// so that it cannot be stolen and reused in other game sessions.
151+
// perhaps we want to scope this claim to a specific game session,
152+
// so that it cannot be stolen by other users and reused in other
153+
// game sessions.
153154
gameSessionId: "9c22b17e",
154155
},
155156
})
156157
```
157-
- **Send the *challengeToken* along with a *proofToken.***
158+
- **Send this *idToken* along with the user's *proofToken.***
158159
```js
159-
await sendElsewhere({
160-
proofToken: login.proof.token,
161-
challengeToken,
162-
})
160+
await sendElsewhere(login.proof.token, idToken)
163161
```
164-
- Each `login` object comes with a `proofToken` that is required to verify a challenge token.
165-
- **Verify the proof and challenge**
162+
- Each `login` object comes with a proof token that is required to verify any claim tokens.
163+
- **Verify the proof and claim**
166164
```js
167-
import {Proof, Challenge} from "@authduo/authduo"
165+
import {Proof, Claim} from "@authduo/authduo"
166+
167+
receiveElsewhere(async(proofToken, idToken) => {
168+
169+
// the origin of your site that triggered the authduo popup
170+
const allowedAudiences = ["https://example.benev.gg"]
171+
172+
// verifying the proof
173+
const proof = await Proof.verify(proofToken, {allowedAudiences})
168174

169-
receiveElsewhere(async(proofToken, challengeToken) => {
170-
const proof = await Proof.verify(proofToken)
171-
const challenge = await Challenge.verify(proof, challengeToken)
175+
// proving the claim
176+
const claim = await Claim.verify(proof, idToken)
172177

173-
// here's that data you packed into the challenge
174-
console.log(challenge.data.username) // "Rec Doamge"
175-
console.log(challenge.data.gameSessionId) // "9c22b17e"
178+
// here's that data you packed into the claim
179+
console.log(claim.data.username) // "Rec Doamge"
180+
console.log(claim.data.avatarId) // "d15aea1a"
181+
console.log(claim.data.gameSessionId) // "9c22b17e"
176182

177183
// user passport public thumbprint, the true user identifier
178-
console.log(challenge.thumbprint) // "a32e638e..."
184+
console.log(claim.thumbprint) // "a32e638e..."
179185
console.log(proof.thumbprint) // "a32e638e..."
180186
})
181187
```
182-
- The same proof can be used to verify multiple challenges from the same login.
188+
- The same proof can be used to verify multiple claims from the same login.
183189

184190
<br/>
185191

s/auth/keypair.ts

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11

2+
import {Hex} from "@benev/slate"
3+
24
import {Pubkey} from "./pubkey.js"
3-
import {hex} from "../tools/hex.js"
4-
import {KeypairJson} from "./types.js"
5-
import {getCrypto} from "./utils/get-crypto.js"
5+
import {KeypairData} from "./types.js"
6+
import {Token, Payload} from "./tokens/token.js"
67
import {CryptoConstants} from "./crypto-constants.js"
7-
import {JsonWebToken, Payload} from "./utils/json-web-token.js"
88

99
export class Keypair extends Pubkey {
1010
constructor(
@@ -16,27 +16,25 @@ export class Keypair extends Pubkey {
1616
}
1717

1818
static async generate() {
19-
const crypto = await getCrypto()
20-
2119
const keys = await crypto.subtle
2220
.generateKey(CryptoConstants.algos.generate, true, ["sign", "verify"])
2321

2422
const publicBuffer = await crypto.subtle
2523
.exportKey(CryptoConstants.formats.public, keys.publicKey)
2624

27-
const thumbprint = hex.from.buffer(
28-
await crypto.subtle.digest(CryptoConstants.algos.thumbprint, publicBuffer)
25+
const thumbprint = Hex.string(
26+
new Uint8Array(
27+
await crypto.subtle.digest(CryptoConstants.algos.thumbprint, publicBuffer)
28+
)
2929
)
3030

3131
return new this(thumbprint, keys.publicKey, keys.privateKey)
3232
}
3333

34-
static async fromJson(json: KeypairJson) {
35-
const crypto = await getCrypto()
36-
37-
const pubkey = await Pubkey.fromJson(json)
34+
static async fromData(data: KeypairData) {
35+
const pubkey = await Pubkey.fromData(data)
3836
const extractable = true
39-
const privateBuffer = hex.to.buffer(json.privateKey)
37+
const privateBuffer = Hex.bytes(data.privateKey).buffer
4038

4139
const privateKey = await crypto.subtle.importKey(
4240
CryptoConstants.formats.private,
@@ -49,17 +47,16 @@ export class Keypair extends Pubkey {
4947
return new this(pubkey.thumbprint, pubkey.publicKey, privateKey)
5048
}
5149

52-
async toJson(): Promise<KeypairJson> {
53-
const crypto = await getCrypto()
54-
const pubkey = await super.toJson()
50+
async toData(): Promise<KeypairData> {
51+
const pubkey = await super.toData()
5552

5653
const privateBuffer = await crypto.subtle
5754
.exportKey(CryptoConstants.formats.private, this.privateKey)
5855

5956
return {
6057
thumbprint: pubkey.thumbprint,
6158
publicKey: pubkey.publicKey,
62-
privateKey: hex.from.buffer(privateBuffer),
59+
privateKey: Hex.string(new Uint8Array(privateBuffer)),
6360
}
6461
}
6562

@@ -68,7 +65,7 @@ export class Keypair extends Pubkey {
6865
}
6966

7067
async sign<P extends Payload>(payload: P) {
71-
return await JsonWebToken.sign<P>(this.privateKey, payload)
68+
return await Token.sign<P>(this.privateKey, payload)
7269
}
7370
}
7471

0 commit comments

Comments
 (0)