Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing id encoding issues when using special characters for custome already on ComputeGateway #22818

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions eng/pipelines/templates/steps/cosmos-integration-public.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ parameters:

steps:
- template: /eng/common/pipelines/templates/steps/cosmos-emulator.yml
parameters:
StartParameters: '/noexplorer /noui /enablepreview /EnableSqlComputeEndpoint /disableratelimiting /enableaadauthentication /partitioncount=50
9 changes: 2 additions & 7 deletions sdk/cosmosdb/cosmos/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
# Release History

## 3.16.4 (Unreleased)

### Features Added

### Breaking Changes
## 3.16.4 (2022-08-05)

### Bugs Fixed

### Other Changes
- Reverts changes of [PR 22548](https://github.com/Azure/azure-sdk-for-js/pull/22548) to avoid possible regression when customers use id with special characters and their account is on ComputeGateway already. - See [PR 22818](https://github.com/Azure/azure-sdk-for-js/pull/22818)

## 3.16.3 (2022-07-13)

Expand Down
26 changes: 9 additions & 17 deletions sdk/cosmosdb/cosmos/src/client/Item/Item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,7 @@ export class Item {
* Returns a reference URL to the resource. Used for linking in Permissions.
*/
public get url(): string {
return createDocumentUri(
this.container.database.id,
this.container.id,
encodeURIComponent(this.id)
);
return createDocumentUri(this.container.database.id, this.container.id, this.id);
}

/**
Expand Down Expand Up @@ -84,9 +80,8 @@ export class Item {
this.partitionKey = undefinedPartitionKey(partitionKeyDefinition);
}

const resourceUri: string = this.url;
const path = getPathFromLink(resourceUri);
const id = getIdFromLink(resourceUri);
const path = getPathFromLink(this.url);
const id = getIdFromLink(this.url);
let response: Response<T & Resource>;
try {
response = await this.clientContext.read<T>({
Expand Down Expand Up @@ -154,9 +149,8 @@ export class Item {
throw err;
}

const resourceUri: string = this.url;
const path = getPathFromLink(resourceUri);
const id = getIdFromLink(resourceUri);
const path = getPathFromLink(this.url);
const id = getIdFromLink(this.url);

const response = await this.clientContext.replace<T>({
body,
Expand Down Expand Up @@ -192,9 +186,8 @@ export class Item {
this.partitionKey = undefinedPartitionKey(partitionKeyDefinition);
}

const resourceUri: string = this.url;
const path = getPathFromLink(resourceUri);
const id = getIdFromLink(resourceUri);
const path = getPathFromLink(this.url);
const id = getIdFromLink(this.url);

const response = await this.clientContext.delete<T>({
path,
Expand Down Expand Up @@ -230,9 +223,8 @@ export class Item {
this.partitionKey = extractPartitionKey(body, partitionKeyDefinition);
}

const resourceUri: string = this.url;
const path = getPathFromLink(resourceUri);
const id = getIdFromLink(resourceUri);
const path = getPathFromLink(this.url);
const id = getIdFromLink(this.url);

const response = await this.clientContext.patch<T>({
body,
Expand Down
24 changes: 21 additions & 3 deletions sdk/cosmosdb/cosmos/src/common/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { OperationType, ResourceType } from "./constants";
const trimLeftSlashes = new RegExp("^[/]+");
const trimRightSlashes = new RegExp("[/]+$");
const illegalResourceIdCharacters = new RegExp("[/\\\\?#]");
const illegalItemResourceIdCharacters = new RegExp("[/\\\\#]");

/** @hidden */
export function jsonStringifyAndEscapeNonASCII(arg: unknown): string {
Expand Down Expand Up @@ -223,7 +224,7 @@ export function isItemResourceValid(resource: { id?: string }, err: { message?:
return false;
}

if (resource.id.indexOf("/") !== -1 || resource.id.indexOf("\\") !== -1) {
if (resource.id.indexOf("/") !== -1 || resource.id.indexOf("\\") !== -1 || resource.id.indexOf("#") !== -1) {
err.message = "Id contains illegal chars.";
return false;
}
Expand Down Expand Up @@ -272,12 +273,29 @@ export function trimSlashFromLeftAndRight(inputString: string): string {
export function validateResourceId(resourceId: string): boolean {
// if resourceId is not a string or is empty throw an error
if (typeof resourceId !== "string" || isStringNullOrEmpty(resourceId)) {
throw new Error("Resource Id must be a string and cannot be undefined, null or empty");
throw new Error("Resource ID must be a string and cannot be undefined, null or empty");
}

// if resource id contains illegal characters throw an error
if (illegalResourceIdCharacters.test(resourceId)) {
throw new Error("Illegal characters ['/', '\\'] cannot be used in resourceId");
throw new Error("Illegal characters ['/', '\\', '#', '?'] cannot be used in Resource ID");
}

return true;
}

/**
* @hidden
*/
export function validateItemResourceId(resourceId: string): boolean {
// if resourceId is not a string or is empty throw an error
if (typeof resourceId !== "string" || isStringNullOrEmpty(resourceId)) {
throw new Error("Resource ID must be a string and cannot be undefined, null or empty");
}

// if resource id contains illegal characters throw an error
if (illegalItemResourceIdCharacters.test(resourceId)) {
throw new Error("Illegal characters ['/', '\\', '#'] cannot be used in Resource ID");
}

return true;
Expand Down
4 changes: 2 additions & 2 deletions sdk/cosmosdb/cosmos/src/common/uriFactory.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { Constants } from "./constants";
import { trimSlashFromLeftAndRight, validateResourceId } from "./helper";
import { trimSlashFromLeftAndRight, validateResourceId, validateItemResourceId } from "./helper";

/**
* Would be used when creating or deleting a DocumentCollection
Expand Down Expand Up @@ -74,7 +74,7 @@ export function createDocumentUri(
documentId: string
): string {
documentId = trimSlashFromLeftAndRight(documentId);
validateResourceId(documentId);
validateItemResourceId(documentId);

return (
createDocumentCollectionUri(databaseId, collectionId) +
Expand Down
16 changes: 1 addition & 15 deletions sdk/cosmosdb/cosmos/src/utils/headers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,6 @@ export async function generateHeaders(
};
}

function getEffectiveResourceIdForSignature(resourceId: string) {
const lastSlashPosition = resourceId.lastIndexOf("/");
if (lastSlashPosition <= 0) {
return resourceId;
}

const prefix: string = resourceId.substring(0, lastSlashPosition);
if (!prefix.endsWith("/docs")) {
return resourceId;
}

return prefix + "/" + decodeURIComponent(resourceId.substring(lastSlashPosition + 1));
}

async function signature(
masterKey: string,
method: HTTPMethod,
Expand All @@ -55,7 +41,7 @@ async function signature(
"\n" +
resourceType.toLowerCase() +
"\n" +
getEffectiveResourceIdForSignature(resourceId) +
resourceId +
"\n" +
date.toUTCString().toLowerCase() +
"\n" +
Expand Down
11 changes: 10 additions & 1 deletion sdk/cosmosdb/cosmos/test/public/common/TestHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,21 @@ import { masterKey } from "../common/_fakeTestSecrets";
import { DatabaseRequest } from "../../../src";
import { ContainerRequest } from "../../../src";

const defaultClient = new CosmosClient({
const defaultRoutingGatewayPort: string = ":8081";
const defaultComputeGatewayPort: string = ":8903";

export const defaultClient = new CosmosClient({
endpoint,
key: masterKey,
connectionPolicy: { enableBackgroundEndpointRefreshing: false },
});

export const defaultComputeGatewayClient = new CosmosClient({
endpoint: endpoint.replace(defaultRoutingGatewayPort, defaultComputeGatewayPort),
key: masterKey,
connectionPolicy: { enableBackgroundEndpointRefreshing: false },
});

export function addEntropy(name: string): string {
return name + getEntropy();
}
Expand Down
Loading