@atproto/oauth-client 0.1.0 → 0.1.1
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 +15 -0
- package/README.md +162 -32
- package/dist/errors/token-invalid-error.d.ts +7 -0
- package/dist/errors/token-invalid-error.d.ts.map +1 -0
- package/dist/errors/token-invalid-error.js +16 -0
- package/dist/errors/token-invalid-error.js.map +1 -0
- package/dist/errors/token-refresh-error.d.ts +7 -0
- package/dist/errors/token-refresh-error.d.ts.map +1 -0
- package/dist/errors/token-refresh-error.js +16 -0
- package/dist/errors/token-refresh-error.js.map +1 -0
- package/dist/errors/token-revoked-error.d.ts +7 -0
- package/dist/errors/token-revoked-error.d.ts.map +1 -0
- package/dist/errors/token-revoked-error.js +16 -0
- package/dist/errors/token-revoked-error.js.map +1 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/lock.d.ts +2 -1
- package/dist/lock.d.ts.map +1 -1
- package/dist/lock.js +2 -2
- package/dist/lock.js.map +1 -1
- package/dist/oauth-agent.d.ts.map +1 -1
- package/dist/oauth-agent.js +14 -9
- package/dist/oauth-agent.js.map +1 -1
- package/dist/oauth-client.d.ts +250 -20
- package/dist/oauth-client.d.ts.map +1 -1
- package/dist/oauth-client.js +67 -9
- package/dist/oauth-client.js.map +1 -1
- package/dist/oauth-resolver.d.ts +5 -4
- package/dist/oauth-resolver.d.ts.map +1 -1
- package/dist/oauth-resolver.js.map +1 -1
- package/dist/oauth-server-agent.d.ts.map +1 -1
- package/dist/oauth-server-agent.js +85 -29
- package/dist/oauth-server-agent.js.map +1 -1
- package/dist/runtime-implementation.d.ts +10 -5
- package/dist/runtime-implementation.d.ts.map +1 -1
- package/dist/runtime.d.ts +3 -3
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +18 -12
- package/dist/runtime.js.map +1 -1
- package/dist/session-getter.d.ts +19 -0
- package/dist/session-getter.d.ts.map +1 -1
- package/dist/session-getter.js +134 -42
- package/dist/session-getter.js.map +1 -1
- package/dist/state-store.d.ts +11 -0
- package/dist/state-store.d.ts.map +1 -0
- package/dist/state-store.js +3 -0
- package/dist/state-store.js.map +1 -0
- package/dist/types.d.ts +3 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/util.d.ts +10 -3
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +43 -23
- package/dist/util.js.map +1 -1
- package/dist/validate-client-metadata.d.ts.map +1 -1
- package/dist/validate-client-metadata.js +17 -0
- package/dist/validate-client-metadata.js.map +1 -1
- package/package.json +8 -8
- package/src/errors/token-invalid-error.ts +9 -0
- package/src/errors/token-refresh-error.ts +9 -0
- package/src/errors/token-revoked-error.ts +9 -0
- package/src/index.ts +11 -1
- package/src/lock.ts +3 -4
- package/src/oauth-agent.ts +20 -9
- package/src/oauth-client.ts +113 -31
- package/src/oauth-resolver.ts +4 -4
- package/src/oauth-server-agent.ts +9 -9
- package/src/runtime-implementation.ts +19 -11
- package/src/runtime.ts +13 -17
- package/src/session-getter.ts +135 -71
- package/src/state-store.ts +12 -0
- package/src/types.ts +5 -2
- package/src/util.ts +63 -32
- package/src/validate-client-metadata.ts +18 -0
@@ -1,12 +1,57 @@
|
|
1
1
|
"use strict";
|
2
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
3
|
+
if (value !== null && value !== void 0) {
|
4
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
5
|
+
var dispose;
|
6
|
+
if (async) {
|
7
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
8
|
+
dispose = value[Symbol.asyncDispose];
|
9
|
+
}
|
10
|
+
if (dispose === void 0) {
|
11
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
12
|
+
dispose = value[Symbol.dispose];
|
13
|
+
}
|
14
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
15
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
16
|
+
}
|
17
|
+
else if (async) {
|
18
|
+
env.stack.push({ async: true });
|
19
|
+
}
|
20
|
+
return value;
|
21
|
+
};
|
22
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
23
|
+
return function (env) {
|
24
|
+
function fail(e) {
|
25
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
26
|
+
env.hasError = true;
|
27
|
+
}
|
28
|
+
function next() {
|
29
|
+
while (env.stack.length) {
|
30
|
+
var rec = env.stack.pop();
|
31
|
+
try {
|
32
|
+
var result = rec.dispose && rec.dispose.call(rec.value);
|
33
|
+
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
34
|
+
}
|
35
|
+
catch (e) {
|
36
|
+
fail(e);
|
37
|
+
}
|
38
|
+
}
|
39
|
+
if (env.hasError) throw env.error;
|
40
|
+
}
|
41
|
+
return next();
|
42
|
+
};
|
43
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
44
|
+
var e = new Error(message);
|
45
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
46
|
+
});
|
2
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
48
|
exports.OAuthServerAgent = void 0;
|
4
49
|
const fetch_1 = require("@atproto-labs/fetch");
|
5
50
|
const oauth_types_1 = require("@atproto/oauth-types");
|
6
51
|
const constants_js_1 = require("./constants.js");
|
52
|
+
const token_refresh_error_js_1 = require("./errors/token-refresh-error.js");
|
7
53
|
const fetch_dpop_js_1 = require("./fetch-dpop.js");
|
8
54
|
const oauth_response_error_js_1 = require("./oauth-response-error.js");
|
9
|
-
const refresh_error_js_1 = require("./refresh-error.js");
|
10
55
|
const util_js_1 = require("./util.js");
|
11
56
|
class OAuthServerAgent {
|
12
57
|
constructor(dpopKey, serverMetadata, clientMetadata, dpopNonces, oauthResolver, runtime, keyset, fetch) {
|
@@ -93,7 +138,7 @@ class OAuthServerAgent {
|
|
93
138
|
}
|
94
139
|
async refresh(tokenSet) {
|
95
140
|
if (!tokenSet.refresh_token) {
|
96
|
-
throw new
|
141
|
+
throw new token_refresh_error_js_1.TokenRefreshError(tokenSet.sub, 'No refresh token available');
|
97
142
|
}
|
98
143
|
const tokenResponse = await this.request('token', {
|
99
144
|
grant_type: 'refresh_token',
|
@@ -101,10 +146,10 @@ class OAuthServerAgent {
|
|
101
146
|
});
|
102
147
|
try {
|
103
148
|
if (tokenSet.sub !== tokenResponse.sub) {
|
104
|
-
throw new
|
149
|
+
throw new token_refresh_error_js_1.TokenRefreshError(tokenSet.sub, `Unexpected "sub" in token response (${tokenResponse.sub})`);
|
105
150
|
}
|
106
151
|
if (tokenSet.iss !== this.serverMetadata.issuer) {
|
107
|
-
throw new
|
152
|
+
throw new token_refresh_error_js_1.TokenRefreshError(tokenSet.sub, 'Issuer mismatch');
|
108
153
|
}
|
109
154
|
return this.processTokenResponse(tokenResponse);
|
110
155
|
}
|
@@ -122,31 +167,42 @@ class OAuthServerAgent {
|
|
122
167
|
* able to use the "sub" (DID) as being the actual user's identifier.
|
123
168
|
*/
|
124
169
|
async processTokenResponse(tokenResponse) {
|
125
|
-
const {
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
:
|
149
|
-
|
170
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
171
|
+
try {
|
172
|
+
const { sub } = tokenResponse;
|
173
|
+
// ATPROTO requires that the "sub" is always present in the token response.
|
174
|
+
if (!sub)
|
175
|
+
throw new TypeError(`Missing "sub" in token response`);
|
176
|
+
// @TODO (?) make timeout configurable
|
177
|
+
const signal = __addDisposableResource(env_1, (0, util_js_1.timeoutSignal)(10e3), false);
|
178
|
+
const resolved = await this.oauthResolver.resolve(sub, { signal });
|
179
|
+
if (resolved.metadata.issuer !== this.serverMetadata.issuer) {
|
180
|
+
// Best case scenario; the user switched PDS. Worst case scenario; a bad
|
181
|
+
// actor is trying to impersonate a user. In any case, we must not allow
|
182
|
+
// this token to be used.
|
183
|
+
throw new TypeError('Issuer mismatch');
|
184
|
+
}
|
185
|
+
return {
|
186
|
+
sub,
|
187
|
+
aud: resolved.identity.pds.href,
|
188
|
+
iss: resolved.metadata.issuer,
|
189
|
+
scope: tokenResponse.scope,
|
190
|
+
id_token: tokenResponse.id_token,
|
191
|
+
refresh_token: tokenResponse.refresh_token,
|
192
|
+
access_token: tokenResponse.access_token,
|
193
|
+
token_type: tokenResponse.token_type ?? 'Bearer',
|
194
|
+
expires_at: typeof tokenResponse.expires_in === 'number'
|
195
|
+
? new Date(Date.now() + tokenResponse.expires_in * 1000).toISOString()
|
196
|
+
: undefined,
|
197
|
+
};
|
198
|
+
}
|
199
|
+
catch (e_1) {
|
200
|
+
env_1.error = e_1;
|
201
|
+
env_1.hasError = true;
|
202
|
+
}
|
203
|
+
finally {
|
204
|
+
__disposeResources(env_1);
|
205
|
+
}
|
150
206
|
}
|
151
207
|
async request(endpoint, payload) {
|
152
208
|
const url = this.serverMetadata[`${endpoint}_endpoint`];
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"oauth-server-agent.js","sourceRoot":"","sources":["../src/oauth-server-agent.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"oauth-server-agent.js","sourceRoot":"","sources":["../src/oauth-server-agent.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAgF;AAGhF,sDAU6B;AAE7B,iDAA6C;AAC7C,4EAAmE;AACnE,mDAAkD;AAElD,uEAA8D;AAG9D,uCAAyC;AAkBzC,MAAa,gBAAgB;IAG3B,YACW,OAAY,EACZ,cAAgD,EAChD,cAA8B,EAC9B,UAA0B,EAC1B,aAA4B,EAC5B,OAAgB,EAChB,MAAe,EACxB,KAAa;QAPb;;;;mBAAS,OAAO;WAAK;QACrB;;;;mBAAS,cAAc;WAAkC;QACzD;;;;mBAAS,cAAc;WAAgB;QACvC;;;;mBAAS,UAAU;WAAgB;QACnC;;;;mBAAS,aAAa;WAAe;QACrC;;;;mBAAS,OAAO;WAAS;QACzB;;;;mBAAS,MAAM;WAAS;QAThB;;;;;WAAyB;QAYjC,IAAI,CAAC,SAAS,GAAG,IAAA,gCAAgB,EAAO;YACtC,KAAK,EAAE,IAAA,iBAAS,EAAC,KAAK,CAAC;YACvB,GAAG,EAAE,cAAc,CAAC,SAAS;YAC7B,GAAG,EAAE,OAAO;YACZ,aAAa,EAAE,cAAc,CAAC,iCAAiC;YAC/D,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YACtC,MAAM,EAAE,UAAU;YAClB,YAAY,EAAE,IAAI;SACnB,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa;QACxB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,aAAa;QACf,CAAC;IACH,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,IAAY,EAAE,QAAiB;QAChD,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;YAChD,UAAU,EAAE,oBAAoB;YAChC,YAAY,EAAE,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC,CAAE;YACnD,IAAI;YACJ,aAAa,EAAE,QAAQ;SACxB,CAAC,CAAA;QAEF,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAA;QACjD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CAAA;YAE7C,MAAM,GAAG,CAAA;QACX,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,QAAkB;QAC9B,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;YAC5B,MAAM,IAAI,0CAAiB,CAAC,QAAQ,CAAC,GAAG,EAAE,4BAA4B,CAAC,CAAA;QACzE,CAAC;QAED,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;YAChD,UAAU,EAAE,eAAe;YAC3B,aAAa,EAAE,QAAQ,CAAC,aAAa;SACtC,CAAC,CAAA;QAEF,IAAI,CAAC;YACH,IAAI,QAAQ,CAAC,GAAG,KAAK,aAAa,CAAC,GAAG,EAAE,CAAC;gBACvC,MAAM,IAAI,0CAAiB,CACzB,QAAQ,CAAC,GAAG,EACZ,uCAAuC,aAAa,CAAC,GAAG,GAAG,CAC5D,CAAA;YACH,CAAC;YACD,IAAI,QAAQ,CAAC,GAAG,KAAK,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC;gBAChD,MAAM,IAAI,0CAAiB,CAAC,QAAQ,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAA;YAC9D,CAAC;YAED,OAAO,IAAI,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAA;QACjD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CAAA;YAE7C,MAAM,GAAG,CAAA;QACX,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACK,KAAK,CAAC,oBAAoB,CAChC,aAAiC;;;YAEjC,MAAM,EAAE,GAAG,EAAE,GAAG,aAAa,CAAA;YAC7B,2EAA2E;YAC3E,IAAI,CAAC,GAAG;gBAAE,MAAM,IAAI,SAAS,CAAC,iCAAiC,CAAC,CAAA;YAEhE,sCAAsC;YACtC,MAAM,MAAM,kCAAG,IAAA,uBAAa,EAAC,IAAI,CAAC,QAAA,CAAA;YAElC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;YAElE,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,KAAK,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC;gBAC5D,wEAAwE;gBACxE,wEAAwE;gBACxE,yBAAyB;gBACzB,MAAM,IAAI,SAAS,CAAC,iBAAiB,CAAC,CAAA;YACxC,CAAC;YAED,OAAO;gBACL,GAAG;gBACH,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI;gBAC/B,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM;gBAE7B,KAAK,EAAE,aAAa,CAAC,KAAK;gBAC1B,QAAQ,EAAE,aAAa,CAAC,QAAQ;gBAChC,aAAa,EAAE,aAAa,CAAC,aAAa;gBAC1C,YAAY,EAAE,aAAa,CAAC,YAAY;gBACxC,UAAU,EAAE,aAAa,CAAC,UAAU,IAAI,QAAQ;gBAChD,UAAU,EACR,OAAO,aAAa,CAAC,UAAU,KAAK,QAAQ;oBAC1C,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;oBACtE,CAAC,CAAC,SAAS;aAChB,CAAA;;;;;;;;;KACF;IAeD,KAAK,CAAC,OAAO,CAAC,QAA2B,EAAE,OAAgC;QACzE,MAAM,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,QAAQ,WAAW,CAAC,CAAA;QACvD,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,MAAM,QAAQ,qBAAqB,CAAC,CAAA;QAE9D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAA;QAEjD,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE;YACnD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAChE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;SACtD,CAAC,CAAC,IAAI,CAAC,IAAA,0BAAkB,GAAE,CAAC,CAAA;QAE7B,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;YAChB,QAAQ,QAAQ,EAAE,CAAC;gBACjB,KAAK,OAAO;oBACV,OAAO,sCAAwB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;gBAC7C,KAAK,8BAA8B;oBACjC,OAAO,oCAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;gBAC3C;oBACE,OAAO,IAAI,CAAA;YACf,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,4CAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QAC9C,CAAC;IACH,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,QAA2B;QAI/C,MAAM,eAAe,GACnB,IAAI,CAAC,cAAc,CAAC,GAAG,QAAQ,kCAAkC,CAAC;YAClE,IAAI,CAAC,cAAc,CAAC,uCAAuC,CAAC,CAAA;QAE9D,MAAM,MAAM,GACV,IAAI,CAAC,cAAc,CAAC,GAAG,QAAQ,uBAAuB,CAAC;YACvD,IAAI,CAAC,cAAc,CAAC,4BAA4B,CAAC,CAAA;QAEnD,IACE,MAAM,KAAK,iBAAiB;YAC5B,CAAC,IAAI,CAAC,MAAM;gBACV,CAAC,MAAM;gBACP,CAAC,eAAe,EAAE,QAAQ,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,CAAC,EAC1D,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAA;YAExD,IAAI,CAAC;gBACH,MAAM,GAAG,GACP,IAAI,CAAC,cAAc,CACjB,GAAG,QAAQ,6CAA6C,CACzD;oBACD,IAAI,CAAC,cAAc,CACjB,kDAAkD,CACnD;oBACD,2BAAY,CAAA;gBAEd,wEAAwE;gBACxE,wEAAwE;gBACxE,wDAAwD;gBACxD,MAAM,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI;qBACvC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC;qBACrB,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAA;gBAEpD,OAAO;oBACL,OAAO,EAAE;wBACP,SAAS,EAAE,IAAI,CAAC,cAAc,CAAC,SAAS;wBACxC,qBAAqB,EAAE,8CAAgC;wBACvD,gBAAgB,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAC3C,EAAE,GAAG,EAAE,GAAG,EAAE,EACZ;4BACE,GAAG,EAAE,IAAI,CAAC,cAAc,CAAC,SAAS;4BAClC,GAAG,EAAE,IAAI,CAAC,cAAc,CAAC,SAAS;4BAClC,GAAG,EAAE,IAAI,CAAC,cAAc,CAAC,MAAM;4BAC/B,GAAG,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE;4BACvC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;yBACnC,CACF;qBACF;iBACF,CAAA;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,MAAM,KAAK,iBAAiB;oBAAE,MAAM,GAAG,CAAA;gBAE3C,uBAAuB;YACzB,CAAC;QACH,CAAC;QAED,IACE,MAAM,KAAK,MAAM;YACjB,CAAC,CAAC,MAAM,IAAI,CAAC,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,EACxD,CAAC;YACD,OAAO;gBACL,OAAO,EAAE;oBACP,SAAS,EAAE,IAAI,CAAC,cAAc,CAAC,SAAS;iBACzC;aACF,CAAA;QACH,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,eAAe,QAAQ,wBAAwB,CAAC,CAAA;IAClE,CAAC;CACF;AA1OD,4CA0OC"}
|
@@ -1,12 +1,17 @@
|
|
1
1
|
import { Key } from '@atproto/jwk';
|
2
|
+
import { Awaitable } from './util.js';
|
3
|
+
export type { Key };
|
4
|
+
export type RuntimeKeyFactory = (algs: string[]) => Key | PromiseLike<Key>;
|
5
|
+
export type RuntimeRandomValues = (length: number) => Awaitable<Uint8Array>;
|
2
6
|
export type DigestAlgorithm = {
|
3
7
|
name: 'sha256' | 'sha384' | 'sha512';
|
4
8
|
};
|
5
|
-
export type
|
9
|
+
export type RuntimeDigest = (data: Uint8Array, alg: DigestAlgorithm) => Awaitable<Uint8Array>;
|
10
|
+
export type RuntimeLock = <T>(name: string, fn: () => Awaitable<T>) => Awaitable<T>;
|
6
11
|
export interface RuntimeImplementation {
|
7
|
-
createKey
|
8
|
-
getRandomValues:
|
9
|
-
digest:
|
10
|
-
requestLock?:
|
12
|
+
createKey: RuntimeKeyFactory;
|
13
|
+
getRandomValues: RuntimeRandomValues;
|
14
|
+
digest: RuntimeDigest;
|
15
|
+
requestLock?: RuntimeLock;
|
11
16
|
}
|
12
17
|
//# sourceMappingURL=runtime-implementation.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"runtime-implementation.d.ts","sourceRoot":"","sources":["../src/runtime-implementation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;
|
1
|
+
{"version":3,"file":"runtime-implementation.d.ts","sourceRoot":"","sources":["../src/runtime-implementation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAErC,YAAY,EAAE,GAAG,EAAE,CAAA;AACnB,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,CAAA;AAE1E,MAAM,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,SAAS,CAAC,UAAU,CAAC,CAAA;AAE3E,MAAM,MAAM,eAAe,GAAG;IAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAA;CAAE,CAAA;AACtE,MAAM,MAAM,aAAa,GAAG,CAC1B,IAAI,EAAE,UAAU,EAChB,GAAG,EAAE,eAAe,KACjB,SAAS,CAAC,UAAU,CAAC,CAAA;AAE1B,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,EAC1B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,SAAS,CAAC,CAAC,CAAC,KACnB,SAAS,CAAC,CAAC,CAAC,CAAA;AAEjB,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,iBAAiB,CAAA;IAC5B,eAAe,EAAE,mBAAmB,CAAA;IACpC,MAAM,EAAE,aAAa,CAAA;IACrB,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B"}
|
package/dist/runtime.d.ts
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
import { JwtHeader, JwtPayload, Key } from '@atproto/jwk';
|
2
|
-
import { RuntimeImplementation } from './runtime-implementation.js';
|
2
|
+
import { RuntimeImplementation, RuntimeLock } from './runtime-implementation.js';
|
3
3
|
export declare class Runtime {
|
4
4
|
protected implementation: RuntimeImplementation;
|
5
|
+
readonly hasImplementationLock: boolean;
|
6
|
+
readonly usingLock: RuntimeLock;
|
5
7
|
constructor(implementation: RuntimeImplementation);
|
6
8
|
generateKey(algs: string[]): Promise<Key>;
|
7
9
|
sha256(text: string): Promise<string>;
|
8
10
|
generateNonce(length?: number): Promise<string>;
|
9
|
-
get hasLock(): boolean;
|
10
|
-
withLock<T>(name: string, fn: () => T | PromiseLike<T>): Promise<T>;
|
11
11
|
validateIdTokenClaims(token: string, state: string, nonce: string, code?: string, accessToken?: string): Promise<{
|
12
12
|
header: JwtHeader;
|
13
13
|
payload: JwtPayload;
|
package/dist/runtime.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,EAAmB,MAAM,cAAc,CAAA;AAI1E,OAAO,EAEL,qBAAqB,
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,EAAmB,MAAM,cAAc,CAAA;AAI1E,OAAO,EAEL,qBAAqB,EACrB,WAAW,EACZ,MAAM,6BAA6B,CAAA;AAEpC,qBAAa,OAAO;IAIN,SAAS,CAAC,cAAc,EAAE,qBAAqB;IAH3D,QAAQ,CAAC,qBAAqB,EAAE,OAAO,CAAA;IACvC,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAA;gBAET,cAAc,EAAE,qBAAqB;IAU9C,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;IAKzC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMrC,aAAa,CAAC,MAAM,SAAK,GAAG,OAAO,CAAC,MAAM,CAAC;IAK3C,qBAAqB,CAChC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC;QACT,MAAM,EAAE,SAAS,CAAA;QACjB,OAAO,EAAE,UAAU,CAAA;KACpB,CAAC;YAoBY,iBAAiB;cAiBf,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE;IAU1B,YAAY,CAAC,UAAU,CAAC,EAAE,MAAM;;;;;IAShC,sBAAsB,CAAC,GAAG,KAAA;IAMvC;;;;;;OAMG;cACa,gBAAgB,CAAC,UAAU,SAAK;CAOjD"}
|
package/dist/runtime.js
CHANGED
@@ -12,6 +12,24 @@ class Runtime {
|
|
12
12
|
writable: true,
|
13
13
|
value: implementation
|
14
14
|
});
|
15
|
+
Object.defineProperty(this, "hasImplementationLock", {
|
16
|
+
enumerable: true,
|
17
|
+
configurable: true,
|
18
|
+
writable: true,
|
19
|
+
value: void 0
|
20
|
+
});
|
21
|
+
Object.defineProperty(this, "usingLock", {
|
22
|
+
enumerable: true,
|
23
|
+
configurable: true,
|
24
|
+
writable: true,
|
25
|
+
value: void 0
|
26
|
+
});
|
27
|
+
const { requestLock } = implementation;
|
28
|
+
this.hasImplementationLock = requestLock != null;
|
29
|
+
this.usingLock =
|
30
|
+
requestLock?.bind(implementation) ||
|
31
|
+
// Falling back to a local lock
|
32
|
+
lock_js_1.requestLocalLock;
|
15
33
|
}
|
16
34
|
async generateKey(algs) {
|
17
35
|
const algsSorted = Array.from(algs).sort(compareAlgos);
|
@@ -26,18 +44,6 @@ class Runtime {
|
|
26
44
|
const bytes = await this.implementation.getRandomValues(length);
|
27
45
|
return base64_1.base64url.baseEncode(bytes);
|
28
46
|
}
|
29
|
-
get hasLock() {
|
30
|
-
return !!this.implementation.requestLock;
|
31
|
-
}
|
32
|
-
async withLock(name, fn) {
|
33
|
-
if (this.implementation.requestLock) {
|
34
|
-
return this.implementation.requestLock(name, fn);
|
35
|
-
}
|
36
|
-
else {
|
37
|
-
// Falling back to a local lock
|
38
|
-
return (0, lock_js_1.requestLocalLock)(name, fn);
|
39
|
-
}
|
40
|
-
}
|
41
47
|
async validateIdTokenClaims(token, state, nonce, code, accessToken) {
|
42
48
|
// It's fine to use unsafeDecodeJwt here because the token was received from
|
43
49
|
// the server's token endpoint. The following checks are to ensure that the
|
package/dist/runtime.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":";;;AAAA,sCAA0E;AAC1E,sDAAqD;AAErD,uCAA4C;
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
|
package/dist/session-getter.d.ts
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
import { CachedGetter, GetCachedOptions, SimpleStore } from '@atproto-labs/simple-store';
|
2
2
|
import { Key } from '@atproto/jwk';
|
3
|
+
import { TokenInvalidError } from './errors/token-invalid-error.js';
|
4
|
+
import { TokenRefreshError } from './errors/token-refresh-error.js';
|
5
|
+
import { TokenRevokedError } from './errors/token-revoked-error.js';
|
3
6
|
import { TokenSet } from './oauth-server-agent.js';
|
4
7
|
import { OAuthServerFactory } from './oauth-server-factory.js';
|
5
8
|
import { Runtime } from './runtime.js';
|
@@ -8,6 +11,16 @@ export type Session = {
|
|
8
11
|
tokenSet: TokenSet;
|
9
12
|
};
|
10
13
|
export type SessionStore = SimpleStore<string, Session>;
|
14
|
+
export type SessionEventMap = {
|
15
|
+
updated: {
|
16
|
+
sub: string;
|
17
|
+
} & Session;
|
18
|
+
deleted: {
|
19
|
+
sub: string;
|
20
|
+
cause: TokenRefreshError | TokenRevokedError | TokenInvalidError | unknown;
|
21
|
+
};
|
22
|
+
};
|
23
|
+
export type SessionEventListener<T extends keyof SessionEventMap = keyof SessionEventMap> = (event: CustomEvent<SessionEventMap[T]>) => void;
|
11
24
|
/**
|
12
25
|
* There are several advantages to wrapping the sessionStore in a (single)
|
13
26
|
* CachedGetter, the main of which is that the cached getter will ensure that at
|
@@ -17,7 +30,13 @@ export type SessionStore = SimpleStore<string, Session>;
|
|
17
30
|
*/
|
18
31
|
export declare class SessionGetter extends CachedGetter<string, Session> {
|
19
32
|
private readonly runtime;
|
33
|
+
private readonly eventTarget;
|
20
34
|
constructor(sessionStore: SessionStore, serverFactory: OAuthServerFactory, runtime: Runtime);
|
35
|
+
addEventListener<T extends keyof SessionEventMap>(type: T, callback: SessionEventListener<T>, options?: AddEventListenerOptions | boolean): void;
|
36
|
+
removeEventListener<T extends keyof SessionEventMap>(type: T, callback: SessionEventListener<T>, options?: EventListenerOptions | boolean): void;
|
37
|
+
dispatchEvent<T extends keyof SessionEventMap>(type: T, detail: SessionEventMap[T]): boolean;
|
38
|
+
setStored(sub: string, session: Session): Promise<void>;
|
39
|
+
delStored(sub: string, cause?: unknown): Promise<void>;
|
21
40
|
/**
|
22
41
|
* @param refresh When `true`, the credentials will be refreshed even if they
|
23
42
|
* are not expired. When `false`, the credentials will not be refreshed even
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"session-getter.d.ts","sourceRoot":"","sources":["../src/session-getter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACZ,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAElC,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;
|
1
|
+
{"version":3,"file":"session-getter.d.ts","sourceRoot":"","sources":["../src/session-getter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACZ,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAElC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AAEnE,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAGtC,MAAM,MAAM,OAAO,GAAG;IACpB,OAAO,EAAE,GAAG,CAAA;IACZ,QAAQ,EAAE,QAAQ,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEvD,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,CAAA;KACZ,GAAG,OAAO,CAAA;IACX,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,CAAA;QACX,KAAK,EAAE,iBAAiB,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,OAAO,CAAA;KAC3E,CAAA;CACF,CAAA;AAED,MAAM,MAAM,oBAAoB,CAC9B,CAAC,SAAS,MAAM,eAAe,GAAG,MAAM,eAAe,IACrD,CAAC,KAAK,EAAE,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;AAEpD;;;;;;GAMG;AACH,qBAAa,aAAc,SAAQ,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC;IAM5D,OAAO,CAAC,QAAQ,CAAC,OAAO;IAL1B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA2C;gBAGrE,YAAY,EAAE,YAAY,EAC1B,aAAa,EAAE,kBAAkB,EAChB,OAAO,EAAE,OAAO;IAqInC,gBAAgB,CAAC,CAAC,SAAS,MAAM,eAAe,EAC9C,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,oBAAoB,CAAC,CAAC,CAAC,EACjC,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO;IAK7C,mBAAmB,CAAC,CAAC,SAAS,MAAM,eAAe,EACjD,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,oBAAoB,CAAC,CAAC,CAAC,EACjC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO;IAK1C,aAAa,CAAC,CAAC,SAAS,MAAM,eAAe,EAC3C,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,GACzB,OAAO;IAIJ,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAKvC,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5D;;;;;OAKG;IACG,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO;IAczC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;CASrE"}
|
package/dist/session-getter.js
CHANGED
@@ -1,9 +1,56 @@
|
|
1
1
|
"use strict";
|
2
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
3
|
+
if (value !== null && value !== void 0) {
|
4
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
5
|
+
var dispose;
|
6
|
+
if (async) {
|
7
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
8
|
+
dispose = value[Symbol.asyncDispose];
|
9
|
+
}
|
10
|
+
if (dispose === void 0) {
|
11
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
12
|
+
dispose = value[Symbol.dispose];
|
13
|
+
}
|
14
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
15
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
16
|
+
}
|
17
|
+
else if (async) {
|
18
|
+
env.stack.push({ async: true });
|
19
|
+
}
|
20
|
+
return value;
|
21
|
+
};
|
22
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
23
|
+
return function (env) {
|
24
|
+
function fail(e) {
|
25
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
26
|
+
env.hasError = true;
|
27
|
+
}
|
28
|
+
function next() {
|
29
|
+
while (env.stack.length) {
|
30
|
+
var rec = env.stack.pop();
|
31
|
+
try {
|
32
|
+
var result = rec.dispose && rec.dispose.call(rec.value);
|
33
|
+
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
34
|
+
}
|
35
|
+
catch (e) {
|
36
|
+
fail(e);
|
37
|
+
}
|
38
|
+
}
|
39
|
+
if (env.hasError) throw env.error;
|
40
|
+
}
|
41
|
+
return next();
|
42
|
+
};
|
43
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
44
|
+
var e = new Error(message);
|
45
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
46
|
+
});
|
2
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
48
|
exports.SessionGetter = void 0;
|
4
49
|
const simple_store_1 = require("@atproto-labs/simple-store");
|
50
|
+
const token_invalid_error_js_1 = require("./errors/token-invalid-error.js");
|
51
|
+
const token_refresh_error_js_1 = require("./errors/token-refresh-error.js");
|
52
|
+
const token_revoked_error_js_1 = require("./errors/token-revoked-error.js");
|
5
53
|
const oauth_response_error_js_1 = require("./oauth-response-error.js");
|
6
|
-
const refresh_error_js_1 = require("./refresh-error.js");
|
7
54
|
const util_js_1 = require("./util.js");
|
8
55
|
/**
|
9
56
|
* There are several advantages to wrapping the sessionStore in a (single)
|
@@ -17,23 +64,26 @@ class SessionGetter extends simple_store_1.CachedGetter {
|
|
17
64
|
super(async (sub, options, storedSession) => {
|
18
65
|
// There needs to be a previous session to be able to refresh. If
|
19
66
|
// storedSession is undefined, it means that the store does not contain
|
20
|
-
// a session for the given sub.
|
21
|
-
// value being cleared in another process (e.g. another tab), we will
|
22
|
-
// give a chance to the process running this code to detect that the
|
23
|
-
// session was revoked. This should allow processes not implementing a
|
24
|
-
// subscribe/notify between instances to still be "notified" that the
|
25
|
-
// session was revoked.
|
67
|
+
// a session for the given sub.
|
26
68
|
if (storedSession === undefined) {
|
27
|
-
// Because the session is not in the store,
|
28
|
-
//
|
29
|
-
//
|
30
|
-
//
|
31
|
-
|
32
|
-
|
69
|
+
// Because the session is not in the store, this.delStored() method
|
70
|
+
// will not be called by the CachedGetter class (because there is
|
71
|
+
// nothing to delete). This would typically happen if there is no
|
72
|
+
// synchronization mechanism between instances of this class. Let's
|
73
|
+
// make sure an event is dispatched here if this occurs.
|
74
|
+
const msg = 'The session was deleted by another process';
|
75
|
+
const cause = new token_refresh_error_js_1.TokenRefreshError(sub, msg);
|
76
|
+
this.dispatchEvent('deleted', { sub, cause });
|
77
|
+
throw cause;
|
33
78
|
}
|
79
|
+
// From this point forward, throwing a TokenRefreshError will result in
|
80
|
+
// this.delStored() being called, resulting in an event being
|
81
|
+
// dispatched, even if the session was removed from the store through a
|
82
|
+
// concurrent access (which, normally, should not happen if a proper
|
83
|
+
// runtime lock was provided).
|
34
84
|
if (sub !== storedSession.tokenSet.sub) {
|
35
85
|
// Fool-proofing (e.g. against invalid session storage)
|
36
|
-
throw new
|
86
|
+
throw new token_refresh_error_js_1.TokenRefreshError(sub, 'Stored session sub mismatch');
|
37
87
|
}
|
38
88
|
// Since refresh tokens can only be used once, we might run into
|
39
89
|
// concurrency issues if multiple tabs/instances are trying to refresh
|
@@ -48,15 +98,24 @@ class SessionGetter extends simple_store_1.CachedGetter {
|
|
48
98
|
// refreshed the token.
|
49
99
|
const { tokenSet, dpopKey } = storedSession;
|
50
100
|
const server = await serverFactory.fromIssuer(tokenSet.iss, dpopKey);
|
51
|
-
//
|
52
|
-
//
|
53
|
-
//
|
54
|
-
//
|
55
|
-
//
|
101
|
+
// Because refresh tokens can only be used once, we must not use the
|
102
|
+
// "signal" to abort the refresh, or throw any abort error beyond this
|
103
|
+
// point. Any thrown error beyond this point will prevent the
|
104
|
+
// SessionGetter from obtaining, and storing, the new token set,
|
105
|
+
// effectively rendering the currently saved session unusable.
|
56
106
|
options?.signal?.throwIfAborted();
|
57
|
-
|
58
|
-
.refresh(tokenSet)
|
59
|
-
|
107
|
+
try {
|
108
|
+
const newTokenSet = await server.refresh(tokenSet);
|
109
|
+
if (sub !== newTokenSet.sub) {
|
110
|
+
// The server returned another sub. Was the tokenSet manipulated?
|
111
|
+
throw new token_refresh_error_js_1.TokenRefreshError(sub, 'Token set sub mismatch');
|
112
|
+
}
|
113
|
+
return { dpopKey, tokenSet: newTokenSet };
|
114
|
+
}
|
115
|
+
catch (cause) {
|
116
|
+
// If the refresh token is invalid, let's try to recover from
|
117
|
+
// concurrency issues, or make sure the session is deleted by throwing
|
118
|
+
// a TokenRefreshError.
|
60
119
|
if (cause instanceof oauth_response_error_js_1.OAuthResponseError &&
|
61
120
|
cause.status === 400 &&
|
62
121
|
cause.error === 'invalid_grant') {
|
@@ -64,37 +123,34 @@ class SessionGetter extends simple_store_1.CachedGetter {
|
|
64
123
|
// wait for a short time to give the other concurrent instances a
|
65
124
|
// chance to finish their refreshing of the token. If a concurrent
|
66
125
|
// refresh did occur, we will pretend that this one succeeded.
|
67
|
-
if (!runtime.
|
126
|
+
if (!runtime.hasImplementationLock) {
|
68
127
|
await new Promise((r) => setTimeout(r, 1000));
|
69
128
|
const stored = await this.getStored(sub);
|
70
129
|
if (stored === undefined) {
|
130
|
+
// A concurrent refresh occurred and caused the session to be
|
131
|
+
// deleted (for a reason we can't know at this point).
|
71
132
|
// Using a distinct error message mainly for debugging
|
72
|
-
// purposes
|
73
|
-
|
74
|
-
|
133
|
+
// purposes. Also, throwing a TokenRefreshError to trigger
|
134
|
+
// deletion through the deleteOnError callback.
|
135
|
+
const msg = 'The session was deleted by another process';
|
136
|
+
throw new token_refresh_error_js_1.TokenRefreshError(sub, msg, { cause });
|
75
137
|
}
|
76
138
|
else if (stored.tokenSet.access_token !== tokenSet.access_token ||
|
77
139
|
stored.tokenSet.refresh_token !== tokenSet.refresh_token) {
|
78
140
|
// A concurrent refresh occurred. Pretend this one succeeded.
|
79
|
-
return stored.tokenSet;
|
141
|
+
return { dpopKey, tokenSet: stored.tokenSet };
|
80
142
|
}
|
81
143
|
else {
|
82
144
|
// There were no concurrent refresh. The token is (likely)
|
83
145
|
// simply no longer valid.
|
84
146
|
}
|
85
147
|
}
|
86
|
-
//
|
87
|
-
// deleteOnError callback.
|
148
|
+
// Make sure the session gets deleted from the store
|
88
149
|
const msg = cause.errorDescription ?? 'The session was revoked';
|
89
|
-
throw new
|
150
|
+
throw new token_refresh_error_js_1.TokenRefreshError(sub, msg, { cause });
|
90
151
|
}
|
91
152
|
throw cause;
|
92
|
-
});
|
93
|
-
if (sub !== newTokenSet.sub) {
|
94
|
-
// The server returned another sub. Was the tokenSet manipulated?
|
95
|
-
throw new refresh_error_js_1.RefreshError(sub, 'Token set sub mismatch');
|
96
153
|
}
|
97
|
-
return { ...storedSession, tokenSet: newTokenSet };
|
98
154
|
}, sessionStore, {
|
99
155
|
isStale: (sub, { tokenSet }) => {
|
100
156
|
return (tokenSet.expires_at != null &&
|
@@ -109,9 +165,11 @@ class SessionGetter extends simple_store_1.CachedGetter {
|
|
109
165
|
await server.revoke(tokenSet.refresh_token ?? tokenSet.access_token);
|
110
166
|
throw err;
|
111
167
|
},
|
112
|
-
deleteOnError: async (err) =>
|
113
|
-
|
114
|
-
|
168
|
+
deleteOnError: async (err) =>
|
169
|
+
// Optimization: More likely to happen first
|
170
|
+
err instanceof token_refresh_error_js_1.TokenRefreshError ||
|
171
|
+
err instanceof token_revoked_error_js_1.TokenRevokedError ||
|
172
|
+
err instanceof token_invalid_error_js_1.TokenInvalidError,
|
115
173
|
});
|
116
174
|
Object.defineProperty(this, "runtime", {
|
117
175
|
enumerable: true,
|
@@ -119,6 +177,29 @@ class SessionGetter extends simple_store_1.CachedGetter {
|
|
119
177
|
writable: true,
|
120
178
|
value: runtime
|
121
179
|
});
|
180
|
+
Object.defineProperty(this, "eventTarget", {
|
181
|
+
enumerable: true,
|
182
|
+
configurable: true,
|
183
|
+
writable: true,
|
184
|
+
value: new util_js_1.CustomEventTarget()
|
185
|
+
});
|
186
|
+
}
|
187
|
+
addEventListener(type, callback, options) {
|
188
|
+
this.eventTarget.addEventListener(type, callback, options);
|
189
|
+
}
|
190
|
+
removeEventListener(type, callback, options) {
|
191
|
+
this.eventTarget.removeEventListener(type, callback, options);
|
192
|
+
}
|
193
|
+
dispatchEvent(type, detail) {
|
194
|
+
return this.eventTarget.dispatchCustomEvent(type, detail);
|
195
|
+
}
|
196
|
+
async setStored(sub, session) {
|
197
|
+
await super.setStored(sub, session);
|
198
|
+
this.dispatchEvent('updated', { sub, ...session });
|
199
|
+
}
|
200
|
+
async delStored(sub, cause) {
|
201
|
+
await super.delStored(sub, cause);
|
202
|
+
this.dispatchEvent('deleted', { sub, cause });
|
122
203
|
}
|
123
204
|
/**
|
124
205
|
* @param refresh When `true`, the credentials will be refreshed even if they
|
@@ -138,10 +219,21 @@ class SessionGetter extends simple_store_1.CachedGetter {
|
|
138
219
|
return session;
|
139
220
|
}
|
140
221
|
async get(sub, options) {
|
141
|
-
return this.runtime.
|
142
|
-
|
143
|
-
|
144
|
-
|
222
|
+
return this.runtime.usingLock(`@atproto-oauth-client-${sub}`, async () => {
|
223
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
224
|
+
try {
|
225
|
+
// Make sure, even if there is no signal in the options, that the request
|
226
|
+
// will be cancelled after at most 30 seconds.
|
227
|
+
const signal = __addDisposableResource(env_1, (0, util_js_1.timeoutSignal)(30e3, options), false);
|
228
|
+
return await super.get(sub, { ...options, signal });
|
229
|
+
}
|
230
|
+
catch (e_1) {
|
231
|
+
env_1.error = e_1;
|
232
|
+
env_1.hasError = true;
|
233
|
+
}
|
234
|
+
finally {
|
235
|
+
__disposeResources(env_1);
|
236
|
+
}
|
145
237
|
});
|
146
238
|
}
|
147
239
|
}
|