PageSourceSearch

https://www.theadviser.com.au/media/com_custom/js/membership/fusionauth-webauthn.js?2ff634

js theadviser.com.au collected 2026-09-24 17:34:55 UTC 4,737 bytes, 116 lines download raw bytes

1// https://fusionauth.io/docs/lifecycle/authenticate-users/passwordless/webauthn-passkeys
2class FusionAuthWebAuthn
3{
4    extraPayloadData = {};
5
6    async startRegistration() {
7        const response = await this.executeHttpRequest('createPasskeyStart');
8        const requestCredentialOptions = {
9            publicKey : {
10                ...response.data.options,
11                challenge          : this.base64UrlToBuffer(response.data.options.challenge),
12                excludeCredentials : response.data.options.excludeCredentials?.map(credential => {
13                    return {
14                        ...credential,
15                        id : this.base64UrlToBuffer(credential.id)
16                    }
17                }) ?? [],
18                user               : {
19                    ...response.data.options.user,
20                    id : this.base64UrlToBuffer(response.data.options.user.id)
21                }
22            }
23        };
24
25        // Remove the authenticatorSelection key so that other authentication options will be available.
26        delete requestCredentialOptions.publicKey.authenticatorSelection;
27
28        return await navigator.credentials.create(requestCredentialOptions);
29    }
30
31    async completeRegistration(publicKeyCredential) {
32        const transformedCredentials = {
33            id          : publicKeyCredential.id,
34            response    : {
35                attestationObject : this.bufferToBase64Url(publicKeyCredential.response.attestationObject),
36                clientDataJSON    : this.bufferToBase64Url(publicKeyCredential.response.clientDataJSON)
37            },
38            transports  : (typeof publicKeyCredential.response.getTransports === 'undefined') ? [] : publicKeyCredential.response.getTransports(),
39            type        : publicKeyCredential.type
40        };
41            
42        return await this.executeHttpRequest('createPasskeyComplete', {
43            credential : transformedCredentials
44        });
45    }
46
47    async startPasskeyAssertion() {
48        const response = await this.executeHttpRequest('startPasskeyAssertion');
49        if (response.result === false) {
50            return response;
51        }
52
53        const requestCredentialOptions = {
54            publicKey : {
55                ...response.data.options,
56                challenge        : this.base64UrlToBuffer(response.data.options.challenge),
57                allowCredentials : response.data.options.allowCredentials?.map(credential => {
58                    return {
59                        ...credential,
60                        id : this.base64UrlToBuffer(credential.id)
61                    }
62                }) ?? []
63            }
64        };
65
66        return await navigator.credentials.get(requestCredentialOptions);
67    }
68
69    async preparePasskeyAssertionCompletionPayload(publicKeyCredential) {
70        return {
71            id                     : publicKeyCredential.id,
72            response               : {
73                authenticatorData : this.bufferToBase64Url(publicKeyCredential.response.authenticatorData),
74                clientDataJSON    : this.bufferToBase64Url(publicKeyCredential.response.clientDataJSON),
75                signature         : this.bufferToBase64Url(publicKeyCredential.response.signature),
76                userHandle        : this.bufferToBase64Url(publicKeyCredential.response.userHandle) ?? undefined
77            },
78            type                   : publicKeyCredential.type,
79            clientExtensionResults : publicKeyCredential.getClientExtensionResults()
80        };
81    }
82
83    setExtraPayloadData(extraPayloadData) {
84        this.extraPayloadData = extraPayloadData;
85    }
86
87    async executeHttpRequest(method, requestParams = {}) {
88        return await $.ajax({
89            url      : '/?' + $.param({
90                option : 'com_ajax',
91                plugin : method, // ajaxfusionauth
92                format : 'json'
93            }),
94            method   : 'POST',
95            data     : {
96                ...requestParams,
97                ...this.extraPayloadData
98            },
99            dataType : 'json'
100        })
101        .then((response) => response.data[response.data.length - 1]);
102    }
103
104    base64UrlToBuffer(base64Url) {
105        const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
106        const padLen = (4 - (base64.length % 4)) % 4;
107        return Uint8Array.from(atob(base64.padEnd(base64.length + padLen, '=')), char => char.charCodeAt(0));
108    }
109
110    bufferToBase64Url(buffer) {
111        let string = '';
112        const bytes = new Uint8Array(buffer);
113        bytes.forEach(byte => string += String.fromCharCode(byte));
114        return btoa(string).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
115    }
116}

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.