@axa-fr/oidc-client 7.22.18 → 7.22.19
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/README.md +31 -39
- package/bin/copy-service-worker-files.mjs +24 -17
- package/dist/OidcTrustedDomains.js +14 -12
- package/dist/cache.d.ts.map +1 -1
- package/dist/checkSession.d.ts +1 -1
- package/dist/checkSession.d.ts.map +1 -1
- package/dist/checkSessionIFrame.d.ts.map +1 -1
- package/dist/crypto.d.ts.map +1 -1
- package/dist/fetch.d.ts +2 -1
- package/dist/fetch.d.ts.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +935 -601
- package/dist/index.umd.cjs +2 -2
- package/dist/initSession.d.ts +1 -1
- package/dist/initSession.d.ts.map +1 -1
- package/dist/initWorker.d.ts +2 -2
- package/dist/initWorker.d.ts.map +1 -1
- package/dist/initWorkerOption.d.ts.map +1 -1
- package/dist/jwt.d.ts +2 -2
- package/dist/jwt.d.ts.map +1 -1
- package/dist/keepSession.d.ts.map +1 -1
- package/dist/location.d.ts.map +1 -1
- package/dist/login.d.ts +1 -1
- package/dist/login.d.ts.map +1 -1
- package/dist/logout.d.ts +1 -1
- package/dist/logout.d.ts.map +1 -1
- package/dist/oidc.d.ts +1 -1
- package/dist/oidc.d.ts.map +1 -1
- package/dist/oidcClient.d.ts +2 -2
- package/dist/oidcClient.d.ts.map +1 -1
- package/dist/parseTokens.d.ts.map +1 -1
- package/dist/renewTokens.d.ts.map +1 -1
- package/dist/requests.d.ts +1 -1
- package/dist/requests.d.ts.map +1 -1
- package/dist/silentLogin.d.ts.map +1 -1
- package/dist/timer.d.ts.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/user.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +2 -2
- package/src/cache.ts +21 -18
- package/src/checkSession.ts +89 -54
- package/src/checkSessionIFrame.ts +70 -69
- package/src/crypto.ts +27 -25
- package/src/events.ts +28 -28
- package/src/fetch.ts +40 -21
- package/src/index.ts +6 -17
- package/src/iniWorker.spec.ts +26 -16
- package/src/initSession.ts +115 -113
- package/src/initWorker.ts +299 -212
- package/src/initWorkerOption.ts +121 -114
- package/src/jwt.ts +150 -136
- package/src/keepSession.ts +100 -81
- package/src/location.ts +24 -26
- package/src/login.ts +246 -189
- package/src/logout.spec.ts +131 -76
- package/src/logout.ts +130 -115
- package/src/oidc.ts +426 -337
- package/src/oidcClient.ts +129 -105
- package/src/parseTokens.spec.ts +198 -179
- package/src/parseTokens.ts +221 -186
- package/src/renewTokens.ts +397 -284
- package/src/requests.spec.ts +5 -7
- package/src/requests.ts +142 -114
- package/src/route-utils.spec.ts +17 -19
- package/src/route-utils.ts +29 -26
- package/src/silentLogin.ts +145 -127
- package/src/timer.ts +10 -11
- package/src/types.ts +56 -46
- package/src/user.ts +17 -12
- package/src/version.ts +1 -1
package/src/initWorkerOption.ts
CHANGED
|
@@ -1,133 +1,140 @@
|
|
|
1
|
-
import {ServiceWorkerActivate} from
|
|
1
|
+
import { ServiceWorkerActivate } from './types';
|
|
2
2
|
|
|
3
|
-
export const excludeOs =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
export const excludeOs = operatingSystem => {
|
|
4
|
+
if (operatingSystem.os === 'iOS' && operatingSystem.osVersion.startsWith('12')) {
|
|
5
|
+
return true;
|
|
6
|
+
}
|
|
7
|
+
if (operatingSystem.os === 'Mac OS X' && operatingSystem.osVersion.startsWith('10_15_6')) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
return false;
|
|
11
11
|
};
|
|
12
|
-
export const getOperatingSystem =
|
|
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
|
-
|
|
12
|
+
export const getOperatingSystem = navigator => {
|
|
13
|
+
const nVer = navigator.appVersion;
|
|
14
|
+
const nAgt = navigator.userAgent;
|
|
15
|
+
const unknown = '-';
|
|
16
|
+
// system
|
|
17
|
+
let os = unknown;
|
|
18
|
+
const clientStrings = [
|
|
19
|
+
{ s: 'Windows 10', r: /(Windows 10.0|Windows NT 10.0)/ },
|
|
20
|
+
{ s: 'Windows 8.1', r: /(Windows 8.1|Windows NT 6.3)/ },
|
|
21
|
+
{ s: 'Windows 8', r: /(Windows 8|Windows NT 6.2)/ },
|
|
22
|
+
{ s: 'Windows 7', r: /(Windows 7|Windows NT 6.1)/ },
|
|
23
|
+
{ s: 'Windows Vista', r: /Windows NT 6.0/ },
|
|
24
|
+
{ s: 'Windows Server 2003', r: /Windows NT 5.2/ },
|
|
25
|
+
{ s: 'Windows XP', r: /(Windows NT 5.1|Windows XP)/ },
|
|
26
|
+
{ s: 'Windows 2000', r: /(Windows NT 5.0|Windows 2000)/ },
|
|
27
|
+
{ s: 'Windows ME', r: /(Win 9x 4.90|Windows ME)/ },
|
|
28
|
+
{ s: 'Windows 98', r: /(Windows 98|Win98)/ },
|
|
29
|
+
{ s: 'Windows 95', r: /(Windows 95|Win95|Windows_95)/ },
|
|
30
|
+
{ s: 'Windows NT 4.0', r: /(Windows NT 4.0|WinNT4.0|WinNT|Windows NT)/ },
|
|
31
|
+
{ s: 'Windows CE', r: /Windows CE/ },
|
|
32
|
+
{ s: 'Windows 3.11', r: /Win16/ },
|
|
33
|
+
{ s: 'Android', r: /Android/ },
|
|
34
|
+
{ s: 'Open BSD', r: /OpenBSD/ },
|
|
35
|
+
{ s: 'Sun OS', r: /SunOS/ },
|
|
36
|
+
{ s: 'Chrome OS', r: /CrOS/ },
|
|
37
|
+
{ s: 'Linux', r: /(Linux|X11(?!.*CrOS))/ },
|
|
38
|
+
{ s: 'iOS', r: /(iPhone|iPad|iPod)/ },
|
|
39
|
+
{ s: 'Mac OS X', r: /Mac OS X/ },
|
|
40
|
+
{ s: 'Mac OS', r: /(Mac OS|MacPPC|MacIntel|Mac_PowerPC|Macintosh)/ },
|
|
41
|
+
{ s: 'QNX', r: /QNX/ },
|
|
42
|
+
{ s: 'UNIX', r: /UNIX/ },
|
|
43
|
+
{ s: 'BeOS', r: /BeOS/ },
|
|
44
|
+
{ s: 'OS/2', r: /OS\/2/ },
|
|
45
|
+
{
|
|
46
|
+
s: 'Search Bot',
|
|
47
|
+
r: /(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver)/,
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
for (const id in clientStrings) {
|
|
51
|
+
const cs = clientStrings[id];
|
|
52
|
+
if (cs.r.test(nAgt)) {
|
|
53
|
+
os = cs.s;
|
|
54
|
+
break;
|
|
53
55
|
}
|
|
56
|
+
}
|
|
54
57
|
|
|
55
|
-
|
|
58
|
+
let osVersion = unknown;
|
|
56
59
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
if (/Windows/.test(os)) {
|
|
61
|
+
osVersion = /Windows (.*)/.exec(os)[1];
|
|
62
|
+
os = 'Windows';
|
|
63
|
+
}
|
|
61
64
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
switch (os) {
|
|
66
|
+
case 'Mac OS':
|
|
67
|
+
case 'Mac OS X':
|
|
68
|
+
case 'Android':
|
|
69
|
+
osVersion =
|
|
70
|
+
/(?:Android|Mac OS|Mac OS X|MacPPC|MacIntel|Mac_PowerPC|Macintosh) ([._\d]+)/.exec(nAgt)[1];
|
|
71
|
+
break;
|
|
68
72
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
case 'iOS': {
|
|
74
|
+
const osVersionArray = /OS (\d+)_(\d+)_?(\d+)?/.exec(nVer);
|
|
75
|
+
if (osVersionArray != null && osVersionArray.length > 2) {
|
|
76
|
+
osVersion =
|
|
77
|
+
osVersionArray[1] + '.' + osVersionArray[2] + '.' + (parseInt(osVersionArray[3]) | 0);
|
|
78
|
+
}
|
|
79
|
+
break;
|
|
76
80
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
os,
|
|
84
|
+
osVersion,
|
|
85
|
+
};
|
|
81
86
|
};
|
|
82
87
|
|
|
83
88
|
function getBrowser() {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (tem != null) {
|
|
94
|
-
let version = tem[1];
|
|
95
|
-
if (!version) {
|
|
96
|
-
const splits = ua.split(tem[0] + '/');
|
|
97
|
-
if (splits.length > 1) {
|
|
98
|
-
version = splits[1];
|
|
99
|
-
}
|
|
100
|
-
}
|
|
89
|
+
const ua = navigator.userAgent;
|
|
90
|
+
let tem;
|
|
91
|
+
let M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
|
|
92
|
+
if (/trident/i.test(M[1])) {
|
|
93
|
+
tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
|
|
94
|
+
return { name: 'ie', version: tem[1] || '' };
|
|
95
|
+
}
|
|
96
|
+
if (M[1] === 'Chrome') {
|
|
97
|
+
tem = ua.match(/\bOPR|Edge\/(\d+)/);
|
|
101
98
|
|
|
102
|
-
|
|
99
|
+
if (tem != null) {
|
|
100
|
+
let version = tem[1];
|
|
101
|
+
if (!version) {
|
|
102
|
+
const splits = ua.split(tem[0] + '/');
|
|
103
|
+
if (splits.length > 1) {
|
|
104
|
+
version = splits[1];
|
|
103
105
|
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return { name: 'opera', version };
|
|
104
109
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
}
|
|
111
|
+
M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?'];
|
|
112
|
+
if ((tem = ua.match(/version\/(\d+)/i)) != null) {
|
|
113
|
+
M.splice(1, 1, tem[1]);
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
name: M[0].toLowerCase(),
|
|
117
|
+
version: M[1],
|
|
118
|
+
};
|
|
111
119
|
}
|
|
112
120
|
|
|
113
|
-
export const activateServiceWorker
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
if (parseInt(version.split('.')[0]) < 80) {
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
121
|
+
export const activateServiceWorker: ServiceWorkerActivate = (): boolean => {
|
|
122
|
+
const { name, version } = getBrowser();
|
|
123
|
+
if (name === 'chrome' && parseInt(version) <= 70) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
if (name === 'opera') {
|
|
127
|
+
if (!version) {
|
|
128
|
+
return false;
|
|
125
129
|
}
|
|
126
|
-
if (
|
|
127
|
-
|
|
130
|
+
if (parseInt(version.split('.')[0]) < 80) {
|
|
131
|
+
return false;
|
|
128
132
|
}
|
|
133
|
+
}
|
|
134
|
+
if (name === 'ie') {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
129
137
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
138
|
+
const operatingSystem = getOperatingSystem(navigator);
|
|
139
|
+
return !excludeOs(operatingSystem);
|
|
140
|
+
};
|
package/src/jwt.ts
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
//
|
|
5
5
|
// because... JavaScript, Strings, and Buffers
|
|
6
6
|
// @ts-ignore
|
|
7
|
-
import {DemonstratingProofOfPossessionConfiguration} from
|
|
7
|
+
import { DemonstratingProofOfPossessionConfiguration } from './types';
|
|
8
8
|
|
|
9
9
|
function strToUint8(str) {
|
|
10
|
-
|
|
10
|
+
return new TextEncoder().encode(str);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
// Binary String to URL-Safe Base64
|
|
@@ -15,10 +15,7 @@ function strToUint8(str) {
|
|
|
15
15
|
// btoa (Binary-to-Ascii) means "binary string" to base64
|
|
16
16
|
// @ts-ignore
|
|
17
17
|
function binToUrlBase64(bin) {
|
|
18
|
-
|
|
19
|
-
.replace(/\+/g, '-')
|
|
20
|
-
.replace(/\//g, '_')
|
|
21
|
-
.replace(/=+/g, '');
|
|
18
|
+
return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+/g, '');
|
|
22
19
|
}
|
|
23
20
|
|
|
24
21
|
// UTF-8 to Binary String
|
|
@@ -27,53 +24,61 @@ function binToUrlBase64(bin) {
|
|
|
27
24
|
// https://coolaj86.com/articles/base64-unicode-utf-8-javascript-and-you/
|
|
28
25
|
// @ts-ignore
|
|
29
26
|
function utf8ToBinaryString(str) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
const escstr = encodeURIComponent(str);
|
|
28
|
+
// replaces any uri escape sequence, such as %0A,
|
|
29
|
+
// with binary escape, such as 0x0A
|
|
30
|
+
return escstr.replace(/%([0-9A-F]{2})/g, function (match, p1) {
|
|
31
|
+
return String.fromCharCode(parseInt(p1, 16));
|
|
32
|
+
});
|
|
36
33
|
}
|
|
37
34
|
|
|
38
35
|
// Uint8Array to URL Safe Base64
|
|
39
36
|
//
|
|
40
37
|
// the shortest distant between two encodings... binary string
|
|
41
38
|
// @ts-ignore
|
|
42
|
-
export const uint8ToUrlBase64 =(uint8: Uint8Array) => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
39
|
+
export const uint8ToUrlBase64 = (uint8: Uint8Array) => {
|
|
40
|
+
let bin = '';
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
uint8.forEach(function (code) {
|
|
43
|
+
bin += String.fromCharCode(code);
|
|
44
|
+
});
|
|
45
|
+
return binToUrlBase64(bin);
|
|
46
|
+
};
|
|
50
47
|
|
|
51
48
|
// UCS-2 String to URL-Safe Base64
|
|
52
49
|
//
|
|
53
50
|
// btoa doesn't work on UTF-8 strings
|
|
54
51
|
// @ts-ignore
|
|
55
52
|
function strToUrlBase64(str) {
|
|
56
|
-
|
|
53
|
+
return binToUrlBase64(utf8ToBinaryString(str));
|
|
57
54
|
}
|
|
58
55
|
|
|
59
|
-
export const defaultDemonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration =
|
|
56
|
+
export const defaultDemonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration =
|
|
57
|
+
{
|
|
60
58
|
importKeyAlgorithm: {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
name: 'ECDSA',
|
|
60
|
+
namedCurve: 'P-256',
|
|
61
|
+
hash: { name: 'ES256' },
|
|
64
62
|
},
|
|
65
|
-
signAlgorithm: {name: 'ECDSA', hash: {name: 'SHA-256'}},
|
|
63
|
+
signAlgorithm: { name: 'ECDSA', hash: { name: 'SHA-256' } },
|
|
66
64
|
generateKeyAlgorithm: {
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
name: 'ECDSA',
|
|
66
|
+
namedCurve: 'P-256',
|
|
69
67
|
},
|
|
70
68
|
digestAlgorithm: { name: 'SHA-256' },
|
|
71
|
-
jwtHeaderAlgorithm
|
|
72
|
-
}
|
|
73
|
-
|
|
69
|
+
jwtHeaderAlgorithm: 'ES256',
|
|
70
|
+
};
|
|
74
71
|
|
|
75
72
|
// @ts-ignore
|
|
76
|
-
const sign =
|
|
73
|
+
const sign =
|
|
74
|
+
(w: any) =>
|
|
75
|
+
async (
|
|
76
|
+
jwk,
|
|
77
|
+
headers,
|
|
78
|
+
claims,
|
|
79
|
+
demonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration,
|
|
80
|
+
jwtHeaderType = 'dpop+jwt',
|
|
81
|
+
) => {
|
|
77
82
|
// Make a shallow copy of the key
|
|
78
83
|
// (to set ext if it wasn't already set)
|
|
79
84
|
jwk = Object.assign({}, jwk);
|
|
@@ -82,25 +87,25 @@ const sign = (w:any) => async (jwk, headers, claims, demonstratingProofOfPossess
|
|
|
82
87
|
headers.typ = jwtHeaderType;
|
|
83
88
|
headers.alg = demonstratingProofOfPossessionConfiguration.jwtHeaderAlgorithm;
|
|
84
89
|
switch (headers.alg) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
90
|
+
case 'ES256': //if (!headers.kid) {
|
|
91
|
+
// alternate: see thumbprint function below
|
|
92
|
+
headers.jwk = { kty: jwk.kty, crv: jwk.crv, x: jwk.x, y: jwk.y };
|
|
93
|
+
//}
|
|
94
|
+
break;
|
|
95
|
+
case 'RS256':
|
|
96
|
+
headers.jwk = { kty: jwk.kty, n: jwk.n, e: jwk.e, kid: headers.kid };
|
|
97
|
+
break;
|
|
98
|
+
default:
|
|
99
|
+
throw new Error('Unknown or not implemented JWS algorithm');
|
|
95
100
|
}
|
|
96
101
|
|
|
97
102
|
const jws = {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
// @ts-ignore
|
|
104
|
+
// JWT "headers" really means JWS "protected headers"
|
|
105
|
+
protected: strToUrlBase64(JSON.stringify(headers)),
|
|
106
|
+
// @ts-ignore
|
|
107
|
+
// JWT "claims" are really a JSON-defined JWS "payload"
|
|
108
|
+
payload: strToUrlBase64(JSON.stringify(claims)),
|
|
104
109
|
};
|
|
105
110
|
|
|
106
111
|
// To import as EC (ECDSA, P-256, SHA-256, ES256)
|
|
@@ -131,13 +136,13 @@ const sign = (w:any) => async (jwk, headers, claims, demonstratingProofOfPossess
|
|
|
131
136
|
// JWT is just a "compressed", "protected" JWS
|
|
132
137
|
// @ts-ignore
|
|
133
138
|
return `${jws.protected}.${jws.payload}.${jws.signature}`;
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
export var JWT = {sign};
|
|
139
|
+
};
|
|
137
140
|
|
|
141
|
+
export const JWT = { sign };
|
|
138
142
|
|
|
139
143
|
// @ts-ignore
|
|
140
|
-
const generate =
|
|
144
|
+
const generate =
|
|
145
|
+
(w: any) => async (generateKeyAlgorithm: RsaHashedKeyGenParams | EcKeyGenParams) => {
|
|
141
146
|
const keyType = generateKeyAlgorithm;
|
|
142
147
|
const exportable = true;
|
|
143
148
|
const privileges = ['sign', 'verify'];
|
|
@@ -146,119 +151,128 @@ const generate = (w:any) => async (generateKeyAlgorithm: RsaHashedKeyGenParams |
|
|
|
146
151
|
// returns an abstract and opaque WebCrypto object,
|
|
147
152
|
// which in most cases you'll want to export as JSON to be able to save
|
|
148
153
|
return await w.crypto.subtle.exportKey('jwk', key.privateKey);
|
|
149
|
-
};
|
|
154
|
+
};
|
|
150
155
|
|
|
151
156
|
// Create a Public Key from a Private Key
|
|
152
157
|
//
|
|
153
158
|
// chops off the private parts
|
|
154
159
|
// @ts-ignore
|
|
155
160
|
const neuter = jwk => {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
161
|
+
const copy = Object.assign({}, jwk);
|
|
162
|
+
delete copy.d;
|
|
163
|
+
copy.key_ops = ['verify'];
|
|
164
|
+
return copy;
|
|
160
165
|
};
|
|
161
166
|
|
|
162
167
|
const EC = {
|
|
163
|
-
|
|
164
|
-
|
|
168
|
+
generate,
|
|
169
|
+
neuter,
|
|
165
170
|
};
|
|
166
171
|
// @ts-ignore
|
|
167
|
-
const thumbprint = (w:any) => async (jwk, digestAlgorithm: AlgorithmIdentifier) => {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return uint8ToUrlBase64(new Uint8Array(hash));
|
|
189
|
-
}
|
|
172
|
+
const thumbprint = (w: any) => async (jwk, digestAlgorithm: AlgorithmIdentifier) => {
|
|
173
|
+
let sortedPub;
|
|
174
|
+
// lexigraphically sorted, no spaces
|
|
175
|
+
switch (jwk.kty) {
|
|
176
|
+
case 'EC':
|
|
177
|
+
sortedPub = '{"crv":"CRV","kty":"EC","x":"X","y":"Y"}'
|
|
178
|
+
.replace('CRV', jwk.crv)
|
|
179
|
+
.replace('X', jwk.x)
|
|
180
|
+
.replace('Y', jwk.y);
|
|
181
|
+
break;
|
|
182
|
+
case 'RSA':
|
|
183
|
+
sortedPub = '{"e":"E","kty":"RSA","n":"N"}'.replace('E', jwk.e).replace('N', jwk.n);
|
|
184
|
+
break;
|
|
185
|
+
default:
|
|
186
|
+
throw new Error('Unknown or not implemented JWK type');
|
|
187
|
+
}
|
|
188
|
+
// The hash should match the size of the key,
|
|
189
|
+
// but we're only dealing with P-256
|
|
190
|
+
const hash = await w.crypto.subtle.digest(digestAlgorithm, strToUint8(sortedPub));
|
|
191
|
+
return uint8ToUrlBase64(new Uint8Array(hash));
|
|
192
|
+
};
|
|
190
193
|
|
|
191
|
-
export
|
|
194
|
+
export const JWK = { thumbprint };
|
|
192
195
|
|
|
193
|
-
export const generateJwkAsync =
|
|
196
|
+
export const generateJwkAsync =
|
|
197
|
+
(w: any) => async (generateKeyAlgorithm: RsaHashedKeyGenParams | EcKeyGenParams) => {
|
|
194
198
|
// @ts-ignore
|
|
195
199
|
const jwk = await EC.generate(w)(generateKeyAlgorithm);
|
|
196
200
|
// console.info('Private Key:', JSON.stringify(jwk));
|
|
197
201
|
// @ts-ignore
|
|
198
202
|
// console.info('Public Key:', JSON.stringify(EC.neuter(jwk)));
|
|
199
203
|
return jwk;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
export const generateJwtDemonstratingProofOfPossessionAsync = (w:any) => (demonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration) => async (jwk, method = 'POST', url: string, extrasClaims={}) => {
|
|
204
|
+
};
|
|
203
205
|
|
|
206
|
+
export const generateJwtDemonstratingProofOfPossessionAsync =
|
|
207
|
+
(w: any) =>
|
|
208
|
+
(demonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration) =>
|
|
209
|
+
async (jwk, method = 'POST', url: string, extrasClaims = {}) => {
|
|
204
210
|
const claims = {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
+
// https://www.rfc-editor.org/rfc/rfc9449.html#name-concept
|
|
212
|
+
jti: btoa(guid()),
|
|
213
|
+
htm: method,
|
|
214
|
+
htu: url,
|
|
215
|
+
iat: Math.round(Date.now() / 1000),
|
|
216
|
+
...extrasClaims,
|
|
211
217
|
};
|
|
212
218
|
// @ts-ignore
|
|
213
|
-
const kid = await JWK.thumbprint(w)(
|
|
219
|
+
const kid = await JWK.thumbprint(w)(
|
|
220
|
+
jwk,
|
|
221
|
+
demonstratingProofOfPossessionConfiguration.digestAlgorithm,
|
|
222
|
+
);
|
|
214
223
|
// @ts-ignore
|
|
215
|
-
const jwt = await JWT.sign(w)(
|
|
224
|
+
const jwt = await JWT.sign(w)(
|
|
225
|
+
jwk,
|
|
226
|
+
{ kid: kid },
|
|
227
|
+
claims,
|
|
228
|
+
demonstratingProofOfPossessionConfiguration,
|
|
229
|
+
);
|
|
216
230
|
// console.info('JWT:', jwt);
|
|
217
231
|
return jwt;
|
|
218
|
-
}
|
|
232
|
+
};
|
|
219
233
|
|
|
220
234
|
const guid = () => {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
235
|
+
// RFC4122: The version 4 UUID is meant for generating UUIDs from truly-random or
|
|
236
|
+
// pseudo-random numbers.
|
|
237
|
+
// The algorithm is as follows:
|
|
238
|
+
// Set the two most significant bits (bits 6 and 7) of the
|
|
239
|
+
// clock_seq_hi_and_reserved to zero and one, respectively.
|
|
240
|
+
// Set the four most significant bits (bits 12 through 15) of the
|
|
241
|
+
// time_hi_and_version field to the 4-bit version number from
|
|
242
|
+
// Section 4.1.3. Version4
|
|
243
|
+
// Set all the other bits to randomly (or pseudo-randomly) chosen
|
|
244
|
+
// values.
|
|
245
|
+
// UUID = time-low "-" time-mid "-"time-high-and-version "-"clock-seq-reserved and low(2hexOctet)"-" node
|
|
246
|
+
// time-low = 4hexOctet
|
|
247
|
+
// time-mid = 2hexOctet
|
|
248
|
+
// time-high-and-version = 2hexOctet
|
|
249
|
+
// clock-seq-and-reserved = hexOctet:
|
|
250
|
+
// clock-seq-low = hexOctet
|
|
251
|
+
// node = 6hexOctet
|
|
252
|
+
// Format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
|
|
253
|
+
// y could be 1000, 1001, 1010, 1011 since most significant two bits needs to be 10
|
|
254
|
+
// y values are 8, 9, A, B
|
|
255
|
+
const guidHolder = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
|
|
256
|
+
const hex = '0123456789abcdef';
|
|
257
|
+
let r = 0;
|
|
258
|
+
let guidResponse = '';
|
|
259
|
+
for (let i = 0; i < 36; i++) {
|
|
260
|
+
if (guidHolder[i] !== '-' && guidHolder[i] !== '4') {
|
|
261
|
+
// each x and y needs to be random
|
|
262
|
+
r = (Math.random() * 16) | 0;
|
|
263
|
+
}
|
|
250
264
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
265
|
+
if (guidHolder[i] === 'x') {
|
|
266
|
+
guidResponse += hex[r];
|
|
267
|
+
} else if (guidHolder[i] === 'y') {
|
|
268
|
+
// clock-seq-and-reserved first hex is filtered and remaining hex values are random
|
|
269
|
+
r &= 0x3; // bit and with 0011 to set pos 2 to zero ?0??
|
|
270
|
+
r |= 0x8; // set pos 3 to 1 as 1???
|
|
271
|
+
guidResponse += hex[r];
|
|
272
|
+
} else {
|
|
273
|
+
guidResponse += guidHolder[i];
|
|
261
274
|
}
|
|
275
|
+
}
|
|
262
276
|
|
|
263
|
-
|
|
277
|
+
return guidResponse;
|
|
264
278
|
};
|