@pixelume/sdk 0.1.1 → 0.2.0
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 +20 -1
- package/README.md +133 -106
- package/dist/contracts/index.d.ts +17 -0
- package/dist/contracts/index.js +36 -0
- package/dist/contracts/index.js.map +1 -1
- package/dist/core/PixelumeClient.d.ts +10 -0
- package/dist/core/PixelumeClient.js +18 -0
- package/dist/core/PixelumeClient.js.map +1 -1
- package/dist/core/config.d.ts +9 -0
- package/dist/core/config.js +70 -2
- package/dist/core/config.js.map +1 -1
- package/dist/core/errors.d.ts +11 -2
- package/dist/core/errors.js +9 -0
- package/dist/core/errors.js.map +1 -1
- package/dist/core/types.d.ts +37 -0
- package/dist/core/types.js.map +1 -1
- package/dist/http/HttpClient.js +8 -0
- package/dist/http/HttpClient.js.map +1 -1
- package/dist/http/types.d.ts +2 -0
- package/dist/http/types.js.map +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/modules/auth/AuthModule.d.ts +55 -0
- package/dist/modules/auth/AuthModule.js +424 -0
- package/dist/modules/auth/AuthModule.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
import { parseEmptyResponse, parseOAuthTokenResponse, parsePlayerEnvelope, } from '../../contracts/index.js';
|
|
2
|
+
import { PixelumeAuthError, PixelumeConfigError, PixelumeHttpError, isPixelumeError, } from '../../core/errors.js';
|
|
3
|
+
const AUTHORIZATION_REQUEST_TTL_MS = 10 * 60_000;
|
|
4
|
+
const TOKEN_EXPIRY_SKEW_MS = 5_000;
|
|
5
|
+
const CALLBACK_PARAMETERS = ['code', 'state', 'error', 'error_description'];
|
|
6
|
+
export class AuthModule {
|
|
7
|
+
#http;
|
|
8
|
+
#config;
|
|
9
|
+
#listeners = new Set();
|
|
10
|
+
#state = Object.freeze({ status: 'uninitialized', player: null });
|
|
11
|
+
#token = null;
|
|
12
|
+
#initializePromise = null;
|
|
13
|
+
#loginPromise = null;
|
|
14
|
+
#playerPromise = null;
|
|
15
|
+
#logoutPromise = null;
|
|
16
|
+
constructor(http, config) {
|
|
17
|
+
this.#http = http;
|
|
18
|
+
this.#config = config;
|
|
19
|
+
}
|
|
20
|
+
get state() {
|
|
21
|
+
return this.#state;
|
|
22
|
+
}
|
|
23
|
+
initialize() {
|
|
24
|
+
this.#initializePromise ??= this.#doInitialize();
|
|
25
|
+
return this.#initializePromise;
|
|
26
|
+
}
|
|
27
|
+
subscribe(listener) {
|
|
28
|
+
this.#listeners.add(listener);
|
|
29
|
+
return () => this.#listeners.delete(listener);
|
|
30
|
+
}
|
|
31
|
+
login(options = {}) {
|
|
32
|
+
const scope = options.scope;
|
|
33
|
+
if (scope !== undefined && scope !== 'profile') {
|
|
34
|
+
return Promise.reject(new PixelumeConfigError('Pixelume Auth supports only the "profile" scope'));
|
|
35
|
+
}
|
|
36
|
+
this.#loginPromise ??= this.#doLogin().finally(() => {
|
|
37
|
+
this.#loginPromise = null;
|
|
38
|
+
});
|
|
39
|
+
return this.#loginPromise;
|
|
40
|
+
}
|
|
41
|
+
getPlayer(options = {}) {
|
|
42
|
+
if (this.#token === null)
|
|
43
|
+
return Promise.resolve(null);
|
|
44
|
+
if (this.#token.expiresAt <= Date.now() + TOKEN_EXPIRY_SKEW_MS) {
|
|
45
|
+
this.#token = null;
|
|
46
|
+
this.#setState(anonymous('expired'));
|
|
47
|
+
return Promise.resolve(null);
|
|
48
|
+
}
|
|
49
|
+
this.#playerPromise ??= this.#fetchPlayer(options).finally(() => {
|
|
50
|
+
this.#playerPromise = null;
|
|
51
|
+
});
|
|
52
|
+
return this.#playerPromise;
|
|
53
|
+
}
|
|
54
|
+
logout(options = {}) {
|
|
55
|
+
this.#logoutPromise ??= this.#doLogout(options).finally(() => {
|
|
56
|
+
this.#logoutPromise = null;
|
|
57
|
+
});
|
|
58
|
+
return this.#logoutPromise;
|
|
59
|
+
}
|
|
60
|
+
async #doInitialize() {
|
|
61
|
+
try {
|
|
62
|
+
const browser = this.#browser();
|
|
63
|
+
const callback = this.#readCallback(browser.currentUrl());
|
|
64
|
+
if (callback !== null) {
|
|
65
|
+
await this.#handleCallback(browser, callback);
|
|
66
|
+
}
|
|
67
|
+
else if (this.#config.restoreSession && this.#readSessionHint(browser.sessionStorage)) {
|
|
68
|
+
this.#removeSessionHint(browser.sessionStorage);
|
|
69
|
+
await this.login();
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
this.#setState(anonymous('visitor'));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
const failure = isPixelumeError(error)
|
|
77
|
+
? error
|
|
78
|
+
: new PixelumeAuthError('browser_unavailable', { cause: error });
|
|
79
|
+
this.#setState(anonymous('error', failure));
|
|
80
|
+
}
|
|
81
|
+
return this.#state;
|
|
82
|
+
}
|
|
83
|
+
async #doLogin() {
|
|
84
|
+
const clientId = this.#requireClientId();
|
|
85
|
+
const redirectUri = this.#requireRedirectUri();
|
|
86
|
+
const browser = this.#browser();
|
|
87
|
+
let pending = this.#readPending(browser.sessionStorage);
|
|
88
|
+
if (pending === null || pending.redirectUri !== redirectUri || this.#isExpired(pending)) {
|
|
89
|
+
pending = {
|
|
90
|
+
version: 1,
|
|
91
|
+
state: randomBase64Url(browser.crypto),
|
|
92
|
+
verifier: randomBase64Url(browser.crypto),
|
|
93
|
+
redirectUri,
|
|
94
|
+
createdAt: Date.now(),
|
|
95
|
+
};
|
|
96
|
+
this.#writePending(browser.sessionStorage, pending);
|
|
97
|
+
}
|
|
98
|
+
const challenge = await sha256Base64Url(browser.crypto, pending.verifier);
|
|
99
|
+
const authorization = new URL('/v1/oauth/authorize', this.#config.apiUrl);
|
|
100
|
+
authorization.search = new URLSearchParams({
|
|
101
|
+
client_id: clientId,
|
|
102
|
+
redirect_uri: redirectUri,
|
|
103
|
+
response_type: 'code',
|
|
104
|
+
state: pending.state,
|
|
105
|
+
code_challenge: challenge,
|
|
106
|
+
code_challenge_method: 'S256',
|
|
107
|
+
scope: 'profile',
|
|
108
|
+
}).toString();
|
|
109
|
+
this.#setState(Object.freeze({ status: 'redirecting', player: null }));
|
|
110
|
+
try {
|
|
111
|
+
browser.navigate(authorization.toString());
|
|
112
|
+
}
|
|
113
|
+
catch (cause) {
|
|
114
|
+
this.#removePending(browser.sessionStorage);
|
|
115
|
+
throw new PixelumeAuthError('browser_unavailable', { cause });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async #handleCallback(browser, callback) {
|
|
119
|
+
const pending = this.#readPending(browser.sessionStorage);
|
|
120
|
+
this.#removePending(browser.sessionStorage);
|
|
121
|
+
this.#cleanCallback(browser, callback.url);
|
|
122
|
+
if (callback.invalid)
|
|
123
|
+
throw new PixelumeAuthError('invalid_callback');
|
|
124
|
+
if (pending === null || this.#isExpired(pending)) {
|
|
125
|
+
this.#removeSessionHint(browser.sessionStorage);
|
|
126
|
+
throw new PixelumeAuthError(pending === null ? 'invalid_callback' : 'authorization_expired');
|
|
127
|
+
}
|
|
128
|
+
if (pending.redirectUri !== this.#config.redirectUri ||
|
|
129
|
+
(callback.code !== null && !/^[A-Za-z0-9_-]{43,128}$/u.test(callback.code))) {
|
|
130
|
+
throw new PixelumeAuthError('invalid_callback');
|
|
131
|
+
}
|
|
132
|
+
const returnedState = singleParameter(callback.url, 'state');
|
|
133
|
+
if (returnedState === null || returnedState !== pending.state) {
|
|
134
|
+
this.#removeSessionHint(browser.sessionStorage);
|
|
135
|
+
throw new PixelumeAuthError('state_mismatch');
|
|
136
|
+
}
|
|
137
|
+
if (callback.error !== null) {
|
|
138
|
+
this.#removeSessionHint(browser.sessionStorage);
|
|
139
|
+
if (callback.error === 'access_denied') {
|
|
140
|
+
this.#setState(anonymous('cancelled'));
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
throw new PixelumeAuthError('invalid_callback');
|
|
144
|
+
}
|
|
145
|
+
if (callback.code === null)
|
|
146
|
+
throw new PixelumeAuthError('invalid_callback');
|
|
147
|
+
this.#setState(Object.freeze({ status: 'exchanging', player: null }));
|
|
148
|
+
const response = await this.#http.request({
|
|
149
|
+
method: 'POST',
|
|
150
|
+
path: '/v1/oauth/token',
|
|
151
|
+
credentials: 'omit',
|
|
152
|
+
form: {
|
|
153
|
+
grant_type: 'authorization_code',
|
|
154
|
+
code: callback.code,
|
|
155
|
+
client_id: this.#requireClientId(),
|
|
156
|
+
redirect_uri: pending.redirectUri,
|
|
157
|
+
code_verifier: pending.verifier,
|
|
158
|
+
},
|
|
159
|
+
parse: parseOAuthTokenResponse,
|
|
160
|
+
});
|
|
161
|
+
this.#token = {
|
|
162
|
+
value: response.data.access_token,
|
|
163
|
+
expiresAt: Date.now() + response.data.expires_in * 1_000,
|
|
164
|
+
};
|
|
165
|
+
const player = await this.getPlayer();
|
|
166
|
+
if (player !== null)
|
|
167
|
+
this.#writeSessionHint(browser.sessionStorage);
|
|
168
|
+
}
|
|
169
|
+
async #fetchPlayer(options) {
|
|
170
|
+
const token = this.#token;
|
|
171
|
+
if (token === null)
|
|
172
|
+
return null;
|
|
173
|
+
try {
|
|
174
|
+
const response = await this.#http.request({
|
|
175
|
+
method: 'GET',
|
|
176
|
+
path: '/v1/oauth/userinfo',
|
|
177
|
+
credentials: 'omit',
|
|
178
|
+
headers: { authorization: `Bearer ${token.value}` },
|
|
179
|
+
signal: options.signal,
|
|
180
|
+
timeoutMs: options.timeoutMs,
|
|
181
|
+
parse: parsePlayerEnvelope,
|
|
182
|
+
});
|
|
183
|
+
const player = Object.freeze({ ...response.data.player });
|
|
184
|
+
this.#setState(Object.freeze({ status: 'authenticated', player }));
|
|
185
|
+
return player;
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
if (error instanceof PixelumeHttpError && error.status === 401) {
|
|
189
|
+
this.#token = null;
|
|
190
|
+
this.#setState(anonymous('expired'));
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
throw error;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
async #doLogout(options) {
|
|
197
|
+
const token = this.#token;
|
|
198
|
+
this.#token = null;
|
|
199
|
+
const browser = this.#optionalBrowser();
|
|
200
|
+
if (browser) {
|
|
201
|
+
this.#removePending(browser.sessionStorage);
|
|
202
|
+
this.#removeSessionHint(browser.sessionStorage);
|
|
203
|
+
}
|
|
204
|
+
this.#setState(anonymous('logged_out'));
|
|
205
|
+
if (token === null)
|
|
206
|
+
return;
|
|
207
|
+
await this.#http.request({
|
|
208
|
+
method: 'POST',
|
|
209
|
+
path: '/v1/oauth/revoke',
|
|
210
|
+
credentials: 'omit',
|
|
211
|
+
form: { token: token.value, token_type_hint: 'access_token' },
|
|
212
|
+
signal: options.signal,
|
|
213
|
+
timeoutMs: options.timeoutMs,
|
|
214
|
+
parse: parseEmptyResponse,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
#readCallback(value) {
|
|
218
|
+
const redirectUri = this.#config.redirectUri;
|
|
219
|
+
if (redirectUri === null)
|
|
220
|
+
return null;
|
|
221
|
+
const current = new URL(value);
|
|
222
|
+
const expected = new URL(redirectUri);
|
|
223
|
+
if (current.origin !== expected.origin || current.pathname !== expected.pathname)
|
|
224
|
+
return null;
|
|
225
|
+
const hasCallbackParameter = CALLBACK_PARAMETERS.some((key) => current.searchParams.has(key));
|
|
226
|
+
if (!hasCallbackParameter)
|
|
227
|
+
return null;
|
|
228
|
+
const code = singleParameter(current, 'code');
|
|
229
|
+
const error = singleParameter(current, 'error');
|
|
230
|
+
return {
|
|
231
|
+
url: current,
|
|
232
|
+
code,
|
|
233
|
+
error,
|
|
234
|
+
invalid: !sameCallbackBase(current, expected) || (code === null) === (error === null),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
#cleanCallback(browser, url) {
|
|
238
|
+
const clean = new URL(url.toString());
|
|
239
|
+
for (const key of CALLBACK_PARAMETERS)
|
|
240
|
+
clean.searchParams.delete(key);
|
|
241
|
+
browser.replaceUrl(`${clean.pathname}${clean.search}${clean.hash}`);
|
|
242
|
+
}
|
|
243
|
+
#browser() {
|
|
244
|
+
const browser = this.#optionalBrowser();
|
|
245
|
+
if (!browser)
|
|
246
|
+
throw new PixelumeAuthError('browser_unavailable');
|
|
247
|
+
if (typeof browser.crypto.getRandomValues !== 'function' ||
|
|
248
|
+
typeof browser.crypto.subtle.digest !== 'function') {
|
|
249
|
+
throw new PixelumeAuthError('crypto_unavailable');
|
|
250
|
+
}
|
|
251
|
+
return browser;
|
|
252
|
+
}
|
|
253
|
+
#optionalBrowser() {
|
|
254
|
+
if (this.#config.browser)
|
|
255
|
+
return this.#config.browser;
|
|
256
|
+
try {
|
|
257
|
+
if (typeof globalThis.location === 'undefined' ||
|
|
258
|
+
typeof globalThis.history === 'undefined' ||
|
|
259
|
+
typeof globalThis.sessionStorage === 'undefined' ||
|
|
260
|
+
typeof globalThis.crypto === 'undefined') {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
currentUrl: () => globalThis.location.href,
|
|
265
|
+
navigate: (url) => {
|
|
266
|
+
globalThis.location.assign(url);
|
|
267
|
+
},
|
|
268
|
+
replaceUrl: (url) => {
|
|
269
|
+
globalThis.history.replaceState(globalThis.history.state, '', url);
|
|
270
|
+
},
|
|
271
|
+
sessionStorage: globalThis.sessionStorage,
|
|
272
|
+
crypto: globalThis.crypto,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
catch (cause) {
|
|
276
|
+
throw new PixelumeAuthError('storage_unavailable', { cause });
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
#requireClientId() {
|
|
280
|
+
if (this.#config.clientId === null) {
|
|
281
|
+
throw new PixelumeConfigError('Pixelume Auth requires clientId or gameId');
|
|
282
|
+
}
|
|
283
|
+
return this.#config.clientId;
|
|
284
|
+
}
|
|
285
|
+
#requireRedirectUri() {
|
|
286
|
+
if (this.#config.redirectUri === null) {
|
|
287
|
+
throw new PixelumeAuthError('browser_unavailable');
|
|
288
|
+
}
|
|
289
|
+
return this.#config.redirectUri;
|
|
290
|
+
}
|
|
291
|
+
#pendingKey() {
|
|
292
|
+
return `pixelume.oauth.pending.${this.#config.clientId ?? 'unconfigured'}`;
|
|
293
|
+
}
|
|
294
|
+
#hintKey() {
|
|
295
|
+
return `pixelume.oauth.session.${this.#config.clientId ?? 'unconfigured'}`;
|
|
296
|
+
}
|
|
297
|
+
#readPending(storage) {
|
|
298
|
+
try {
|
|
299
|
+
const raw = storage.getItem(this.#pendingKey());
|
|
300
|
+
if (raw === null)
|
|
301
|
+
return null;
|
|
302
|
+
const value = JSON.parse(raw);
|
|
303
|
+
if (!isPendingAuthorization(value)) {
|
|
304
|
+
storage.removeItem(this.#pendingKey());
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
return value;
|
|
308
|
+
}
|
|
309
|
+
catch (cause) {
|
|
310
|
+
throw new PixelumeAuthError('storage_unavailable', { cause });
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
#writePending(storage, pending) {
|
|
314
|
+
try {
|
|
315
|
+
storage.setItem(this.#pendingKey(), JSON.stringify(pending));
|
|
316
|
+
}
|
|
317
|
+
catch (cause) {
|
|
318
|
+
throw new PixelumeAuthError('storage_unavailable', { cause });
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
#removePending(storage) {
|
|
322
|
+
try {
|
|
323
|
+
storage.removeItem(this.#pendingKey());
|
|
324
|
+
}
|
|
325
|
+
catch (cause) {
|
|
326
|
+
throw new PixelumeAuthError('storage_unavailable', { cause });
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
#readSessionHint(storage) {
|
|
330
|
+
try {
|
|
331
|
+
return storage.getItem(this.#hintKey()) === '1';
|
|
332
|
+
}
|
|
333
|
+
catch (cause) {
|
|
334
|
+
throw new PixelumeAuthError('storage_unavailable', { cause });
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
#writeSessionHint(storage) {
|
|
338
|
+
try {
|
|
339
|
+
storage.setItem(this.#hintKey(), '1');
|
|
340
|
+
}
|
|
341
|
+
catch (cause) {
|
|
342
|
+
throw new PixelumeAuthError('storage_unavailable', { cause });
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
#removeSessionHint(storage) {
|
|
346
|
+
try {
|
|
347
|
+
storage.removeItem(this.#hintKey());
|
|
348
|
+
}
|
|
349
|
+
catch (cause) {
|
|
350
|
+
throw new PixelumeAuthError('storage_unavailable', { cause });
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
#isExpired(pending) {
|
|
354
|
+
const now = Date.now();
|
|
355
|
+
return (pending.createdAt > now + 60_000 || pending.createdAt + AUTHORIZATION_REQUEST_TTL_MS < now);
|
|
356
|
+
}
|
|
357
|
+
#setState(state) {
|
|
358
|
+
const previous = this.#state;
|
|
359
|
+
if (sameState(previous, state))
|
|
360
|
+
return;
|
|
361
|
+
this.#state = state;
|
|
362
|
+
for (const listener of [...this.#listeners])
|
|
363
|
+
listener(state, previous);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
function anonymous(reason, error = null) {
|
|
367
|
+
return Object.freeze({ status: 'anonymous', player: null, reason, error });
|
|
368
|
+
}
|
|
369
|
+
function isPendingAuthorization(value) {
|
|
370
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
371
|
+
return false;
|
|
372
|
+
const pending = value;
|
|
373
|
+
return (pending.version === 1 &&
|
|
374
|
+
typeof pending.state === 'string' &&
|
|
375
|
+
/^[A-Za-z0-9_-]{43}$/u.test(pending.state) &&
|
|
376
|
+
typeof pending.verifier === 'string' &&
|
|
377
|
+
/^[A-Za-z0-9_-]{43}$/u.test(pending.verifier) &&
|
|
378
|
+
typeof pending.redirectUri === 'string' &&
|
|
379
|
+
typeof pending.createdAt === 'number' &&
|
|
380
|
+
Number.isFinite(pending.createdAt));
|
|
381
|
+
}
|
|
382
|
+
function sameCallbackBase(current, expected) {
|
|
383
|
+
if (current.origin !== expected.origin || current.pathname !== expected.pathname)
|
|
384
|
+
return false;
|
|
385
|
+
const currentBase = new URL(current.toString());
|
|
386
|
+
for (const key of CALLBACK_PARAMETERS)
|
|
387
|
+
currentBase.searchParams.delete(key);
|
|
388
|
+
currentBase.hash = '';
|
|
389
|
+
const expectedBase = new URL(expected.toString());
|
|
390
|
+
expectedBase.hash = '';
|
|
391
|
+
return currentBase.toString() === expectedBase.toString();
|
|
392
|
+
}
|
|
393
|
+
function singleParameter(url, name) {
|
|
394
|
+
const values = url.searchParams.getAll(name);
|
|
395
|
+
if (values.length !== 1 || values[0] === '')
|
|
396
|
+
return null;
|
|
397
|
+
return values[0] ?? null;
|
|
398
|
+
}
|
|
399
|
+
function randomBase64Url(crypto) {
|
|
400
|
+
const bytes = crypto.getRandomValues(new Uint8Array(32));
|
|
401
|
+
return bytesToBase64Url(bytes);
|
|
402
|
+
}
|
|
403
|
+
async function sha256Base64Url(crypto, value) {
|
|
404
|
+
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(value));
|
|
405
|
+
return bytesToBase64Url(new Uint8Array(digest));
|
|
406
|
+
}
|
|
407
|
+
function bytesToBase64Url(bytes) {
|
|
408
|
+
let binary = '';
|
|
409
|
+
for (const byte of bytes)
|
|
410
|
+
binary += String.fromCharCode(byte);
|
|
411
|
+
return btoa(binary).replaceAll('+', '-').replaceAll('/', '_').replace(/=+$/u, '');
|
|
412
|
+
}
|
|
413
|
+
function sameState(left, right) {
|
|
414
|
+
if (left.status !== right.status)
|
|
415
|
+
return false;
|
|
416
|
+
if (left.status === 'authenticated' && right.status === 'authenticated') {
|
|
417
|
+
return left.player === right.player;
|
|
418
|
+
}
|
|
419
|
+
if (left.status === 'anonymous' && right.status === 'anonymous') {
|
|
420
|
+
return left.reason === right.reason && left.error === right.error;
|
|
421
|
+
}
|
|
422
|
+
return true;
|
|
423
|
+
}
|
|
424
|
+
//# sourceMappingURL=AuthModule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthModule.js","sourceRoot":"","sources":["../../../src/modules/auth/AuthModule.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n parseEmptyResponse,\n parseOAuthTokenResponse,\n parsePlayerEnvelope,\n} from '../../contracts/index.js';\nimport {\n PixelumeAuthError,\n PixelumeConfigError,\n PixelumeHttpError,\n isPixelumeError,\n type PixelumeError,\n} from '../../core/errors.js';\nimport type {\n PixelumeBrowserAdapter,\n PixelumeRequestOptions,\n PixelumeSessionStorage,\n} from '../../core/types.js';\nimport type { ResolvedConfig } from '../../core/config.js';\nimport type { HttpClient } from '../../http/HttpClient.js';\n\nconst AUTHORIZATION_REQUEST_TTL_MS = 10 * 60_000;\nconst TOKEN_EXPIRY_SKEW_MS = 5_000;\nconst CALLBACK_PARAMETERS = ['code', 'state', 'error', 'error_description'] as const;\n\nexport interface PixelumePlayer {\n readonly id: string;\n readonly displayName: string;\n readonly avatarUrl: string | null;\n}\n\nexport type PixelumeAnonymousReason = 'visitor' | 'cancelled' | 'expired' | 'logged_out' | 'error';\n\nexport type PixelumeAuthState =\n | { readonly status: 'uninitialized'; readonly player: null }\n | { readonly status: 'redirecting'; readonly player: null }\n | { readonly status: 'exchanging'; readonly player: null }\n | {\n readonly status: 'anonymous';\n readonly player: null;\n readonly reason: PixelumeAnonymousReason;\n readonly error: PixelumeError | null;\n }\n | { readonly status: 'authenticated'; readonly player: PixelumePlayer };\n\nexport type PixelumeAuthListener = (state: PixelumeAuthState, previous: PixelumeAuthState) => void;\n\nexport interface PixelumeLoginOptions {\n /** OAuth scope. The current API accepts only `profile`. */\n readonly scope?: 'profile';\n}\n\nexport interface PixelumeAuthApi {\n /** Current synchronous authentication state. */\n readonly state: PixelumeAuthState;\n /** Starts a top-level redirect to the API authorization endpoint. */\n login(options?: PixelumeLoginOptions): Promise<void>;\n /** Returns the current player, revalidating the memory-only access token with the API. */\n getPlayer(options?: PixelumeRequestOptions): Promise<PixelumePlayer | null>;\n /** Revokes this game's access token and clears local authentication state. */\n logout(options?: PixelumeRequestOptions): Promise<void>;\n /** Subscribes to state changes. The returned function removes the listener. */\n subscribe(listener: PixelumeAuthListener): () => void;\n}\n\ninterface PendingAuthorization {\n readonly version: 1;\n readonly state: string;\n readonly verifier: string;\n readonly redirectUri: string;\n readonly createdAt: number;\n}\n\ninterface AccessToken {\n readonly value: string;\n readonly expiresAt: number;\n}\n\nexport class AuthModule implements PixelumeAuthApi {\n readonly #http: HttpClient;\n readonly #config: ResolvedConfig;\n readonly #listeners = new Set<PixelumeAuthListener>();\n #state: PixelumeAuthState = Object.freeze({ status: 'uninitialized', player: null });\n #token: AccessToken | null = null;\n #initializePromise: Promise<PixelumeAuthState> | null = null;\n #loginPromise: Promise<void> | null = null;\n #playerPromise: Promise<PixelumePlayer | null> | null = null;\n #logoutPromise: Promise<void> | null = null;\n\n constructor(http: HttpClient, config: ResolvedConfig) {\n this.#http = http;\n this.#config = config;\n }\n\n get state(): PixelumeAuthState {\n return this.#state;\n }\n\n initialize(): Promise<PixelumeAuthState> {\n this.#initializePromise ??= this.#doInitialize();\n return this.#initializePromise;\n }\n\n subscribe(listener: PixelumeAuthListener): () => void {\n this.#listeners.add(listener);\n return () => this.#listeners.delete(listener);\n }\n\n login(options: PixelumeLoginOptions = {}): Promise<void> {\n const scope: unknown = options.scope;\n if (scope !== undefined && scope !== 'profile') {\n return Promise.reject(\n new PixelumeConfigError('Pixelume Auth supports only the \"profile\" scope'),\n );\n }\n this.#loginPromise ??= this.#doLogin().finally(() => {\n this.#loginPromise = null;\n });\n return this.#loginPromise;\n }\n\n getPlayer(options: PixelumeRequestOptions = {}): Promise<PixelumePlayer | null> {\n if (this.#token === null) return Promise.resolve(null);\n if (this.#token.expiresAt <= Date.now() + TOKEN_EXPIRY_SKEW_MS) {\n this.#token = null;\n this.#setState(anonymous('expired'));\n return Promise.resolve(null);\n }\n this.#playerPromise ??= this.#fetchPlayer(options).finally(() => {\n this.#playerPromise = null;\n });\n return this.#playerPromise;\n }\n\n logout(options: PixelumeRequestOptions = {}): Promise<void> {\n this.#logoutPromise ??= this.#doLogout(options).finally(() => {\n this.#logoutPromise = null;\n });\n return this.#logoutPromise;\n }\n\n async #doInitialize(): Promise<PixelumeAuthState> {\n try {\n const browser = this.#browser();\n const callback = this.#readCallback(browser.currentUrl());\n if (callback !== null) {\n await this.#handleCallback(browser, callback);\n } else if (this.#config.restoreSession && this.#readSessionHint(browser.sessionStorage)) {\n this.#removeSessionHint(browser.sessionStorage);\n await this.login();\n } else {\n this.#setState(anonymous('visitor'));\n }\n } catch (error) {\n const failure = isPixelumeError(error)\n ? error\n : new PixelumeAuthError('browser_unavailable', { cause: error });\n this.#setState(anonymous('error', failure));\n }\n return this.#state;\n }\n\n async #doLogin(): Promise<void> {\n const clientId = this.#requireClientId();\n const redirectUri = this.#requireRedirectUri();\n const browser = this.#browser();\n let pending = this.#readPending(browser.sessionStorage);\n if (pending === null || pending.redirectUri !== redirectUri || this.#isExpired(pending)) {\n pending = {\n version: 1,\n state: randomBase64Url(browser.crypto),\n verifier: randomBase64Url(browser.crypto),\n redirectUri,\n createdAt: Date.now(),\n };\n this.#writePending(browser.sessionStorage, pending);\n }\n const challenge = await sha256Base64Url(browser.crypto, pending.verifier);\n const authorization = new URL('/v1/oauth/authorize', this.#config.apiUrl);\n authorization.search = new URLSearchParams({\n client_id: clientId,\n redirect_uri: redirectUri,\n response_type: 'code',\n state: pending.state,\n code_challenge: challenge,\n code_challenge_method: 'S256',\n scope: 'profile',\n }).toString();\n this.#setState(Object.freeze({ status: 'redirecting', player: null }));\n try {\n browser.navigate(authorization.toString());\n } catch (cause) {\n this.#removePending(browser.sessionStorage);\n throw new PixelumeAuthError('browser_unavailable', { cause });\n }\n }\n\n async #handleCallback(\n browser: PixelumeBrowserAdapter,\n callback: {\n readonly url: URL;\n readonly code: string | null;\n readonly error: string | null;\n readonly invalid: boolean;\n },\n ): Promise<void> {\n const pending = this.#readPending(browser.sessionStorage);\n this.#removePending(browser.sessionStorage);\n this.#cleanCallback(browser, callback.url);\n\n if (callback.invalid) throw new PixelumeAuthError('invalid_callback');\n if (pending === null || this.#isExpired(pending)) {\n this.#removeSessionHint(browser.sessionStorage);\n throw new PixelumeAuthError(pending === null ? 'invalid_callback' : 'authorization_expired');\n }\n if (\n pending.redirectUri !== this.#config.redirectUri ||\n (callback.code !== null && !/^[A-Za-z0-9_-]{43,128}$/u.test(callback.code))\n ) {\n throw new PixelumeAuthError('invalid_callback');\n }\n const returnedState = singleParameter(callback.url, 'state');\n if (returnedState === null || returnedState !== pending.state) {\n this.#removeSessionHint(browser.sessionStorage);\n throw new PixelumeAuthError('state_mismatch');\n }\n if (callback.error !== null) {\n this.#removeSessionHint(browser.sessionStorage);\n if (callback.error === 'access_denied') {\n this.#setState(anonymous('cancelled'));\n return;\n }\n throw new PixelumeAuthError('invalid_callback');\n }\n if (callback.code === null) throw new PixelumeAuthError('invalid_callback');\n\n this.#setState(Object.freeze({ status: 'exchanging', player: null }));\n const response = await this.#http.request({\n method: 'POST',\n path: '/v1/oauth/token',\n credentials: 'omit',\n form: {\n grant_type: 'authorization_code',\n code: callback.code,\n client_id: this.#requireClientId(),\n redirect_uri: pending.redirectUri,\n code_verifier: pending.verifier,\n },\n parse: parseOAuthTokenResponse,\n });\n this.#token = {\n value: response.data.access_token,\n expiresAt: Date.now() + response.data.expires_in * 1_000,\n };\n const player = await this.getPlayer();\n if (player !== null) this.#writeSessionHint(browser.sessionStorage);\n }\n\n async #fetchPlayer(options: PixelumeRequestOptions): Promise<PixelumePlayer | null> {\n const token = this.#token;\n if (token === null) return null;\n try {\n const response = await this.#http.request({\n method: 'GET',\n path: '/v1/oauth/userinfo',\n credentials: 'omit',\n headers: { authorization: `Bearer ${token.value}` },\n signal: options.signal,\n timeoutMs: options.timeoutMs,\n parse: parsePlayerEnvelope,\n });\n const player = Object.freeze({ ...response.data.player });\n this.#setState(Object.freeze({ status: 'authenticated', player }));\n return player;\n } catch (error) {\n if (error instanceof PixelumeHttpError && error.status === 401) {\n this.#token = null;\n this.#setState(anonymous('expired'));\n return null;\n }\n throw error;\n }\n }\n\n async #doLogout(options: PixelumeRequestOptions): Promise<void> {\n const token = this.#token;\n this.#token = null;\n const browser = this.#optionalBrowser();\n if (browser) {\n this.#removePending(browser.sessionStorage);\n this.#removeSessionHint(browser.sessionStorage);\n }\n this.#setState(anonymous('logged_out'));\n if (token === null) return;\n await this.#http.request({\n method: 'POST',\n path: '/v1/oauth/revoke',\n credentials: 'omit',\n form: { token: token.value, token_type_hint: 'access_token' },\n signal: options.signal,\n timeoutMs: options.timeoutMs,\n parse: parseEmptyResponse,\n });\n }\n\n #readCallback(value: string): {\n readonly url: URL;\n readonly code: string | null;\n readonly error: string | null;\n readonly invalid: boolean;\n } | null {\n const redirectUri = this.#config.redirectUri;\n if (redirectUri === null) return null;\n const current = new URL(value);\n const expected = new URL(redirectUri);\n if (current.origin !== expected.origin || current.pathname !== expected.pathname) return null;\n const hasCallbackParameter = CALLBACK_PARAMETERS.some((key) => current.searchParams.has(key));\n if (!hasCallbackParameter) return null;\n const code = singleParameter(current, 'code');\n const error = singleParameter(current, 'error');\n return {\n url: current,\n code,\n error,\n invalid: !sameCallbackBase(current, expected) || (code === null) === (error === null),\n };\n }\n\n #cleanCallback(browser: PixelumeBrowserAdapter, url: URL): void {\n const clean = new URL(url.toString());\n for (const key of CALLBACK_PARAMETERS) clean.searchParams.delete(key);\n browser.replaceUrl(`${clean.pathname}${clean.search}${clean.hash}`);\n }\n\n #browser(): PixelumeBrowserAdapter {\n const browser = this.#optionalBrowser();\n if (!browser) throw new PixelumeAuthError('browser_unavailable');\n if (\n typeof browser.crypto.getRandomValues !== 'function' ||\n typeof browser.crypto.subtle.digest !== 'function'\n ) {\n throw new PixelumeAuthError('crypto_unavailable');\n }\n return browser;\n }\n\n #optionalBrowser(): PixelumeBrowserAdapter | null {\n if (this.#config.browser) return this.#config.browser;\n try {\n if (\n typeof globalThis.location === 'undefined' ||\n typeof globalThis.history === 'undefined' ||\n typeof globalThis.sessionStorage === 'undefined' ||\n typeof globalThis.crypto === 'undefined'\n ) {\n return null;\n }\n return {\n currentUrl: () => globalThis.location.href,\n navigate: (url) => {\n globalThis.location.assign(url);\n },\n replaceUrl: (url) => {\n globalThis.history.replaceState(globalThis.history.state, '', url);\n },\n sessionStorage: globalThis.sessionStorage,\n crypto: globalThis.crypto,\n };\n } catch (cause) {\n throw new PixelumeAuthError('storage_unavailable', { cause });\n }\n }\n\n #requireClientId(): string {\n if (this.#config.clientId === null) {\n throw new PixelumeConfigError('Pixelume Auth requires clientId or gameId');\n }\n return this.#config.clientId;\n }\n\n #requireRedirectUri(): string {\n if (this.#config.redirectUri === null) {\n throw new PixelumeAuthError('browser_unavailable');\n }\n return this.#config.redirectUri;\n }\n\n #pendingKey(): string {\n return `pixelume.oauth.pending.${this.#config.clientId ?? 'unconfigured'}`;\n }\n\n #hintKey(): string {\n return `pixelume.oauth.session.${this.#config.clientId ?? 'unconfigured'}`;\n }\n\n #readPending(storage: PixelumeSessionStorage): PendingAuthorization | null {\n try {\n const raw = storage.getItem(this.#pendingKey());\n if (raw === null) return null;\n const value: unknown = JSON.parse(raw);\n if (!isPendingAuthorization(value)) {\n storage.removeItem(this.#pendingKey());\n return null;\n }\n return value;\n } catch (cause) {\n throw new PixelumeAuthError('storage_unavailable', { cause });\n }\n }\n\n #writePending(storage: PixelumeSessionStorage, pending: PendingAuthorization): void {\n try {\n storage.setItem(this.#pendingKey(), JSON.stringify(pending));\n } catch (cause) {\n throw new PixelumeAuthError('storage_unavailable', { cause });\n }\n }\n\n #removePending(storage: PixelumeSessionStorage): void {\n try {\n storage.removeItem(this.#pendingKey());\n } catch (cause) {\n throw new PixelumeAuthError('storage_unavailable', { cause });\n }\n }\n\n #readSessionHint(storage: PixelumeSessionStorage): boolean {\n try {\n return storage.getItem(this.#hintKey()) === '1';\n } catch (cause) {\n throw new PixelumeAuthError('storage_unavailable', { cause });\n }\n }\n\n #writeSessionHint(storage: PixelumeSessionStorage): void {\n try {\n storage.setItem(this.#hintKey(), '1');\n } catch (cause) {\n throw new PixelumeAuthError('storage_unavailable', { cause });\n }\n }\n\n #removeSessionHint(storage: PixelumeSessionStorage): void {\n try {\n storage.removeItem(this.#hintKey());\n } catch (cause) {\n throw new PixelumeAuthError('storage_unavailable', { cause });\n }\n }\n\n #isExpired(pending: PendingAuthorization): boolean {\n const now = Date.now();\n return (\n pending.createdAt > now + 60_000 || pending.createdAt + AUTHORIZATION_REQUEST_TTL_MS < now\n );\n }\n\n #setState(state: PixelumeAuthState): void {\n const previous = this.#state;\n if (sameState(previous, state)) return;\n this.#state = state;\n for (const listener of [...this.#listeners]) listener(state, previous);\n }\n}\n\nfunction anonymous(\n reason: PixelumeAnonymousReason,\n error: PixelumeError | null = null,\n): PixelumeAuthState {\n return Object.freeze({ status: 'anonymous', player: null, reason, error });\n}\n\nfunction isPendingAuthorization(value: unknown): value is PendingAuthorization {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const pending = value as Record<string, unknown>;\n return (\n pending.version === 1 &&\n typeof pending.state === 'string' &&\n /^[A-Za-z0-9_-]{43}$/u.test(pending.state) &&\n typeof pending.verifier === 'string' &&\n /^[A-Za-z0-9_-]{43}$/u.test(pending.verifier) &&\n typeof pending.redirectUri === 'string' &&\n typeof pending.createdAt === 'number' &&\n Number.isFinite(pending.createdAt)\n );\n}\n\nfunction sameCallbackBase(current: URL, expected: URL): boolean {\n if (current.origin !== expected.origin || current.pathname !== expected.pathname) return false;\n const currentBase = new URL(current.toString());\n for (const key of CALLBACK_PARAMETERS) currentBase.searchParams.delete(key);\n currentBase.hash = '';\n const expectedBase = new URL(expected.toString());\n expectedBase.hash = '';\n return currentBase.toString() === expectedBase.toString();\n}\n\nfunction singleParameter(url: URL, name: string): string | null {\n const values = url.searchParams.getAll(name);\n if (values.length !== 1 || values[0] === '') return null;\n return values[0] ?? null;\n}\n\nfunction randomBase64Url(crypto: Crypto): string {\n const bytes = crypto.getRandomValues(new Uint8Array(32));\n return bytesToBase64Url(bytes);\n}\n\nasync function sha256Base64Url(crypto: Crypto, value: string): Promise<string> {\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(value));\n return bytesToBase64Url(new Uint8Array(digest));\n}\n\nfunction bytesToBase64Url(bytes: Uint8Array): string {\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replaceAll('+', '-').replaceAll('/', '_').replace(/=+$/u, '');\n}\n\nfunction sameState(left: PixelumeAuthState, right: PixelumeAuthState): boolean {\n if (left.status !== right.status) return false;\n if (left.status === 'authenticated' && right.status === 'authenticated') {\n return left.player === right.player;\n }\n if (left.status === 'anonymous' && right.status === 'anonymous') {\n return left.reason === right.reason && left.error === right.error;\n }\n return true;\n}\n"]}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Version of the SDK package. Kept in sync with `package.json` (checked by tests and by the release workflow). */
|
|
2
|
-
export declare const SDK_VERSION = "0.
|
|
2
|
+
export declare const SDK_VERSION = "0.2.0";
|
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,mHAAmH;AACnH,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC","sourcesContent":["/** Version of the SDK package. Kept in sync with `package.json` (checked by tests and by the release workflow). */\nexport const SDK_VERSION = '0.
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,mHAAmH;AACnH,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC","sourcesContent":["/** Version of the SDK package. Kept in sync with `package.json` (checked by tests and by the release workflow). */\nexport const SDK_VERSION = '0.2.0';\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixelume/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "SDK TypeScript da Pixelume para jogos web:
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "SDK TypeScript da Pixelume para jogos web: SSO com PKCE e cliente seguro para a Pixelume API.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"author": "Erickson Nascimento",
|
|
7
7
|
"repository": {
|