PageSourceSearch

https://www.smartpropertyinvestment.com.au/media/templates/site/mo…/public/js/fusionauth-webauthn.js?8109a2

js smartpropertyinvestment.com.au collected 2026-10-02 06:26:33 UTC 4,737 bytes, 115 lines download raw bytes

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

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.