PageSourceSearch

https://login.codere.mx/jswrapper/fidoAuth.js?casino=codere.mx&min=1

js codere.mx collected 2026-09-24 19:19:36 UTC 22,589 bytes, 683 lines download raw bytes

1function fidoWrapper() {
2
3    const ENROLL_INIT_URL = 'FidoEnroll/init';
4    const ENROLL_FINALIZE_URL = 'FidoEnroll/finalize';
5
6    const AUTH_INIT_URL = 'FidoAuth/init';
7    const AUTH_FINALIZE_URL = 'FidoAuth/finalize'
8
9    let abortController = new AbortController();
10    let timeoutEvent;
11
12    const TIMEOUT_OFFSET = 5000;
13
14    const ERR_GENERAL = -1
15    const ERR_CANCELLED = -10;
16    const ERR_ABORT = -11;
17    const ERR_INVALID_STATE = -12;
18    const ERR_NOT_SUPPORTED = -13;
19    const ERR_AUTOFILL_NOT_AVAILABLE = -14;
20
21    return {
22        ERR_CANCELLED: ERR_CANCELLED,
23        // The same error is used for both timeouts and regular aborts (initiating a new flow while the old one is in progress)
24        ERR_TIMEOUT: ERR_ABORT,
25        ERR_ABORT: ERR_ABORT,
26        ERR_INVALID_STATE: ERR_INVALID_STATE,
27        ERR_NOT_SUPPORTED: ERR_NOT_SUPPORTED,
28        ERR_AUTOFILL_NOT_AVAILABLE: ERR_AUTOFILL_NOT_AVAILABLE,
29
30        /**
31         * Enroll an authenticator (passkey)
32         *
33         * @param callback called with {errorCode:iapiERR_OK} when enrollment was successful, or {errorCode: <error>} when something went wrong.
34         *                  if errorCode < 0 then the error originated from the frontend.
35         * @param authenticatorName name for the authenticator
36         * @param username if null then will attempt to fall back to using sessionStorage or cookies.
37         * @param token sessionToken. if null then will attempt to fall back to using sessionStorage or cookies.
38         * @returns {Promise<Object>} resolved with the same data as callback, except promise is rejected if there was an error.
39         */
40        enroll: async function (callback, authenticatorName, username, token) {
41            try {
42                ensureConf();
43
44                abortController.abort({
45                    errorCode: ERR_ABORT,
46                    message: "New enroll initiated"
47                })
48                abortController = new AbortController();
49
50                const enrollCredentials = await initEnroll(username, token);
51                const credentialCreateResult = await webAuthn.create(enrollCredentials);
52
53                const enrollResponse = await finalizeEnroll(credentialCreateResult, authenticatorName, username, token);
54
55                call(callback, enrollResponse);
56                return enrollResponse;
57            } catch (e) {
58                const pasError = mapError(e);
59                call(callback, pasError);
60                throw pasError;
61            } finally {
62                clearTimeout(timeoutEvent)
63                timeoutEvent = null;
64            }
65        },
66
67        /**
68         * Authentication flow
69         *
70         * Use when you want to enable autofill UI
71         * Only call this on a login screen, when you have a "username" text input field on screen with autocomplete="username webauthn" params
72         * Availability can be checked first with isAutofillSupported()
73         *
74         * @param callback called with {errorCode:iapiERR_OK} when authentication was successful, or {errorCode: <error>} when something went wrong.
75         *                  if errorCode < 0 then the error originated from the frontend.
76         * @returns {Promise<Object>} resolved with the same data as callback, except promise is rejected if there was an error.
77         */
78        authenticateAutofillUI: async function (callback) {
79            try {
80                ensureConf();
81                await ensureConditionalMediationAvailable();
82            } catch (e) {
83                const pasError = mapError(e)
84                call(callback, pasError)
85                throw pasError;
86            }
87
88            return await continueAuth(callback, true);
89        },
90
91        /**
92         * Authentication flow
93         *
94         * for use on a "Login with Passkey" button.
95         *
96         * @param callback called with {errorCode:iapiERR_OK} when authentication was successful, or {errorCode: <error>} when something went wrong.
97         *                  if errorCode < 0 then the error originated from the frontend.
98         * @returns {Promise<Object>} resolved with the same data as callback, except promise is rejected if there was an error.
99         */
100        authenticate: async function (callback) {
101            try {
102                ensureConf();
103            } catch (e) {
104                const pasError = mapError(e)
105                call(callback, pasError)
106                throw pasError;
107            }
108
109            return await continueAuth(callback, false);
110        },
111
112        /**
113         * Check if browser supports FIDO2/Passkey authentication and the feature has been enabled in the casino conf.
114         *
115         * @returns {boolean}
116         */
117        isSupported: function () {
118            try {
119                ensureConf();
120                return true;
121            } catch (e) {
122                return false;
123            }
124        },
125
126        /**
127         * Check if the FIDO2/Passkey login feature has been enabled in the casino conf.
128         *
129         * @returns {boolean}
130         */
131        isConfigured: function () {
132            try {
133                ensureEnabled();
134                return true;
135            } catch (e) {
136                return false;
137            }
138        },
139
140        /**
141         * Check if autofill auth flow is supported by the browser, and it is possible to show to the user a passkey login prompt.
142         * @returns {Promise<boolean>}
143         */
144        isAutofillSupported: async function () {
145            try {
146                ensureConf();
147                await ensureConditionalMediationAvailable();
148                return true;
149            } catch (e) {
150                return false;
151            }
152        },
153
154        /**
155         * Abort the currently pending user interaction.
156         */
157        abortCurrent() {
158            abortController.abort({
159                errorCode: ERR_ABORT,
160                message: "Request aborted."
161            })
162        }
163    }
164
165    async function continueAuth(callback, conditionalMediation) {
166        abortController.abort({
167            errorCode: ERR_ABORT,
168            message: conditionalMediation ? "New autofill auth initiated" : "New auth initiated"
169        })
170
171        abortController = new AbortController();
172        try {
173            const authCredentials = await initAuthFetch(conditionalMediation);
174            const credentialGetResult = await webAuthn.get(authCredentials);
175            const authResponse = await finalizeAuth(credentialGetResult);
176
177            call(callback, authResponse);
178            return authResponse;
179        } catch (e) {
180            const pasError = mapError(e);
181            call(callback, pasError)
182            throw pasError;
183        } finally {
184            clearTimeout(timeoutEvent)
185            timeoutEvent = null;
186        }
187    }
188
189    async function initAuthFetch(conditionalMediation) {
190
191        const postParams = {casinoname: iapiConf['casinoname']}
192
193        const initAuthResponse = await fetchRequest(AUTH_INIT_URL, postParams)
194
195        if (initAuthResponse.errorCode !== iapiERR_OK || !initAuthResponse.credentialRequestOptions) {
196            throw initAuthResponse;
197        }
198
199        const requestOptions = JSON.parse(initAuthResponse.credentialRequestOptions);
200
201        setTimeoutEvent(requestOptions.timeout)
202
203        let requestJSON = {
204            publicKey: requestOptions,
205            signal: abortController.signal
206        };
207
208        if (conditionalMediation) {
209            requestJSON.mediation = 'conditional'
210        }
211
212        return webAuthn.getRequestFromJSON(requestJSON);
213    }
214
215
216    async function finalizeAuth(result) {
217        let credentialGetResultJSON = webAuthn.getResponseToJSON(result);
218
219        if (!credentialGetResultJSON.response.userHandle) {
220            throw {
221                errorCode: ERR_NOT_SUPPORTED,
222                errorText: "Operation not supported by this browser."
223            }
224        }
225        credentialGetResultJSON.userAgent = navigator.userAgent;
226
227
228        const postParams = {
229            "casinoname": iapiConf['casinoname'],
230            "credentials": JSON.stringify(credentialGetResultJSON)
231        }
232
233        const finalizeResponse = await fetchRequest(AUTH_FINALIZE_URL, postParams);
234
235        if (finalizeResponse.errorCode !== iapiERR_OK) {
236            throw finalizeResponse;
237        }
238        return finalizeResponse
239    }
240
241
242// 
243
244    async function initEnroll(username, token) {
245        let params = {casinoname: iapiConf["casinoname"]}
246
247        if (username && token) {
248            params["username"] = username
249            params["token"] = token
250        } else {
251            const username = getFromStorage("username");
252            const token = getFromStorage("token");
253
254            if (username) {
255                params["username"] = username;
256            }
257            if (token) {
258                params["token"] = token;
259            }
260        }
261
262        const initEnrollResponse = await fetchRequest(ENROLL_INIT_URL, params)
263        if (initEnrollResponse.errorCode !== iapiERR_OK || !initEnrollResponse.credentialCreateOptions) {
264            throw initEnrollResponse;
265        }
266
267        const creationOptions = JSON.parse(initEnrollResponse.credentialCreateOptions);
268
269        setTimeoutEvent(creationOptions.timeout)
270
271        return webAuthn.createRequestFromJSON({
272            publicKey: creationOptions,
273            signal: abortController.signal
274        });
275    }
276
277    async function finalizeEnroll(credentialCreateResult, authenticatorName, username, token) {
278        let credentialCreateResultJSON = webAuthn.createResponseToJSON(credentialCreateResult);
279        credentialCreateResultJSON.userAgent = navigator.userAgent;
280        credentialCreateResultJSON.userFriendlyName = authenticatorName;
281
282        let params = {
283            "casinoname": iapiConf['casinoname'],
284            "credentials": JSON.stringify(credentialCreateResultJSON)
285        }
286
287        if (username && token) {
288            params["username"] = username
289            params["token"] = token
290        } else {
291            const username = getFromStorage("username");
292            const token = getFromStorage("token");
293
294            if (username) {
295                params["username"] = username;
296            }
297            if (token) {
298                params["token"] = token;
299            }
300        }
301
302        const finalizeResponse = await fetchRequest(ENROLL_FINALIZE_URL, params);
303
304        if (finalizeResponse.errorCode !== iapiERR_OK) {
305            throw finalizeResponse;
306        }
307        return finalizeResponse;
308    }
309
310
311    async function fetchRequest(credentialsUrl, params) {
312        const availableServers = iapiConf['loginServer'].split('|');
313        const loginServer = availableServers[Math.floor(Math.random() * availableServers.length)];
314
315        let url = getHttpProtocol() + '://' + loginServer + "/" + iapiAppendContextParameters(credentialsUrl)
316
317        if (iapiConf['errorLevel'] === '1' || iapiConf['errorLevel'] === 1) {
318            url += '&errorLevel=1';
319        }
320
321        let bodyMap = new Map();
322        for (let property in params) {
323            const encodedKey = encodeURIComponent(property);
324            const encodedValue = encodeURIComponent(params[property]);
325            bodyMap.set(encodedKey, encodedValue);
326        }
327        bodyMap.set("responseType", "json");
328        bodyMap.set("sessionRef", getFromStorage("sessionRef"));
329
330        let body = ""
331        bodyMap.forEach((value, key) => {
332            body += key + "=" + value + "&";
333        });
334        if (body.endsWith('&')) {
335            body = body.substring(0, body.length - 1)
336        }
337
338        const response = await fetch(url, {
339            method: "POST",
340            headers: {
341                "Content-Type": "application/x-www-form-urlencoded"
342            },
343            body: body
344        })
345
346        return await response.json();
347    }
348
349// 
350
351    function getFromStorage(key) {
352        return sessionStorage.getItem(getSessionKey(iapiConf["casinoname"], key))
353    }
354
355    function getSessionKey(casino, key) {
356        return "pas[" + casino + "][real][" + key + "]";
357    }
358
359    function call(callback, param) {
360        if (callback && typeof callback === "function") {
361            callback(param)
362        }
363    }
364
365    // maps errors coming from frontend to be in the same format as PAS API errors.
366    function mapError(e) {
367        if (typeof iapiConf === 'object' && iapiConf["fidoDebug"] === '1') {
368            console.error(e)
369        }
370
371        if (e.errorCode >= 0) {
372        // 
373            return e;
374        }
375
376        // map WebAuthn api errors to have an errorCode.
377        const errorMap = {
378            "NotAllowedError": ERR_CANCELLED,
379            "InvalidStateError": ERR_INVALID_STATE,
380            "AbortError": ERR_ABORT,
381            "NotSupportedError": ERR_NOT_SUPPORTED
382        };
383
384        const errorCode = e.errorCode ?? (errorMap[e.name] || ERR_GENERAL);
385        const errorText = e.errorText ?? e.message ?? e;
386        let error = {errorCode: errorCode, errorText: errorText};
387        if (e.name) error['name'] = e.name
388
389        return error
390
391    }
392
393    function setTimeoutEvent(timeoutMs) {
394        if (!timeoutMs || timeoutMs <= 0) {
395            return // 
396        }
397    // 
398        timeoutMs = timeoutMs <= TIMEOUT_OFFSET ? timeoutMs : timeoutMs - TIMEOUT_OFFSET
399
400        if (timeoutEvent) {
401            clearTimeout(timeoutEvent)
402            timeoutEvent = null;
403        }
404
405        timeoutEvent = setTimeout(() => {
406            abortController.abort({
407                errorCode: ERR_ABORT,
408                message: "User did not complete the interaction in the allocated time."
409            })
410        }, timeoutMs)
411    }
412
413    function ensureConf() {
414        ensureEnabled();
415        ensureWebAuthnSupported();
416    }
417
418    function ensureEnabled() {
419        if (typeof iapiConf === 'undefined' || !iapiConf) {
420            throw {
421                errorCode: ERR_GENERAL,
422                errorText: 'Not configured!. Please, do add integration.js'
423            };
424        }
425
426        if (iapiConf['fidoAuth'] !== "1") {
427            throw {
428                errorCode: ERR_GENERAL,
429                errorText: 'FIDO2 authentication not enabled in casino'
430            };
431        }
432    }
433
434    function ensureWebAuthnSupported() {
435        if (!navigator.credentials || !navigator.credentials.get || !navigator.credentials.get) {
436            throw {
437                errorCode: ERR_NOT_SUPPORTED,
438                errorText: 'No navigator.credentials. Is this a secure context?'
439            };
440        }
441
442        if (!window.PublicKeyCredential) {
443            throw {
444                errorCode: ERR_NOT_SUPPORTED,
445                errorText: 'Browser does not support webAuthn'
446            };
447        }
448    }
449
450    async function ensureConditionalMediationAvailable() {
451        if (window.PublicKeyCredential && typeof PublicKeyCredential.isConditionalMediationAvailable === "function") {
452            if (await PublicKeyCredential.isConditionalMediationAvailable()) {
453                return
454            } else {
455                throw {
456                    errorCode: ERR_AUTOFILL_NOT_AVAILABLE,
457                    errorText: "Browser is not reporting a discoverable resident key. Cannot initiate autofill flow."
458                };
459            }
460        }
461
462        throw {
463            errorCode: ERR_AUTOFILL_NOT_AVAILABLE,
464            errorText: "Browser does not support autofill."
465        };
466    }
467}
468
469self.fidoAuth = fidoWrapper();
470
471
472// https://github.com/github/webauthn-json
473function webAuthnWrapper() {
474    function base64urlToBuffer(baseurl64String) {
475        const padding = "==".slice(0, (4 - baseurl64String.length % 4) % 4);
476        const base64String = baseurl64String.replace(/-/g, "+").replace(/_/g, "/") + padding;
477        const str = atob(base64String);
478        const buffer = new ArrayBuffer(str.length);
479        const byteView = new Uint8Array(buffer);
480        for (let i = 0; i < str.length; i++) {
481            byteView[i] = str.charCodeAt(i);
482        }
483        return buffer;
484    }
485
486    function bufferToBase64url(buffer) {
487        const byteView = new Uint8Array(buffer);
488        let str = "";
489        for (const charCode of byteView) {
490            str += String.fromCharCode(charCode);
491        }
492        const base64String = btoa(str);
493        return base64String.replace(/\+/g, "-").replace(
494            /\//g,
495            "_"
496        ).replace(/=/g, "");
497    }
498
499    const copyValue = "copy";
500    const convertValue = "convert";
501
502    function convert(conversionFn, schema, input) {
503        if (schema === copyValue) {
504            return input;
505        }
506        if (schema === convertValue) {
507            return conversionFn(input);
508        }
509        if (schema instanceof Array) {
510            return input.map((v) => convert(conversionFn, schema[0], v));
511        }
512        if (schema instanceof Object) {
513            const output = {};
514            for (const [key, schemaField] of Object.entries(schema)) {
515                if (schemaField.derive) {
516                    const v = schemaField.derive(input);
517                    if (v !== void 0) {
518                        input[key] = v;
519                    }
520                }
521                if (!(key in input)) {
522                    if (schemaField.required) {
523                        throw new Error("Missing key: " + key);
524                    }
525                    continue;
526                }
527                if (input[key] == null) {
528                    output[key] = null;
529                    continue;
530                }
531                output[key] = convert(
532                    conversionFn,
533                    schemaField.schema,
534                    input[key]
535                );
536            }
537            return output;
538        }
539    }
540
541    function derived(schema, derive) {
542        return {
543            required: true,
544            schema,
545            derive
546        };
547    }
548
549    function required(schema) {
550        return {
551            required: true,
552            schema
553        };
554    }
555
556    function optional(schema) {
557        return {
558            required: false,
559            schema
560        };
561    }
562
563    const publicKeyCredentialDescriptorSchema = {
564        type: required(copyValue),
565        id: required(convertValue),
566        transports: optional(copyValue)
567    };
568    const simplifiedExtensionsSchema = {
569        appid: optional(copyValue),
570        appidExclude: optional(copyValue),
571        credProps: optional(copyValue)
572    };
573    const simplifiedClientExtensionResultsSchema = {
574        appid: optional(copyValue),
575        appidExclude: optional(copyValue),
576        credProps: optional(copyValue)
577    };
578    const credentialCreationOptions = {
579        publicKey: required({
580            rp: required(copyValue),
581            user: required({
582                id: required(convertValue),
583                name: required(copyValue),
584                displayName: required(copyValue)
585            }),
586            challenge: required(convertValue),
587            pubKeyCredParams: required(copyValue),
588            timeout: optional(copyValue),
589            excludeCredentials: optional([publicKeyCredentialDescriptorSchema]),
590            authenticatorSelection: optional(copyValue),
591            attestation: optional(copyValue),
592            extensions: optional(simplifiedExtensionsSchema)
593        }),
594        signal: optional(copyValue)
595    };
596    const publicKeyCredentialWithAttestation = {
597        type: required(copyValue),
598        id: required(copyValue),
599        rawId: required(convertValue),
600        authenticatorAttachment: optional(copyValue),
601        response: required({
602            clientDataJSON: required(convertValue),
603            attestationObject: required(convertValue),
604            transports: derived(
605                copyValue,
606                (response) => {
607                    let _a;
608                    return ((_a = response.getTransports) == null ? void 0 : _a.call(response)) || [];
609                }
610            )
611        }),
612        clientExtensionResults: derived(
613            simplifiedClientExtensionResultsSchema,
614            (pkc) => pkc.getClientExtensionResults()
615        )
616    };
617    const credentialRequestOptions = {
618        mediation: optional(copyValue),
619        publicKey: required({
620            challenge: required(convertValue),
621            timeout: optional(copyValue),
622            rpId: optional(copyValue),
623            allowCredentials: optional([publicKeyCredentialDescriptorSchema]),
624            userVerification: optional(copyValue),
625            extensions: optional(simplifiedExtensionsSchema)
626        }),
627        signal: optional(copyValue)
628    };
629    const publicKeyCredentialWithAssertion = {
630        type: required(copyValue),
631        id: required(copyValue),
632        rawId: required(convertValue),
633        authenticatorAttachment: optional(copyValue),
634        response: required({
635            clientDataJSON: required(convertValue),
636            authenticatorData: required(convertValue),
637            signature: required(convertValue),
638            userHandle: required(convertValue)
639        }),
640        clientExtensionResults: derived(
641            simplifiedClientExtensionResultsSchema,
642            (pkc) => pkc.getClientExtensionResults()
643        )
644    };
645
646    return {
647        createRequestFromJSON: function createRequestFromJSON(requestJSON) {
648            return convert(base64urlToBuffer, credentialCreationOptions, requestJSON);
649        },
650        createResponseToJSON: function createResponseToJSON(credential) {
651            return convert(
652                bufferToBase64url,
653                publicKeyCredentialWithAttestation,
654                credential
655            );
656        },
657        getRequestFromJSON: function getRequestFromJSON(requestJSON) {
658            return convert(base64urlToBuffer, credentialRequestOptions, requestJSON);
659        },
660        getResponseToJSON: function getResponseToJSON(credential) {
661            return convert(
662                bufferToBase64url,
663                publicKeyCredentialWithAssertion,
664                credential
665            );
666        },
667
668        create: async function create(options) {
669            const response = await navigator.credentials.create(
670                options
671            );
672            response.toJSON = () => this.createResponseToJSON(response);
673            return response;
674        },
675        get: async function get(options) {
676            return navigator.credentials.get(
677                options
678            );
679        }
680    }
681}
682
683self.webAuthn = webAuthnWrapper();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.