@atproto/oauth-client 0.3.17 → 0.3.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/fetch-dpop.d.ts.map +1 -1
- package/dist/fetch-dpop.js +27 -10
- package/dist/fetch-dpop.js.map +1 -1
- package/package.json +1 -1
- package/src/fetch-dpop.ts +30 -26
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# @atproto/oauth-client
|
2
2
|
|
3
|
+
## 0.3.19
|
4
|
+
|
5
|
+
### Patch Changes
|
6
|
+
|
7
|
+
- [#3877](https://github.com/bluesky-social/atproto/pull/3877) [`a03f0b906`](https://github.com/bluesky-social/atproto/commit/a03f0b906b108f8c766a5700f0d68b55748f23bd) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Remove un-necessary validation of `alg` on every dpop token creation
|
8
|
+
|
9
|
+
## 0.3.18
|
10
|
+
|
11
|
+
### Patch Changes
|
12
|
+
|
13
|
+
- [`36d0d370c`](https://github.com/bluesky-social/atproto/commit/36d0d370c24498f74c243ebfb01564e5050c672d) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Remove query & fragment from DPoP proof `htu` claim
|
14
|
+
|
3
15
|
## 0.3.17
|
4
16
|
|
5
17
|
### Patch Changes
|
package/dist/fetch-dpop.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"fetch-dpop.d.ts","sourceRoot":"","sources":["../src/fetch-dpop.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAClC,OAAO,EAAE,KAAK,EAAE,YAAY,EAAwB,MAAM,qBAAqB,CAAA;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AASxD,MAAM,MAAM,uBAAuB,CAAC,CAAC,GAAG,YAAY,IAAI;IACtD,GAAG,EAAE,GAAG,CAAA;IACR,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAE3C;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;CACjB,CAAA;AAED,wBAAgB,gBAAgB,CAAC,CAAC,GAAG,YAAY,EAAE,EACjD,GAAG,EACH,GAAG,
|
1
|
+
{"version":3,"file":"fetch-dpop.d.ts","sourceRoot":"","sources":["../src/fetch-dpop.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAClC,OAAO,EAAE,KAAK,EAAE,YAAY,EAAwB,MAAM,qBAAqB,CAAA;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AASxD,MAAM,MAAM,uBAAuB,CAAC,CAAC,GAAG,YAAY,IAAI;IACtD,GAAG,EAAE,GAAG,CAAA;IACR,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAE3C;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;CACjB,CAAA;AAED,wBAAgB,gBAAgB,CAAC,CAAC,GAAG,YAAY,EAAE,EACjD,GAAG,EACH,GAAG,EAEH,aAAa,EACb,MAAM,EACN,MAAiE,EACjE,YAAY,EACZ,KAAwB,GACzB,EAAE,uBAAuB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAuFvC"}
|
package/dist/fetch-dpop.js
CHANGED
@@ -6,15 +6,15 @@ const fetch_1 = require("@atproto-labs/fetch");
|
|
6
6
|
// "undefined" in non https environments or environments without crypto
|
7
7
|
const subtle = globalThis.crypto?.subtle;
|
8
8
|
const ReadableStream = globalThis.ReadableStream;
|
9
|
-
function dpopFetchWrapper({ key, iss,
|
9
|
+
function dpopFetchWrapper({ key, iss,
|
10
|
+
// @TODO we should provide a default based on specs
|
11
|
+
supportedAlgs, nonces, sha256 = typeof subtle !== 'undefined' ? subtleSha256 : undefined, isAuthServer, fetch = globalThis.fetch, }) {
|
10
12
|
if (!sha256) {
|
11
13
|
throw new TypeError(`crypto.subtle is not available in this environment. Please provide a sha256 function.`);
|
12
14
|
}
|
15
|
+
// Throws if negotiation fails
|
13
16
|
const alg = negotiateAlg(key, supportedAlgs);
|
14
17
|
return async function (input, init) {
|
15
|
-
if (!key.algorithms.includes(alg)) {
|
16
|
-
throw new TypeError(`Key does not support the algorithm ${alg}`);
|
17
|
-
}
|
18
18
|
const request = init == null && input instanceof Request
|
19
19
|
? input
|
20
20
|
: new Request(input, init);
|
@@ -22,8 +22,9 @@ function dpopFetchWrapper({ key, iss, supportedAlgs, nonces, sha256 = typeof sub
|
|
22
22
|
const ath = authorizationHeader?.startsWith('DPoP ')
|
23
23
|
? await sha256(authorizationHeader.slice(5))
|
24
24
|
: undefined;
|
25
|
-
const {
|
26
|
-
const
|
25
|
+
const { origin } = new URL(request.url);
|
26
|
+
const htm = request.method;
|
27
|
+
const htu = buildHtu(request.url);
|
27
28
|
let initNonce;
|
28
29
|
try {
|
29
30
|
initNonce = await nonces.get(origin);
|
@@ -31,7 +32,7 @@ function dpopFetchWrapper({ key, iss, supportedAlgs, nonces, sha256 = typeof sub
|
|
31
32
|
catch {
|
32
33
|
// Ignore get errors, we will just not send a nonce
|
33
34
|
}
|
34
|
-
const initProof = await buildProof(key, alg, iss,
|
35
|
+
const initProof = await buildProof(key, alg, iss, htm, htu, initNonce, ath);
|
35
36
|
request.headers.set('DPoP', initProof);
|
36
37
|
const initResponse = await fetch.call(this, request);
|
37
38
|
// Make sure the response body is consumed. Either by the caller (when the
|
@@ -69,14 +70,30 @@ function dpopFetchWrapper({ key, iss, supportedAlgs, nonces, sha256 = typeof sub
|
|
69
70
|
// We will now retry the request with the fresh nonce.
|
70
71
|
// The initial response body must be consumed (see cancelBody's doc).
|
71
72
|
await (0, fetch_1.cancelBody)(initResponse, 'log');
|
72
|
-
const nextProof = await buildProof(key, alg, iss,
|
73
|
+
const nextProof = await buildProof(key, alg, iss, htm, htu, nextNonce, ath);
|
73
74
|
const nextRequest = new Request(input, init);
|
74
75
|
nextRequest.headers.set('DPoP', nextProof);
|
75
76
|
return fetch.call(this, nextRequest);
|
76
77
|
};
|
77
78
|
}
|
79
|
+
/**
|
80
|
+
* Strip query and fragment
|
81
|
+
*
|
82
|
+
* @see {@link https://www.rfc-editor.org/rfc/rfc9449.html#section-4.2-4.6}
|
83
|
+
*/
|
84
|
+
function buildHtu(url) {
|
85
|
+
const fragmentIndex = url.indexOf('#');
|
86
|
+
const queryIndex = url.indexOf('?');
|
87
|
+
const end = fragmentIndex === -1
|
88
|
+
? queryIndex
|
89
|
+
: queryIndex === -1
|
90
|
+
? fragmentIndex
|
91
|
+
: Math.min(fragmentIndex, queryIndex);
|
92
|
+
return end === -1 ? url : url.slice(0, end);
|
93
|
+
}
|
78
94
|
async function buildProof(key, alg, iss, htm, htu, nonce, ath) {
|
79
|
-
|
95
|
+
const jwk = key.bareJwk;
|
96
|
+
if (!jwk) {
|
80
97
|
throw new Error('Only asymmetric keys can be used as DPoP proofs');
|
81
98
|
}
|
82
99
|
const now = Math.floor(Date.now() / 1e3);
|
@@ -85,7 +102,7 @@ async function buildProof(key, alg, iss, htm, htu, nonce, ath) {
|
|
85
102
|
{
|
86
103
|
alg,
|
87
104
|
typ: 'dpop+jwt',
|
88
|
-
jwk
|
105
|
+
jwk,
|
89
106
|
}, {
|
90
107
|
iss,
|
91
108
|
iat: now,
|
package/dist/fetch-dpop.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"fetch-dpop.js","sourceRoot":"","sources":["../src/fetch-dpop.ts"],"names":[],"mappings":";;AA8BA,
|
1
|
+
{"version":3,"file":"fetch-dpop.js","sourceRoot":"","sources":["../src/fetch-dpop.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@atproto/oauth-client",
|
3
|
-
"version": "0.3.
|
3
|
+
"version": "0.3.19",
|
4
4
|
"license": "MIT",
|
5
5
|
"description": "OAuth client for ATPROTO PDS. This package serves as common base for environment-specific implementations (NodeJS, Browser, React-Native).",
|
6
6
|
"keywords": [
|
package/src/fetch-dpop.ts
CHANGED
@@ -31,6 +31,7 @@ export type DpopFetchWrapperOptions<C = FetchContext> = {
|
|
31
31
|
export function dpopFetchWrapper<C = FetchContext>({
|
32
32
|
key,
|
33
33
|
iss,
|
34
|
+
// @TODO we should provide a default based on specs
|
34
35
|
supportedAlgs,
|
35
36
|
nonces,
|
36
37
|
sha256 = typeof subtle !== 'undefined' ? subtleSha256 : undefined,
|
@@ -43,13 +44,10 @@ export function dpopFetchWrapper<C = FetchContext>({
|
|
43
44
|
)
|
44
45
|
}
|
45
46
|
|
47
|
+
// Throws if negotiation fails
|
46
48
|
const alg = negotiateAlg(key, supportedAlgs)
|
47
49
|
|
48
50
|
return async function (this: C, input, init) {
|
49
|
-
if (!key.algorithms.includes(alg)) {
|
50
|
-
throw new TypeError(`Key does not support the algorithm ${alg}`)
|
51
|
-
}
|
52
|
-
|
53
51
|
const request: Request =
|
54
52
|
init == null && input instanceof Request
|
55
53
|
? input
|
@@ -60,8 +58,10 @@ export function dpopFetchWrapper<C = FetchContext>({
|
|
60
58
|
? await sha256(authorizationHeader.slice(5))
|
61
59
|
: undefined
|
62
60
|
|
63
|
-
const {
|
64
|
-
|
61
|
+
const { origin } = new URL(request.url)
|
62
|
+
|
63
|
+
const htm = request.method
|
64
|
+
const htu = buildHtu(request.url)
|
65
65
|
|
66
66
|
let initNonce: string | undefined
|
67
67
|
try {
|
@@ -70,15 +70,7 @@ export function dpopFetchWrapper<C = FetchContext>({
|
|
70
70
|
// Ignore get errors, we will just not send a nonce
|
71
71
|
}
|
72
72
|
|
73
|
-
const initProof = await buildProof(
|
74
|
-
key,
|
75
|
-
alg,
|
76
|
-
iss,
|
77
|
-
method,
|
78
|
-
url,
|
79
|
-
initNonce,
|
80
|
-
ath,
|
81
|
-
)
|
73
|
+
const initProof = await buildProof(key, alg, iss, htm, htu, initNonce, ath)
|
82
74
|
request.headers.set('DPoP', initProof)
|
83
75
|
|
84
76
|
const initResponse = await fetch.call(this, request)
|
@@ -126,15 +118,7 @@ export function dpopFetchWrapper<C = FetchContext>({
|
|
126
118
|
// The initial response body must be consumed (see cancelBody's doc).
|
127
119
|
await cancelBody(initResponse, 'log')
|
128
120
|
|
129
|
-
const nextProof = await buildProof(
|
130
|
-
key,
|
131
|
-
alg,
|
132
|
-
iss,
|
133
|
-
method,
|
134
|
-
url,
|
135
|
-
nextNonce,
|
136
|
-
ath,
|
137
|
-
)
|
121
|
+
const nextProof = await buildProof(key, alg, iss, htm, htu, nextNonce, ath)
|
138
122
|
const nextRequest = new Request(input, init)
|
139
123
|
nextRequest.headers.set('DPoP', nextProof)
|
140
124
|
|
@@ -142,6 +126,25 @@ export function dpopFetchWrapper<C = FetchContext>({
|
|
142
126
|
}
|
143
127
|
}
|
144
128
|
|
129
|
+
/**
|
130
|
+
* Strip query and fragment
|
131
|
+
*
|
132
|
+
* @see {@link https://www.rfc-editor.org/rfc/rfc9449.html#section-4.2-4.6}
|
133
|
+
*/
|
134
|
+
function buildHtu(url: string): string {
|
135
|
+
const fragmentIndex = url.indexOf('#')
|
136
|
+
const queryIndex = url.indexOf('?')
|
137
|
+
|
138
|
+
const end =
|
139
|
+
fragmentIndex === -1
|
140
|
+
? queryIndex
|
141
|
+
: queryIndex === -1
|
142
|
+
? fragmentIndex
|
143
|
+
: Math.min(fragmentIndex, queryIndex)
|
144
|
+
|
145
|
+
return end === -1 ? url : url.slice(0, end)
|
146
|
+
}
|
147
|
+
|
145
148
|
async function buildProof(
|
146
149
|
key: Key,
|
147
150
|
alg: string,
|
@@ -151,7 +154,8 @@ async function buildProof(
|
|
151
154
|
nonce?: string,
|
152
155
|
ath?: string,
|
153
156
|
) {
|
154
|
-
|
157
|
+
const jwk = key.bareJwk
|
158
|
+
if (!jwk) {
|
155
159
|
throw new Error('Only asymmetric keys can be used as DPoP proofs')
|
156
160
|
}
|
157
161
|
|
@@ -162,7 +166,7 @@ async function buildProof(
|
|
162
166
|
{
|
163
167
|
alg,
|
164
168
|
typ: 'dpop+jwt',
|
165
|
-
jwk
|
169
|
+
jwk,
|
166
170
|
},
|
167
171
|
{
|
168
172
|
iss,
|