Skip to content

Commit 3f05285

Browse files
update
1 parent a30b421 commit 3f05285

File tree

4 files changed

+59
-51
lines changed

4 files changed

+59
-51
lines changed

src/AzureAppConfigurationImpl.ts

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ import { FeatureFlagTracingOptions } from "./requestTracing/FeatureFlagTracingOp
6262
import { AIConfigurationTracingOptions } from "./requestTracing/AIConfigurationTracingOptions.js";
6363
import { KeyFilter, LabelFilter, SettingSelector } from "./types.js";
6464
import { ConfigurationClientManager } from "./ConfigurationClientManager.js";
65-
import { CDN_TOKEN_LOOKUP_HEADER } from "./CdnTokenPipelinePolicy.js";
65+
import { CDN_TOKEN_LOOKUP_HEADER, calculateResourceDeletedCacheConsistencyToken } from "./cdnTokenPipelinePolicy.js";
6666
import { getFixedBackoffDuration, getExponentialBackoffDuration } from "./common/backoffUtils.js";
6767
import { InvalidOperationError, ArgumentError, isFailoverableError, isInputError } from "./common/error.js";
6868

@@ -691,7 +691,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
691691
) {
692692
if (response === undefined) {
693693
this.#kvSelectorCollection.cdnToken =
694-
await this.#calculateResourceDeletedCacheConsistencyToken(sentinel.etag!);
694+
await calculateResourceDeletedCacheConsistencyToken(sentinel.etag!);
695695
} else {
696696
this.#kvSelectorCollection.cdnToken = response.etag;
697697
}
@@ -1072,25 +1072,6 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
10721072
return first15Bytes.toString("base64url");
10731073
}
10741074
}
1075-
1076-
async #calculateResourceDeletedCacheConsistencyToken(etag: string): Promise<string> {
1077-
const crypto = getCryptoModule();
1078-
const rawString = `ResourceDeleted\n${etag}`;
1079-
const payload = new TextEncoder().encode(rawString);
1080-
// In the browser or Node.js 18+, use crypto.subtle.digest
1081-
if (crypto.subtle) {
1082-
const hashBuffer = await crypto.subtle.digest("SHA-256", payload);
1083-
const hashArray = new Uint8Array(hashBuffer);
1084-
const base64String = btoa(String.fromCharCode(...hashArray));
1085-
const base64urlString = base64String.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
1086-
return base64urlString;
1087-
}
1088-
// Use the crypto module's hash function
1089-
else {
1090-
const hash = crypto.createHash("sha256").update(payload).digest();
1091-
return hash.toString("base64url");
1092-
}
1093-
}
10941075
}
10951076

10961077
function getValidSettingSelectors(selectors: SettingSelector[]): SettingSelector[] {

src/CdnTokenPipelinePolicy.ts

Lines changed: 0 additions & 29 deletions
This file was deleted.

src/cdnTokenPipelinePolicy.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
import { PipelinePolicy } from "@azure/core-rest-pipeline";
5+
import { getCryptoModule } from "./common/utils.js";
6+
7+
const CDN_TOKEN_QUERY_PARAMETER = "_";
8+
const RESOURCE_DELETED_PREFIX = "ResourceDeleted";
9+
10+
export const CDN_TOKEN_LOOKUP_HEADER = "cdn-token-lookup";
11+
12+
/**
13+
* The pipeline policy that retrieves the CDN token from the request header and appends it to the request URL. After that the lookup header is removed from the request.
14+
* @remarks
15+
* The policy position should be perCall.
16+
* The App Configuration service will not recognize the CDN token query parameter in the url, but this can help to break the CDN cache as the cache entry is based on the URL.
17+
*/
18+
export class CdnTokenPipelinePolicy implements PipelinePolicy {
19+
name: string = "AppConfigurationCdnTokenPolicy";
20+
21+
async sendRequest(request, next) {
22+
if (request.headers.has(CDN_TOKEN_LOOKUP_HEADER)) {
23+
const token = request.headers.get(CDN_TOKEN_LOOKUP_HEADER);
24+
request.headers.delete(CDN_TOKEN_LOOKUP_HEADER);
25+
26+
const url = new URL(request.url);
27+
url.searchParams.append(CDN_TOKEN_QUERY_PARAMETER, token); // _ is a dummy query parameter to break the CDN cache
28+
request.url = url.toString();
29+
}
30+
31+
return next(request);
32+
}
33+
}
34+
35+
/**
36+
* Calculates a cache consistency token for a deleted resource based on its previous ETag.
37+
* @param etag - The previous ETag of the deleted resource.
38+
*/
39+
export async function calculateResourceDeletedCacheConsistencyToken(etag: string): Promise<string> {
40+
const crypto = getCryptoModule();
41+
const rawString = `${RESOURCE_DELETED_PREFIX}\n${etag}`;
42+
const payload = new TextEncoder().encode(rawString);
43+
// In the browser or Node.js 18+, use crypto.subtle.digest
44+
if (crypto.subtle) {
45+
const hashBuffer = await crypto.subtle.digest("SHA-256", payload);
46+
const hashArray = new Uint8Array(hashBuffer);
47+
const base64String = btoa(String.fromCharCode(...hashArray));
48+
const base64urlString = base64String.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
49+
return base64urlString;
50+
}
51+
// Use the crypto module's hash function
52+
else {
53+
const hash = crypto.createHash("sha256").update(payload).digest();
54+
return hash.toString("base64url");
55+
}
56+
}

src/load.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { AzureAppConfiguration } from "./AzureAppConfiguration.js";
66
import { AzureAppConfigurationImpl } from "./AzureAppConfigurationImpl.js";
77
import { AzureAppConfigurationOptions } from "./AzureAppConfigurationOptions.js";
88
import { ConfigurationClientManager } from "./ConfigurationClientManager.js";
9-
import { CdnTokenPipelinePolicy } from "./CdnTokenPipelinePolicy.js";
9+
import { CdnTokenPipelinePolicy } from "./cdnTokenPipelinePolicy.js";
1010
import { instanceOfTokenCredential } from "./common/utils.js";
1111
import { ArgumentError } from "./common/error.js";
1212

0 commit comments

Comments
 (0)