-
Notifications
You must be signed in to change notification settings - Fork 327
/
Copy pathutils.ts
107 lines (86 loc) · 3.24 KB
/
utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import { ClerkWebAuthnError } from '@clerk/shared/error';
import { Buffer } from 'buffer';
export { ClerkWebAuthnError };
export function encodeBase64(data: ArrayBufferLike) {
return btoa(String.fromCharCode(...new Uint8Array(data)));
}
export function encodeBase64Url(data: ArrayBufferLike) {
return encodeBase64(data).replaceAll('=', '').replaceAll('+', '-').replaceAll('/', '_');
}
export function decodeBase64Url(data: string) {
return decodeBase64(data.replaceAll('-', '+').replaceAll('_', '/'));
}
export function decodeToken(data: string) {
const base64 = data.replace(/-/g, '+').replace(/_/g, '/');
const jsonPayload = decodeURIComponent(
atob(base64)
.split('')
.map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
.join(''),
);
return JSON.parse(jsonPayload);
}
export function decodeBase64(data: string) {
return Uint8Array.from(atob(data).split(''), x => x.charCodeAt(0));
}
export function utf8Decode(buffer: BufferSource) {
const textDecoder = new TextDecoder();
return textDecoder.decode(buffer);
}
export function toArrayBuffer(bufferSource: BufferSource) {
if (bufferSource instanceof ArrayBuffer) {
return bufferSource; // It's already an ArrayBuffer
} else if (ArrayBuffer.isView(bufferSource)) {
return bufferSource.buffer; // Extract the ArrayBuffer from the typed array
} else {
throw new TypeError('Expected a BufferSource, but received an incompatible type.');
}
}
export function base64urlToArrayBuffer(base64url: string) {
const base64 = base64url.replace(/-/g, '+').replace(/_/g, '/');
const binaryString = Buffer.from(base64, 'base64').toString('binary');
const len = binaryString.length;
const buffer = new ArrayBuffer(len);
const uintArray = new Uint8Array(buffer);
for (let i = 0; i < len; i++) {
uintArray[i] = binaryString.charCodeAt(i);
}
return buffer;
}
export function arrayBufferToBase64Url(buffer: ArrayBufferLike) {
const bytes = new Uint8Array(buffer);
let binary = '';
for (let i = 0; i < bytes.length; i++) {
binary += String.fromCharCode(bytes[i]);
}
const base64String = btoa(binary);
const base64Url = base64String.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
return base64Url;
}
export function mapNativeErrorToClerkWebAuthnErrorCode(
code: string,
message: string,
action: 'get' | 'create',
): ClerkWebAuthnError {
if (code === '1000' || code === '1004' || code === 'CreatePublicKeyCredentialDomException') {
return new ClerkWebAuthnError(message, {
code: action === 'create' ? 'passkey_registration_failed' : 'passkey_retrieval_failed',
});
}
if (
code === '1001' ||
code === 'CreateCredentialCancellationException' ||
code === 'GetCredentialCancellationException'
) {
return new ClerkWebAuthnError(message, { code: 'passkey_registration_cancelled' });
}
if (code === '1002') {
return new ClerkWebAuthnError(message, { code: 'passkey_invalid_rpID_or_domain' });
}
if (code === '1003' || code === 'CreateCredentialInterruptedException') {
return new ClerkWebAuthnError(message, { code: 'passkey_operation_aborted' });
}
return new ClerkWebAuthnError(message, {
code: action === 'create' ? 'passkey_registration_failed' : 'passkey_retrieval_failed',
});
}