oidc-spa 8.5.5 → 8.6.0

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.
@@ -2,7 +2,7 @@ import { assert } from "../tools/tsafe/assert";
2
2
 
3
3
  let isTokenSubstitutionEnabled = false;
4
4
 
5
- export function markTokenSubstitutionAdEnabled() {
5
+ export function markTokenSubstitutionAsEnabled() {
6
6
  isTokenSubstitutionEnabled = true;
7
7
  }
8
8
 
@@ -18,10 +18,61 @@ type Tokens = {
18
18
 
19
19
  const entries: {
20
20
  configId: string;
21
- tokens: Tokens;
22
21
  id: number;
22
+ tokens: Tokens;
23
+ tokens_placeholder: Tokens;
23
24
  }[] = [];
24
25
 
26
+ function generatePlaceholderForToken(params: {
27
+ tokenType: "id_token" | "access_token" | "refresh_token";
28
+ token_real: string;
29
+ id: number;
30
+ }): string {
31
+ const { tokenType, token_real, id } = params;
32
+
33
+ const match = token_real.match(/^([A-Za-z0-9\-_]+)\.([A-Za-z0-9\-_]+)\.([A-Za-z0-9\-_]+)$/);
34
+
35
+ if (match === null) {
36
+ assert(tokenType !== "id_token", "39232932927");
37
+ return `${tokenType}_placeholder_${id}`;
38
+ }
39
+
40
+ const [, header_b64, payload_b64, signature_b64] = match;
41
+
42
+ const signatureByteLength = (() => {
43
+ const b64 = signature_b64
44
+ .replace(/-/g, "+")
45
+ .replace(/_/g, "/")
46
+ .padEnd(Math.ceil(signature_b64.length / 4) * 4, "=");
47
+
48
+ const padding = b64.endsWith("==") ? 2 : b64.endsWith("=") ? 1 : 0;
49
+ return (b64.length * 3) / 4 - padding;
50
+ })();
51
+
52
+ const targetSigB64Length = Math.ceil((signatureByteLength * 4) / 3);
53
+
54
+ const sig_placeholder = (function makeZeroPaddedBase64UrlString(
55
+ targetLength: number,
56
+ seed: string
57
+ ): string {
58
+ const PAD = "A";
59
+
60
+ let out = seed.slice(0, targetLength);
61
+
62
+ if (out.length < targetLength) {
63
+ out = out + PAD.repeat(targetLength - out.length);
64
+ }
65
+
66
+ if (out.length % 4 === 1) {
67
+ out = out.slice(0, -1) + PAD;
68
+ }
69
+
70
+ return out;
71
+ })(targetSigB64Length, `sig_placeholder_${id}_`);
72
+
73
+ return `${header_b64}.${payload_b64}.${sig_placeholder}`;
74
+ }
75
+
25
76
  let counter = Math.floor(Math.random() * 1_000_000) + 1_000_000;
26
77
 
27
78
  export function getTokensPlaceholders(params: { configId: string; tokens: Tokens }): Tokens {
@@ -48,66 +99,68 @@ export function getTokensPlaceholders(params: { configId: string; tokens: Tokens
48
99
  const id = counter++;
49
100
 
50
101
  const entry_new: (typeof entries)[number] = {
51
- id,
52
102
  configId,
103
+ id,
53
104
  tokens: {
54
- accessToken: tokens.accessToken,
55
105
  idToken: tokens.idToken,
106
+ accessToken: tokens.accessToken,
56
107
  refreshToken: tokens.refreshToken
108
+ },
109
+ tokens_placeholder: {
110
+ idToken: generatePlaceholderForToken({
111
+ tokenType: "id_token",
112
+ id,
113
+ token_real: tokens.idToken
114
+ }),
115
+ accessToken: generatePlaceholderForToken({
116
+ tokenType: "access_token",
117
+ id,
118
+ token_real: tokens.accessToken
119
+ }),
120
+ refreshToken:
121
+ tokens.refreshToken === undefined
122
+ ? undefined
123
+ : generatePlaceholderForToken({
124
+ tokenType: "refresh_token",
125
+ id,
126
+ token_real: tokens.refreshToken
127
+ })
57
128
  }
58
129
  };
59
130
 
60
131
  entries.push(entry_new);
61
132
 
62
- return {
63
- accessToken: `access_token_placeholder_${id}`,
64
- idToken: `id_token_placeholder_${id}`,
65
- refreshToken: tokens.refreshToken === undefined ? undefined : `refresh_token_placeholder_${id}`
66
- };
133
+ return entry_new.tokens_placeholder;
67
134
  }
68
135
 
69
- export function substitutePlaceholderByRealToken(params: {
70
- text: string;
71
- doEncodeUriComponent: boolean;
72
- }): string {
73
- const { text, doEncodeUriComponent } = params;
136
+ export function substitutePlaceholderByRealToken(text: string): string {
137
+ if (!text.includes("_placeholder_")) {
138
+ return text;
139
+ }
74
140
 
75
141
  let text_modified = text;
76
142
 
77
- for (const [tokenType, regExp] of [
78
- ["access_token", /access_token_placeholder_(\d+)/g],
79
- ["id_token", /id_token_placeholder_(\d+)/g],
80
- ["refresh_token", /refresh_token_placeholder_(\d+)/g]
81
- ] as const) {
82
- text_modified = text_modified.replace(regExp, (...[, p1]) => {
83
- const id = parseInt(p1);
84
-
85
- const entry = entries.find(e => e.id === id);
86
-
87
- if (!entry) {
88
- throw new Error(
89
- [
90
- "oidc-spa: Outdated token used to make a request.",
91
- "Token should not be stored at the application level, when a token",
92
- "is needed, it should be requested and used immediately."
93
- ].join(" ")
94
- );
95
- }
143
+ for (const entry of entries) {
144
+ if (!text.includes(`${entry.id}`)) {
145
+ continue;
146
+ }
147
+
148
+ for (const tokenType of ["idToken", "accessToken", "refreshToken"] as const) {
149
+ const placeholder = entry.tokens_placeholder[tokenType];
96
150
 
97
- const token = (() => {
98
- switch (tokenType) {
99
- case "access_token":
100
- return entry.tokens.accessToken;
101
- case "id_token":
102
- return entry.tokens.idToken;
103
- case "refresh_token":
104
- assert(entry.tokens.refreshToken !== undefined, "204392284");
105
- return entry.tokens.refreshToken;
151
+ if (tokenType === "refreshToken") {
152
+ if (placeholder === undefined) {
153
+ continue;
106
154
  }
107
- })();
155
+ }
156
+ assert(placeholder !== undefined, "023948092393");
157
+
158
+ const realToken = entry.tokens[tokenType];
108
159
 
109
- return doEncodeUriComponent ? encodeURIComponent(token) : token;
110
- });
160
+ assert(realToken !== undefined, "02394809239328");
161
+
162
+ text_modified = text_modified.split(placeholder).join(realToken);
163
+ }
111
164
  }
112
165
 
113
166
  return text_modified;