@azure/core-rest-pipeline 1.17.1-alpha.20241031.2 → 1.17.1-alpha.20241111.2

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 CHANGED
@@ -32,7 +32,9 @@ A `PipelineResponse` describes the HTTP response (body, headers, and status code
32
32
  A `SendRequest` method is a method that given a `PipelineRequest` can asynchronously return a `PipelineResponse`.
33
33
 
34
34
  ```ts snippet:send_request
35
- export type SendRequest = (request: PipelineRequest) => Promise<PipelineResponse>;
35
+ import { PipelineRequest, PipelineResponse } from "@azure/core-rest-pipeline";
36
+
37
+ type SendRequest = (request: PipelineRequest) => Promise<PipelineResponse>;
36
38
  ```
37
39
 
38
40
  ### HttpClient
@@ -40,7 +42,9 @@ export type SendRequest = (request: PipelineRequest) => Promise<PipelineResponse
40
42
  An `HttpClient` is any object that satisfies the following interface to implement a `SendRequest` method:
41
43
 
42
44
  ```ts snippet:http_request
43
- export interface HttpClient {
45
+ import { SendRequest } from "@azure/core-rest-pipeline";
46
+
47
+ interface HttpClient {
44
48
  /**
45
49
  * The method that makes the request and returns a response.
46
50
  */
@@ -55,7 +59,9 @@ export interface HttpClient {
55
59
  A `PipelinePolicy` is a simple object that implements the following interface:
56
60
 
57
61
  ```ts snippet:pipeline_policy
58
- export interface PipelinePolicy {
62
+ import { PipelineRequest, SendRequest, PipelineResponse } from "@azure/core-rest-pipeline";
63
+
64
+ interface PipelinePolicy {
59
65
  /**
60
66
  * The policy name. Must be a unique string in the pipeline.
61
67
  */
@@ -76,13 +82,15 @@ One can view the role of policies as that of `middleware`, a concept that is fam
76
82
  The `sendRequest` implementation can both transform the outgoing request as well as the incoming response:
77
83
 
78
84
  ```ts snippet:custom_policy
85
+ import { PipelineRequest, SendRequest, PipelineResponse } from "@azure/core-rest-pipeline";
86
+
79
87
  const customPolicy = {
80
88
  name: "My wonderful policy",
81
89
  async sendRequest(request: PipelineRequest, next: SendRequest): Promise<PipelineResponse> {
82
90
  // Change the outgoing request by adding a new header
83
91
  request.headers.set("X-Cool-Header", 42);
84
92
  const result = await next(request);
85
- if (response.status === 403) {
93
+ if (result.status === 403) {
86
94
  // Do something special if this policy sees Forbidden
87
95
  }
88
96
  return result;
@@ -101,8 +109,17 @@ You can think of policies being applied like a stack (first-in/last-out.) The fi
101
109
  A `Pipeline` satisfies the following interface:
102
110
 
103
111
  ```ts snippet:pipeline
104
- export interface Pipeline {
105
- addPolicy(policy: PipelinePolicy, options?: AddPolicyOptions): void;
112
+ import {
113
+ PipelinePolicy,
114
+ AddPipelineOptions,
115
+ PipelinePhase,
116
+ HttpClient,
117
+ PipelineRequest,
118
+ PipelineResponse,
119
+ } from "@azure/core-rest-pipeline";
120
+
121
+ interface Pipeline {
122
+ addPolicy(policy: PipelinePolicy, options?: AddPipelineOptions): void;
106
123
  removePolicy(options: { name?: string; phase?: PipelinePhase }): PipelinePolicy[];
107
124
  sendRequest(httpClient: HttpClient, request: PipelineRequest): Promise<PipelineResponse>;
108
125
  getOrderedPolicies(): PipelinePolicy[];
@@ -124,7 +141,9 @@ Phases occur in the above order, with serialization policies being applied first
124
141
  When adding a policy to the pipeline you can specify not only what phase a policy is in, but also if it has any dependencies:
125
142
 
126
143
  ```ts snippet:add_policy_options
127
- export interface AddPolicyOptions {
144
+ import { PipelinePhase } from "@azure/core-rest-pipeline";
145
+
146
+ interface AddPipelineOptions {
128
147
  beforePolicies?: string[];
129
148
  afterPolicies?: string[];
130
149
  afterPhase?: PipelinePhase;
@@ -96,4 +96,22 @@ export interface BearerTokenAuthenticationPolicyOptions {
96
96
  * then apply it to the Authorization header of a request as a Bearer token.
97
97
  */
98
98
  export declare function bearerTokenAuthenticationPolicy(options: BearerTokenAuthenticationPolicyOptions): PipelinePolicy;
99
+ /**
100
+ *
101
+ * Interface to represent a parsed challenge.
102
+ *
103
+ * @internal
104
+ */
105
+ interface AuthChallenge {
106
+ scheme: string;
107
+ params: Record<string, string>;
108
+ }
109
+ /**
110
+ * Converts: `Bearer a="b", c="d", Pop e="f", g="h"`.
111
+ * Into: `[ { scheme: 'Bearer', params: { a: 'b', c: 'd' } }, { scheme: 'Pop', params: { e: 'f', g: 'h' } } ]`.
112
+ *
113
+ * @internal
114
+ */
115
+ export declare function parseChallenges(challenges: string): AuthChallenge[];
116
+ export {};
99
117
  //# sourceMappingURL=bearerTokenAuthenticationPolicy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bearerTokenAuthenticationPolicy.d.ts","sourceRoot":"","sources":["../../../src/policies/bearerTokenAuthenticationPolicy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACtF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAe,MAAM,kBAAkB,CAAC;AACvF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAIrD;;GAEG;AACH,eAAO,MAAM,mCAAmC,oCAAoC,CAAC;AAErF;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB;;OAEG;IACH,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC5F;;OAEG;IACH,OAAO,EAAE,eAAe,CAAC;IACzB;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,kCAAkC;IACjD;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB;;OAEG;IACH,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC5F;;OAEG;IACH,OAAO,EAAE,eAAe,CAAC;IACzB;;OAEG;IACH,QAAQ,EAAE,gBAAgB,CAAC;IAC3B;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,gBAAgB,CAAC,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE;;;;;OAKG;IACH,2BAA2B,CAAC,CAAC,OAAO,EAAE,kCAAkC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7F;AAED;;GAEG;AACH,MAAM,WAAW,sCAAsC;IACrD;;OAEG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B;;OAEG;IACH,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AA8BD;;;GAGG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,sCAAsC,GAC9C,cAAc,CAkFhB"}
1
+ {"version":3,"file":"bearerTokenAuthenticationPolicy.d.ts","sourceRoot":"","sources":["../../../src/policies/bearerTokenAuthenticationPolicy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACtF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAe,MAAM,kBAAkB,CAAC;AACvF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKrD;;GAEG;AACH,eAAO,MAAM,mCAAmC,oCAAoC,CAAC;AAErF;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB;;OAEG;IACH,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC5F;;OAEG;IACH,OAAO,EAAE,eAAe,CAAC;IACzB;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,kCAAkC;IACjD;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB;;OAEG;IACH,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC5F;;OAEG;IACH,OAAO,EAAE,eAAe,CAAC;IACzB;;OAEG;IACH,QAAQ,EAAE,gBAAgB,CAAC;IAC3B;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,gBAAgB,CAAC,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE;;;;;OAKG;IACH,2BAA2B,CAAC,CAAC,OAAO,EAAE,kCAAkC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7F;AAED;;GAEG;AACH,MAAM,WAAW,sCAAsC;IACrD;;OAEG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B;;OAEG;IACH,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AA6ED;;;GAGG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,sCAAsC,GAC9C,cAAc,CAqIhB;AAED;;;;;GAKG;AACH,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,EAAE,CA0BnE"}
@@ -2,18 +2,43 @@
2
2
  // Licensed under the MIT License.
3
3
  import { createTokenCycler } from "../util/tokenCycler.js";
4
4
  import { logger as coreLogger } from "../log.js";
5
+ import { isRestError } from "../restError.js";
5
6
  /**
6
7
  * The programmatic identifier of the bearerTokenAuthenticationPolicy.
7
8
  */
8
9
  export const bearerTokenAuthenticationPolicyName = "bearerTokenAuthenticationPolicy";
10
+ /**
11
+ * Try to send the given request.
12
+ *
13
+ * When a response is received, returns a tuple of the response received and, if the response was received
14
+ * inside a thrown RestError, the RestError that was thrown.
15
+ *
16
+ * Otherwise, if an error was thrown while sending the request that did not provide an underlying response, it
17
+ * will be rethrown.
18
+ */
19
+ async function trySendRequest(request, next) {
20
+ try {
21
+ return [await next(request), undefined];
22
+ }
23
+ catch (e) {
24
+ if (isRestError(e) && e.response) {
25
+ return [e.response, e];
26
+ }
27
+ else {
28
+ throw e;
29
+ }
30
+ }
31
+ }
9
32
  /**
10
33
  * Default authorize request handler
11
34
  */
12
35
  async function defaultAuthorizeRequest(options) {
13
36
  const { scopes, getAccessToken, request } = options;
37
+ // Enable CAE true by default
14
38
  const getTokenOptions = {
15
39
  abortSignal: request.abortSignal,
16
40
  tracingOptions: request.tracingOptions,
41
+ enableCae: true,
17
42
  };
18
43
  const accessToken = await getAccessToken(scopes, getTokenOptions);
19
44
  if (accessToken) {
@@ -24,12 +49,26 @@ async function defaultAuthorizeRequest(options) {
24
49
  * We will retrieve the challenge only if the response status code was 401,
25
50
  * and if the response contained the header "WWW-Authenticate" with a non-empty value.
26
51
  */
27
- function getChallenge(response) {
28
- const challenge = response.headers.get("WWW-Authenticate");
29
- if (response.status === 401 && challenge) {
30
- return challenge;
52
+ function isChallengeResponse(response) {
53
+ return response.status === 401 && response.headers.has("WWW-Authenticate");
54
+ }
55
+ /**
56
+ * Re-authorize the request for CAE challenge.
57
+ * The response containing the challenge is `options.response`.
58
+ * If this method returns true, the underlying request will be sent once again.
59
+ */
60
+ async function authorizeRequestOnCaeChallenge(onChallengeOptions, caeClaims) {
61
+ var _a;
62
+ const { scopes } = onChallengeOptions;
63
+ const accessToken = await onChallengeOptions.getAccessToken(scopes, {
64
+ enableCae: true,
65
+ claims: caeClaims,
66
+ });
67
+ if (!accessToken) {
68
+ return false;
31
69
  }
32
- return;
70
+ onChallengeOptions.request.headers.set("Authorization", `${(_a = accessToken.tokenType) !== null && _a !== void 0 ? _a : "Bearer"} ${accessToken.token}`);
71
+ return true;
33
72
  }
34
73
  /**
35
74
  * A policy that can request a token from a TokenCredential implementation and
@@ -39,7 +78,10 @@ export function bearerTokenAuthenticationPolicy(options) {
39
78
  var _a;
40
79
  const { credential, scopes, challengeCallbacks } = options;
41
80
  const logger = options.logger || coreLogger;
42
- const callbacks = Object.assign({ authorizeRequest: (_a = challengeCallbacks === null || challengeCallbacks === void 0 ? void 0 : challengeCallbacks.authorizeRequest) !== null && _a !== void 0 ? _a : defaultAuthorizeRequest, authorizeRequestOnChallenge: challengeCallbacks === null || challengeCallbacks === void 0 ? void 0 : challengeCallbacks.authorizeRequestOnChallenge }, challengeCallbacks);
81
+ const callbacks = {
82
+ authorizeRequest: (_a = challengeCallbacks === null || challengeCallbacks === void 0 ? void 0 : challengeCallbacks.authorizeRequest) !== null && _a !== void 0 ? _a : defaultAuthorizeRequest,
83
+ authorizeRequestOnChallenge: challengeCallbacks === null || challengeCallbacks === void 0 ? void 0 : challengeCallbacks.authorizeRequestOnChallenge,
84
+ };
43
85
  // This function encapsulates the entire process of reliably retrieving the token
44
86
  // The options are left out of the public API until there's demand to configure this.
45
87
  // Remember to extend `BearerTokenAuthenticationPolicyOptions` with `TokenCyclerOptions`
@@ -74,26 +116,71 @@ export function bearerTokenAuthenticationPolicy(options) {
74
116
  });
75
117
  let response;
76
118
  let error;
77
- try {
78
- response = await next(request);
79
- }
80
- catch (err) {
81
- error = err;
82
- response = err.response;
83
- }
84
- if (callbacks.authorizeRequestOnChallenge &&
85
- (response === null || response === void 0 ? void 0 : response.status) === 401 &&
86
- getChallenge(response)) {
87
- // processes challenge
88
- const shouldSendRequest = await callbacks.authorizeRequestOnChallenge({
89
- scopes: Array.isArray(scopes) ? scopes : [scopes],
90
- request,
91
- response,
92
- getAccessToken,
93
- logger,
94
- });
95
- if (shouldSendRequest) {
96
- return next(request);
119
+ let shouldSendRequest;
120
+ [response, error] = await trySendRequest(request, next);
121
+ if (isChallengeResponse(response)) {
122
+ let claims = getCaeChallengeClaims(response.headers.get("WWW-Authenticate"));
123
+ // Handle CAE by default when receive CAE claim
124
+ if (claims) {
125
+ let parsedClaim;
126
+ // Return the response immediately if claims is not a valid base64 encoded string
127
+ try {
128
+ parsedClaim = atob(claims);
129
+ }
130
+ catch (e) {
131
+ logger.warning(`The WWW-Authenticate header contains "claims" that cannot be parsed. Unable to perform the Continuous Access Evaluation authentication flow. Unparsable claims: ${claims}`);
132
+ return response;
133
+ }
134
+ shouldSendRequest = await authorizeRequestOnCaeChallenge({
135
+ scopes: Array.isArray(scopes) ? scopes : [scopes],
136
+ response,
137
+ request,
138
+ getAccessToken,
139
+ logger,
140
+ }, parsedClaim);
141
+ // Send updated request and handle response for RestError
142
+ if (shouldSendRequest) {
143
+ [response, error] = await trySendRequest(request, next);
144
+ }
145
+ }
146
+ else if (callbacks.authorizeRequestOnChallenge) {
147
+ // Handle custom challenges when client provides custom callback
148
+ shouldSendRequest = await callbacks.authorizeRequestOnChallenge({
149
+ scopes: Array.isArray(scopes) ? scopes : [scopes],
150
+ request,
151
+ response,
152
+ getAccessToken,
153
+ logger,
154
+ });
155
+ // Send updated request and handle response for RestError
156
+ if (shouldSendRequest) {
157
+ [response, error] = await trySendRequest(request, next);
158
+ }
159
+ // If we get another CAE Claim, we will handle it by default and return whatever value we receive for this
160
+ if (isChallengeResponse(response)) {
161
+ claims = getCaeChallengeClaims(response.headers.get("WWW-Authenticate"));
162
+ if (claims) {
163
+ let parsedClaim;
164
+ try {
165
+ parsedClaim = atob(claims);
166
+ }
167
+ catch (e) {
168
+ logger.warning(`The WWW-Authenticate header contains "claims" that cannot be parsed. Unable to perform the Continuous Access Evaluation authentication flow. Unparsable claims: ${claims}`);
169
+ return response;
170
+ }
171
+ shouldSendRequest = await authorizeRequestOnCaeChallenge({
172
+ scopes: Array.isArray(scopes) ? scopes : [scopes],
173
+ response,
174
+ request,
175
+ getAccessToken,
176
+ logger,
177
+ }, parsedClaim);
178
+ // Send updated request and handle response for RestError
179
+ if (shouldSendRequest) {
180
+ [response, error] = await trySendRequest(request, next);
181
+ }
182
+ }
183
+ }
97
184
  }
98
185
  }
99
186
  if (error) {
@@ -105,4 +192,47 @@ export function bearerTokenAuthenticationPolicy(options) {
105
192
  },
106
193
  };
107
194
  }
195
+ /**
196
+ * Converts: `Bearer a="b", c="d", Pop e="f", g="h"`.
197
+ * Into: `[ { scheme: 'Bearer', params: { a: 'b', c: 'd' } }, { scheme: 'Pop', params: { e: 'f', g: 'h' } } ]`.
198
+ *
199
+ * @internal
200
+ */
201
+ export function parseChallenges(challenges) {
202
+ // Challenge regex seperates the string to individual challenges with different schemes in the format `Scheme a="b", c=d`
203
+ // The challenge regex captures parameteres with either quotes values or unquoted values
204
+ const challengeRegex = /(\w+)\s+((?:\w+=(?:"[^"]*"|[^,]*),?\s*)+)/g;
205
+ // Parameter regex captures the claims group removed from the scheme in the format `a="b"` and `c="d"`
206
+ // CAE challenge always have quoted parameters. For more reference, https://learn.microsoft.com/entra/identity-platform/claims-challenge
207
+ const paramRegex = /(\w+)="([^"]*)"/g;
208
+ const parsedChallenges = [];
209
+ let match;
210
+ // Iterate over each challenge match
211
+ while ((match = challengeRegex.exec(challenges)) !== null) {
212
+ const scheme = match[1];
213
+ const paramsString = match[2];
214
+ const params = {};
215
+ let paramMatch;
216
+ // Iterate over each parameter match
217
+ while ((paramMatch = paramRegex.exec(paramsString)) !== null) {
218
+ params[paramMatch[1]] = paramMatch[2];
219
+ }
220
+ parsedChallenges.push({ scheme, params });
221
+ }
222
+ return parsedChallenges;
223
+ }
224
+ /**
225
+ * Parse a pipeline response and look for a CAE challenge with "Bearer" scheme
226
+ * Return the value in the header without parsing the challenge
227
+ * @internal
228
+ */
229
+ function getCaeChallengeClaims(challenges) {
230
+ var _a;
231
+ if (!challenges) {
232
+ return;
233
+ }
234
+ // Find all challenges present in the header
235
+ const parsedChallenges = parseChallenges(challenges);
236
+ return (_a = parsedChallenges.find((x) => x.scheme === "Bearer" && x.params.claims && x.params.error === "insufficient_claims")) === null || _a === void 0 ? void 0 : _a.params.claims;
237
+ }
108
238
  //# sourceMappingURL=bearerTokenAuthenticationPolicy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bearerTokenAuthenticationPolicy.js","sourceRoot":"","sources":["../../../src/policies/bearerTokenAuthenticationPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AccessToken, GetTokenOptions, TokenCredential } from \"@azure/core-auth\";\nimport type { AzureLogger } from \"@azure/logger\";\nimport type { PipelineRequest, PipelineResponse, SendRequest } from \"../interfaces.js\";\nimport type { PipelinePolicy } from \"../pipeline.js\";\nimport { createTokenCycler } from \"../util/tokenCycler.js\";\nimport { logger as coreLogger } from \"../log.js\";\n\n/**\n * The programmatic identifier of the bearerTokenAuthenticationPolicy.\n */\nexport const bearerTokenAuthenticationPolicyName = \"bearerTokenAuthenticationPolicy\";\n\n/**\n * Options sent to the authorizeRequest callback\n */\nexport interface AuthorizeRequestOptions {\n /**\n * The scopes for which the bearer token applies.\n */\n scopes: string[];\n /**\n * Function that retrieves either a cached access token or a new access token.\n */\n getAccessToken: (scopes: string[], options: GetTokenOptions) => Promise<AccessToken | null>;\n /**\n * Request that the policy is trying to fulfill.\n */\n request: PipelineRequest;\n /**\n * A logger, if one was sent through the HTTP pipeline.\n */\n logger?: AzureLogger;\n}\n\n/**\n * Options sent to the authorizeRequestOnChallenge callback\n */\nexport interface AuthorizeRequestOnChallengeOptions {\n /**\n * The scopes for which the bearer token applies.\n */\n scopes: string[];\n /**\n * Function that retrieves either a cached access token or a new access token.\n */\n getAccessToken: (scopes: string[], options: GetTokenOptions) => Promise<AccessToken | null>;\n /**\n * Request that the policy is trying to fulfill.\n */\n request: PipelineRequest;\n /**\n * Response containing the challenge.\n */\n response: PipelineResponse;\n /**\n * A logger, if one was sent through the HTTP pipeline.\n */\n logger?: AzureLogger;\n}\n\n/**\n * Options to override the processing of [Continuous Access Evaluation](https://docs.microsoft.com/azure/active-directory/conditional-access/concept-continuous-access-evaluation) challenges.\n */\nexport interface ChallengeCallbacks {\n /**\n * Allows for the authorization of the main request of this policy before it's sent.\n */\n authorizeRequest?(options: AuthorizeRequestOptions): Promise<void>;\n /**\n * Allows to handle authentication challenges and to re-authorize the request.\n * The response containing the challenge is `options.response`.\n * If this method returns true, the underlying request will be sent once again.\n * The request may be modified before being sent.\n */\n authorizeRequestOnChallenge?(options: AuthorizeRequestOnChallengeOptions): Promise<boolean>;\n}\n\n/**\n * Options to configure the bearerTokenAuthenticationPolicy\n */\nexport interface BearerTokenAuthenticationPolicyOptions {\n /**\n * The TokenCredential implementation that can supply the bearer token.\n */\n credential?: TokenCredential;\n /**\n * The scopes for which the bearer token applies.\n */\n scopes: string | string[];\n /**\n * Allows for the processing of [Continuous Access Evaluation](https://docs.microsoft.com/azure/active-directory/conditional-access/concept-continuous-access-evaluation) challenges.\n * If provided, it must contain at least the `authorizeRequestOnChallenge` method.\n * If provided, after a request is sent, if it has a challenge, it can be processed to re-send the original request with the relevant challenge information.\n */\n challengeCallbacks?: ChallengeCallbacks;\n /**\n * A logger can be sent for debugging purposes.\n */\n logger?: AzureLogger;\n}\n\n/**\n * Default authorize request handler\n */\nasync function defaultAuthorizeRequest(options: AuthorizeRequestOptions): Promise<void> {\n const { scopes, getAccessToken, request } = options;\n const getTokenOptions: GetTokenOptions = {\n abortSignal: request.abortSignal,\n tracingOptions: request.tracingOptions,\n };\n const accessToken = await getAccessToken(scopes, getTokenOptions);\n\n if (accessToken) {\n options.request.headers.set(\"Authorization\", `Bearer ${accessToken.token}`);\n }\n}\n\n/**\n * We will retrieve the challenge only if the response status code was 401,\n * and if the response contained the header \"WWW-Authenticate\" with a non-empty value.\n */\nfunction getChallenge(response: PipelineResponse): string | undefined {\n const challenge = response.headers.get(\"WWW-Authenticate\");\n if (response.status === 401 && challenge) {\n return challenge;\n }\n return;\n}\n\n/**\n * A policy that can request a token from a TokenCredential implementation and\n * then apply it to the Authorization header of a request as a Bearer token.\n */\nexport function bearerTokenAuthenticationPolicy(\n options: BearerTokenAuthenticationPolicyOptions,\n): PipelinePolicy {\n const { credential, scopes, challengeCallbacks } = options;\n const logger = options.logger || coreLogger;\n const callbacks = {\n authorizeRequest: challengeCallbacks?.authorizeRequest ?? defaultAuthorizeRequest,\n authorizeRequestOnChallenge: challengeCallbacks?.authorizeRequestOnChallenge,\n // keep all other properties\n ...challengeCallbacks,\n };\n\n // This function encapsulates the entire process of reliably retrieving the token\n // The options are left out of the public API until there's demand to configure this.\n // Remember to extend `BearerTokenAuthenticationPolicyOptions` with `TokenCyclerOptions`\n // in order to pass through the `options` object.\n const getAccessToken = credential\n ? createTokenCycler(credential /* , options */)\n : () => Promise.resolve(null);\n\n return {\n name: bearerTokenAuthenticationPolicyName,\n /**\n * If there's no challenge parameter:\n * - It will try to retrieve the token using the cache, or the credential's getToken.\n * - Then it will try the next policy with or without the retrieved token.\n *\n * It uses the challenge parameters to:\n * - Skip a first attempt to get the token from the credential if there's no cached token,\n * since it expects the token to be retrievable only after the challenge.\n * - Prepare the outgoing request if the `prepareRequest` method has been provided.\n * - Send an initial request to receive the challenge if it fails.\n * - Process a challenge if the response contains it.\n * - Retrieve a token with the challenge information, then re-send the request.\n */\n async sendRequest(request: PipelineRequest, next: SendRequest): Promise<PipelineResponse> {\n if (!request.url.toLowerCase().startsWith(\"https://\")) {\n throw new Error(\n \"Bearer token authentication is not permitted for non-TLS protected (non-https) URLs.\",\n );\n }\n\n await callbacks.authorizeRequest({\n scopes: Array.isArray(scopes) ? scopes : [scopes],\n request,\n getAccessToken,\n logger,\n });\n\n let response: PipelineResponse;\n let error: Error | undefined;\n try {\n response = await next(request);\n } catch (err: any) {\n error = err;\n response = err.response;\n }\n\n if (\n callbacks.authorizeRequestOnChallenge &&\n response?.status === 401 &&\n getChallenge(response)\n ) {\n // processes challenge\n const shouldSendRequest = await callbacks.authorizeRequestOnChallenge({\n scopes: Array.isArray(scopes) ? scopes : [scopes],\n request,\n response,\n getAccessToken,\n logger,\n });\n\n if (shouldSendRequest) {\n return next(request);\n }\n }\n\n if (error) {\n throw error;\n } else {\n return response;\n }\n },\n };\n}\n"]}
1
+ {"version":3,"file":"bearerTokenAuthenticationPolicy.js","sourceRoot":"","sources":["../../../src/policies/bearerTokenAuthenticationPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AccessToken, GetTokenOptions, TokenCredential } from \"@azure/core-auth\";\nimport type { AzureLogger } from \"@azure/logger\";\nimport type { PipelineRequest, PipelineResponse, SendRequest } from \"../interfaces.js\";\nimport type { PipelinePolicy } from \"../pipeline.js\";\nimport { createTokenCycler } from \"../util/tokenCycler.js\";\nimport { logger as coreLogger } from \"../log.js\";\nimport { isRestError, RestError } from \"../restError.js\";\n\n/**\n * The programmatic identifier of the bearerTokenAuthenticationPolicy.\n */\nexport const bearerTokenAuthenticationPolicyName = \"bearerTokenAuthenticationPolicy\";\n\n/**\n * Options sent to the authorizeRequest callback\n */\nexport interface AuthorizeRequestOptions {\n /**\n * The scopes for which the bearer token applies.\n */\n scopes: string[];\n /**\n * Function that retrieves either a cached access token or a new access token.\n */\n getAccessToken: (scopes: string[], options: GetTokenOptions) => Promise<AccessToken | null>;\n /**\n * Request that the policy is trying to fulfill.\n */\n request: PipelineRequest;\n /**\n * A logger, if one was sent through the HTTP pipeline.\n */\n logger?: AzureLogger;\n}\n\n/**\n * Options sent to the authorizeRequestOnChallenge callback\n */\nexport interface AuthorizeRequestOnChallengeOptions {\n /**\n * The scopes for which the bearer token applies.\n */\n scopes: string[];\n /**\n * Function that retrieves either a cached access token or a new access token.\n */\n getAccessToken: (scopes: string[], options: GetTokenOptions) => Promise<AccessToken | null>;\n /**\n * Request that the policy is trying to fulfill.\n */\n request: PipelineRequest;\n /**\n * Response containing the challenge.\n */\n response: PipelineResponse;\n /**\n * A logger, if one was sent through the HTTP pipeline.\n */\n logger?: AzureLogger;\n}\n\n/**\n * Options to override the processing of [Continuous Access Evaluation](https://docs.microsoft.com/azure/active-directory/conditional-access/concept-continuous-access-evaluation) challenges.\n */\nexport interface ChallengeCallbacks {\n /**\n * Allows for the authorization of the main request of this policy before it's sent.\n */\n authorizeRequest?(options: AuthorizeRequestOptions): Promise<void>;\n /**\n * Allows to handle authentication challenges and to re-authorize the request.\n * The response containing the challenge is `options.response`.\n * If this method returns true, the underlying request will be sent once again.\n * The request may be modified before being sent.\n */\n authorizeRequestOnChallenge?(options: AuthorizeRequestOnChallengeOptions): Promise<boolean>;\n}\n\n/**\n * Options to configure the bearerTokenAuthenticationPolicy\n */\nexport interface BearerTokenAuthenticationPolicyOptions {\n /**\n * The TokenCredential implementation that can supply the bearer token.\n */\n credential?: TokenCredential;\n /**\n * The scopes for which the bearer token applies.\n */\n scopes: string | string[];\n /**\n * Allows for the processing of [Continuous Access Evaluation](https://docs.microsoft.com/azure/active-directory/conditional-access/concept-continuous-access-evaluation) challenges.\n * If provided, it must contain at least the `authorizeRequestOnChallenge` method.\n * If provided, after a request is sent, if it has a challenge, it can be processed to re-send the original request with the relevant challenge information.\n */\n challengeCallbacks?: ChallengeCallbacks;\n /**\n * A logger can be sent for debugging purposes.\n */\n logger?: AzureLogger;\n}\n/**\n * Try to send the given request.\n *\n * When a response is received, returns a tuple of the response received and, if the response was received\n * inside a thrown RestError, the RestError that was thrown.\n *\n * Otherwise, if an error was thrown while sending the request that did not provide an underlying response, it\n * will be rethrown.\n */\nasync function trySendRequest(\n request: PipelineRequest,\n next: SendRequest,\n): Promise<[PipelineResponse, RestError | undefined]> {\n try {\n return [await next(request), undefined];\n } catch (e: any) {\n if (isRestError(e) && e.response) {\n return [e.response, e];\n } else {\n throw e;\n }\n }\n}\n/**\n * Default authorize request handler\n */\nasync function defaultAuthorizeRequest(options: AuthorizeRequestOptions): Promise<void> {\n const { scopes, getAccessToken, request } = options;\n // Enable CAE true by default\n const getTokenOptions: GetTokenOptions = {\n abortSignal: request.abortSignal,\n tracingOptions: request.tracingOptions,\n enableCae: true,\n };\n\n const accessToken = await getAccessToken(scopes, getTokenOptions);\n\n if (accessToken) {\n options.request.headers.set(\"Authorization\", `Bearer ${accessToken.token}`);\n }\n}\n\n/**\n * We will retrieve the challenge only if the response status code was 401,\n * and if the response contained the header \"WWW-Authenticate\" with a non-empty value.\n */\nfunction isChallengeResponse(response: PipelineResponse): boolean {\n return response.status === 401 && response.headers.has(\"WWW-Authenticate\");\n}\n\n/**\n * Re-authorize the request for CAE challenge.\n * The response containing the challenge is `options.response`.\n * If this method returns true, the underlying request will be sent once again.\n */\nasync function authorizeRequestOnCaeChallenge(\n onChallengeOptions: AuthorizeRequestOnChallengeOptions,\n caeClaims: string,\n): Promise<boolean> {\n const { scopes } = onChallengeOptions;\n\n const accessToken = await onChallengeOptions.getAccessToken(scopes, {\n enableCae: true,\n claims: caeClaims,\n });\n if (!accessToken) {\n return false;\n }\n\n onChallengeOptions.request.headers.set(\n \"Authorization\",\n `${accessToken.tokenType ?? \"Bearer\"} ${accessToken.token}`,\n );\n return true;\n}\n\n/**\n * A policy that can request a token from a TokenCredential implementation and\n * then apply it to the Authorization header of a request as a Bearer token.\n */\nexport function bearerTokenAuthenticationPolicy(\n options: BearerTokenAuthenticationPolicyOptions,\n): PipelinePolicy {\n const { credential, scopes, challengeCallbacks } = options;\n const logger = options.logger || coreLogger;\n const callbacks = {\n authorizeRequest: challengeCallbacks?.authorizeRequest ?? defaultAuthorizeRequest,\n authorizeRequestOnChallenge: challengeCallbacks?.authorizeRequestOnChallenge,\n };\n\n // This function encapsulates the entire process of reliably retrieving the token\n // The options are left out of the public API until there's demand to configure this.\n // Remember to extend `BearerTokenAuthenticationPolicyOptions` with `TokenCyclerOptions`\n // in order to pass through the `options` object.\n const getAccessToken = credential\n ? createTokenCycler(credential /* , options */)\n : () => Promise.resolve(null);\n\n return {\n name: bearerTokenAuthenticationPolicyName,\n /**\n * If there's no challenge parameter:\n * - It will try to retrieve the token using the cache, or the credential's getToken.\n * - Then it will try the next policy with or without the retrieved token.\n *\n * It uses the challenge parameters to:\n * - Skip a first attempt to get the token from the credential if there's no cached token,\n * since it expects the token to be retrievable only after the challenge.\n * - Prepare the outgoing request if the `prepareRequest` method has been provided.\n * - Send an initial request to receive the challenge if it fails.\n * - Process a challenge if the response contains it.\n * - Retrieve a token with the challenge information, then re-send the request.\n */\n async sendRequest(request: PipelineRequest, next: SendRequest): Promise<PipelineResponse> {\n if (!request.url.toLowerCase().startsWith(\"https://\")) {\n throw new Error(\n \"Bearer token authentication is not permitted for non-TLS protected (non-https) URLs.\",\n );\n }\n\n await callbacks.authorizeRequest({\n scopes: Array.isArray(scopes) ? scopes : [scopes],\n request,\n getAccessToken,\n logger,\n });\n\n let response: PipelineResponse;\n let error: Error | undefined;\n let shouldSendRequest: boolean;\n [response, error] = await trySendRequest(request, next);\n\n if (isChallengeResponse(response)) {\n let claims = getCaeChallengeClaims(response.headers.get(\"WWW-Authenticate\"));\n // Handle CAE by default when receive CAE claim\n if (claims) {\n let parsedClaim: string;\n // Return the response immediately if claims is not a valid base64 encoded string\n try {\n parsedClaim = atob(claims);\n } catch (e) {\n logger.warning(\n `The WWW-Authenticate header contains \"claims\" that cannot be parsed. Unable to perform the Continuous Access Evaluation authentication flow. Unparsable claims: ${claims}`,\n );\n return response;\n }\n shouldSendRequest = await authorizeRequestOnCaeChallenge(\n {\n scopes: Array.isArray(scopes) ? scopes : [scopes],\n response,\n request,\n getAccessToken,\n logger,\n },\n parsedClaim,\n );\n // Send updated request and handle response for RestError\n if (shouldSendRequest) {\n [response, error] = await trySendRequest(request, next);\n }\n } else if (callbacks.authorizeRequestOnChallenge) {\n // Handle custom challenges when client provides custom callback\n shouldSendRequest = await callbacks.authorizeRequestOnChallenge({\n scopes: Array.isArray(scopes) ? scopes : [scopes],\n request,\n response,\n getAccessToken,\n logger,\n });\n\n // Send updated request and handle response for RestError\n if (shouldSendRequest) {\n [response, error] = await trySendRequest(request, next);\n }\n\n // If we get another CAE Claim, we will handle it by default and return whatever value we receive for this\n if (isChallengeResponse(response)) {\n claims = getCaeChallengeClaims(response.headers.get(\"WWW-Authenticate\") as string);\n if (claims) {\n let parsedClaim: string;\n try {\n parsedClaim = atob(claims);\n } catch (e) {\n logger.warning(\n `The WWW-Authenticate header contains \"claims\" that cannot be parsed. Unable to perform the Continuous Access Evaluation authentication flow. Unparsable claims: ${claims}`,\n );\n return response;\n }\n\n shouldSendRequest = await authorizeRequestOnCaeChallenge(\n {\n scopes: Array.isArray(scopes) ? scopes : [scopes],\n response,\n request,\n getAccessToken,\n logger,\n },\n parsedClaim,\n );\n // Send updated request and handle response for RestError\n if (shouldSendRequest) {\n [response, error] = await trySendRequest(request, next);\n }\n }\n }\n }\n }\n\n if (error) {\n throw error;\n } else {\n return response;\n }\n },\n };\n}\n\n/**\n *\n * Interface to represent a parsed challenge.\n *\n * @internal\n */\ninterface AuthChallenge {\n scheme: string;\n params: Record<string, string>;\n}\n\n/**\n * Converts: `Bearer a=\"b\", c=\"d\", Pop e=\"f\", g=\"h\"`.\n * Into: `[ { scheme: 'Bearer', params: { a: 'b', c: 'd' } }, { scheme: 'Pop', params: { e: 'f', g: 'h' } } ]`.\n *\n * @internal\n */\nexport function parseChallenges(challenges: string): AuthChallenge[] {\n // Challenge regex seperates the string to individual challenges with different schemes in the format `Scheme a=\"b\", c=d`\n // The challenge regex captures parameteres with either quotes values or unquoted values\n const challengeRegex = /(\\w+)\\s+((?:\\w+=(?:\"[^\"]*\"|[^,]*),?\\s*)+)/g;\n // Parameter regex captures the claims group removed from the scheme in the format `a=\"b\"` and `c=\"d\"`\n // CAE challenge always have quoted parameters. For more reference, https://learn.microsoft.com/entra/identity-platform/claims-challenge\n const paramRegex = /(\\w+)=\"([^\"]*)\"/g;\n\n const parsedChallenges: AuthChallenge[] = [];\n let match;\n\n // Iterate over each challenge match\n while ((match = challengeRegex.exec(challenges)) !== null) {\n const scheme = match[1];\n const paramsString = match[2];\n const params: Record<string, string> = {};\n let paramMatch;\n\n // Iterate over each parameter match\n while ((paramMatch = paramRegex.exec(paramsString)) !== null) {\n params[paramMatch[1]] = paramMatch[2];\n }\n\n parsedChallenges.push({ scheme, params });\n }\n return parsedChallenges;\n}\n\n/**\n * Parse a pipeline response and look for a CAE challenge with \"Bearer\" scheme\n * Return the value in the header without parsing the challenge\n * @internal\n */\nfunction getCaeChallengeClaims(challenges: string | undefined): string | undefined {\n if (!challenges) {\n return;\n }\n // Find all challenges present in the header\n const parsedChallenges = parseChallenges(challenges);\n return parsedChallenges.find(\n (x) => x.scheme === \"Bearer\" && x.params.claims && x.params.error === \"insufficient_claims\",\n )?.params.claims;\n}\n"]}
@@ -96,4 +96,22 @@ export interface BearerTokenAuthenticationPolicyOptions {
96
96
  * then apply it to the Authorization header of a request as a Bearer token.
97
97
  */
98
98
  export declare function bearerTokenAuthenticationPolicy(options: BearerTokenAuthenticationPolicyOptions): PipelinePolicy;
99
+ /**
100
+ *
101
+ * Interface to represent a parsed challenge.
102
+ *
103
+ * @internal
104
+ */
105
+ interface AuthChallenge {
106
+ scheme: string;
107
+ params: Record<string, string>;
108
+ }
109
+ /**
110
+ * Converts: `Bearer a="b", c="d", Pop e="f", g="h"`.
111
+ * Into: `[ { scheme: 'Bearer', params: { a: 'b', c: 'd' } }, { scheme: 'Pop', params: { e: 'f', g: 'h' } } ]`.
112
+ *
113
+ * @internal
114
+ */
115
+ export declare function parseChallenges(challenges: string): AuthChallenge[];
116
+ export {};
99
117
  //# sourceMappingURL=bearerTokenAuthenticationPolicy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bearerTokenAuthenticationPolicy.d.ts","sourceRoot":"","sources":["../../../src/policies/bearerTokenAuthenticationPolicy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACtF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAe,MAAM,kBAAkB,CAAC;AACvF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAIrD;;GAEG;AACH,eAAO,MAAM,mCAAmC,oCAAoC,CAAC;AAErF;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB;;OAEG;IACH,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC5F;;OAEG;IACH,OAAO,EAAE,eAAe,CAAC;IACzB;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,kCAAkC;IACjD;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB;;OAEG;IACH,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC5F;;OAEG;IACH,OAAO,EAAE,eAAe,CAAC;IACzB;;OAEG;IACH,QAAQ,EAAE,gBAAgB,CAAC;IAC3B;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,gBAAgB,CAAC,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE;;;;;OAKG;IACH,2BAA2B,CAAC,CAAC,OAAO,EAAE,kCAAkC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7F;AAED;;GAEG;AACH,MAAM,WAAW,sCAAsC;IACrD;;OAEG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B;;OAEG;IACH,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AA8BD;;;GAGG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,sCAAsC,GAC9C,cAAc,CAkFhB"}
1
+ {"version":3,"file":"bearerTokenAuthenticationPolicy.d.ts","sourceRoot":"","sources":["../../../src/policies/bearerTokenAuthenticationPolicy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACtF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAe,MAAM,kBAAkB,CAAC;AACvF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKrD;;GAEG;AACH,eAAO,MAAM,mCAAmC,oCAAoC,CAAC;AAErF;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB;;OAEG;IACH,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC5F;;OAEG;IACH,OAAO,EAAE,eAAe,CAAC;IACzB;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,kCAAkC;IACjD;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB;;OAEG;IACH,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC5F;;OAEG;IACH,OAAO,EAAE,eAAe,CAAC;IACzB;;OAEG;IACH,QAAQ,EAAE,gBAAgB,CAAC;IAC3B;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,gBAAgB,CAAC,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE;;;;;OAKG;IACH,2BAA2B,CAAC,CAAC,OAAO,EAAE,kCAAkC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7F;AAED;;GAEG;AACH,MAAM,WAAW,sCAAsC;IACrD;;OAEG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B;;OAEG;IACH,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AA6ED;;;GAGG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,sCAAsC,GAC9C,cAAc,CAqIhB;AAED;;;;;GAKG;AACH,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,EAAE,CA0BnE"}