diff --git a/packages/nodes-base/credentials/MicrosoftCosmosDbSharedKeyApi.credentials.ts b/packages/nodes-base/credentials/MicrosoftCosmosDbSharedKeyApi.credentials.ts index 686ff14f98..d0dfa8a6af 100644 --- a/packages/nodes-base/credentials/MicrosoftCosmosDbSharedKeyApi.credentials.ts +++ b/packages/nodes-base/credentials/MicrosoftCosmosDbSharedKeyApi.credentials.ts @@ -55,8 +55,7 @@ export class MicrosoftCosmosDbSharedKeyApi implements ICredentialType { credentials: ICredentialDataDecryptedObject, requestOptions: IHttpRequestOptions, ): Promise { - console.log('Authenticate invoked with requestOptions:', requestOptions); - + // Remove undefined query parameters? if (requestOptions.qs) { for (const [key, value] of Object.entries(requestOptions.qs)) { if (value === undefined) { @@ -65,38 +64,54 @@ export class MicrosoftCosmosDbSharedKeyApi implements ICredentialType { } } + // Add headers for date and version requestOptions.headers ??= {}; - const date = new Date().toUTCString(); + const date = new Date().toUTCString().toLowerCase(); requestOptions.headers = { ...requestOptions.headers, 'x-ms-date': date, 'x-ms-version': '2018-12-31', + 'x-ms-partitionkey': '[]', }; if (credentials.sessionToken) { requestOptions.headers['x-ms-session-token'] = credentials.sessionToken; } - let resourceType = ''; - const resourceLink = '/dbs/first_database_1' + requestOptions.url; + // This shouldn't be the full url + // Refer to https://stackoverflow.com/questions/45645389/documentdb-rest-api-authorization-token-error - console.log('Link', resourceLink); - if (resourceLink.includes('/colls')) { - resourceType = 'colls'; - } else if (resourceLink.includes('/docs')) { + const url = new URL(requestOptions.baseURL + requestOptions.url); + const pathSegments = url.pathname.split('/').filter((segment) => segment); + console.log('Filtered Path Segments:', pathSegments); + + let resourceType = ''; + let resourceId = ''; + + if (pathSegments.includes('docs')) { + const docsIndex = pathSegments.lastIndexOf('docs'); resourceType = 'docs'; - } else if (resourceLink.includes('/dbs')) { + resourceId = pathSegments.slice(0, docsIndex).join('/'); + } else if (pathSegments.includes('colls')) { + const collsIndex = pathSegments.lastIndexOf('colls'); + resourceType = 'colls'; + resourceId = pathSegments.slice(0, collsIndex).join('/'); + } else if (pathSegments.includes('dbs')) { + const dbsIndex = pathSegments.lastIndexOf('dbs'); resourceType = 'dbs'; + resourceId = pathSegments.slice(0, dbsIndex + 2).join('/'); } else { - throw new ApplicationError('Unable to determine resourceType'); + throw new ApplicationError('Unable to determine resourceType and resourceId from the URL.'); } - console.log('Type', resourceType); + + console.log('resourceId', resourceId); + console.log('resourceType', resourceType); if (requestOptions.method) { const authToken = getAuthorizationTokenUsingMasterKey( requestOptions.method, resourceType, - resourceLink, + resourceId, date, credentials.key as string, ); diff --git a/packages/nodes-base/nodes/Microsoft/CosmosDB/CosmosDb.node.ts b/packages/nodes-base/nodes/Microsoft/CosmosDB/CosmosDb.node.ts index 566ea4b05d..5e37f8605f 100644 --- a/packages/nodes-base/nodes/Microsoft/CosmosDB/CosmosDb.node.ts +++ b/packages/nodes-base/nodes/Microsoft/CosmosDB/CosmosDb.node.ts @@ -3,9 +3,9 @@ import { NodeConnectionType } from 'n8n-workflow'; import { containerFields, containerOperations } from './descriptions/ContainerDescription'; import { itemFields, itemOperations } from './descriptions/ItemDescription'; -import { searchCollections } from './GenericFunctions'; +import { presendStringifyBody, searchCollections } from './GenericFunctions'; -export class AzureCosmosDb implements INodeType { +export class CosmosDb implements INodeType { description: INodeTypeDescription = { displayName: 'Cosmos DB', name: 'cosmosDb', @@ -58,6 +58,11 @@ export class AzureCosmosDb implements INodeType { name: 'resource', type: 'options', noDataExpression: true, + routing: { + send: { + preSend: [presendStringifyBody], + }, + }, options: [ { name: 'Container', diff --git a/packages/nodes-base/nodes/Microsoft/CosmosDB/GenericFunctions.ts b/packages/nodes-base/nodes/Microsoft/CosmosDB/GenericFunctions.ts index 1613e82729..e6cf960e35 100644 --- a/packages/nodes-base/nodes/Microsoft/CosmosDB/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Microsoft/CosmosDB/GenericFunctions.ts @@ -3,6 +3,7 @@ import type { DeclarativeRestApiSettings, IDataObject, IExecutePaginationFunctions, + IExecuteSingleFunctions, IHttpRequestOptions, ILoadOptionsFunctions, INodeExecutionData, @@ -43,7 +44,7 @@ export const HeaderConstants = { export function getAuthorizationTokenUsingMasterKey( verb: string, resourceType: string, - resourceLink: string, + resourceId: string, date: string, masterKey: string, ): string { @@ -51,14 +52,24 @@ export function getAuthorizationTokenUsingMasterKey( const payload = `${verb.toLowerCase()}\n` + `${resourceType.toLowerCase()}\n` + - `${resourceLink}\n` + - `${date}\n` + + `${resourceId}\n` + + `${date.toLowerCase()}\n` + '\n'; const hmacSha256 = crypto.createHmac('sha256', key); - const hashPayload = hmacSha256.update(payload, 'utf8').digest('base64'); + const signature = hmacSha256.update(payload, 'utf8').digest('base64'); - return encodeURIComponent('type=master&ver=1.0&sig=' + hashPayload); + return `type=master&ver=1.0&sig=${signature}`; +} + +export async function presendStringifyBody( + this: IExecuteSingleFunctions, + requestOptions: IHttpRequestOptions, +): Promise { + if (requestOptions.body) { + requestOptions.body = JSON.stringify(requestOptions.body); + } + return requestOptions; } export async function handlePagination( @@ -207,10 +218,12 @@ export async function searchCollections( } const results: INodeListSearchItems[] = collections - .map((collection) => ({ - name: String(collection.id), - value: String(collection.id), - })) + .map((collection) => { + return { + name: String(collection.id), + value: String(collection.id), + }; + }) .filter((collection) => !filter || collection.name.includes(filter)) .sort((a, b) => a.name.localeCompare(b.name)); diff --git a/packages/nodes-base/nodes/Microsoft/CosmosDB/descriptions/ContainerDescription.ts b/packages/nodes-base/nodes/Microsoft/CosmosDB/descriptions/ContainerDescription.ts index 079f30b74c..2ceafa919f 100644 --- a/packages/nodes-base/nodes/Microsoft/CosmosDB/descriptions/ContainerDescription.ts +++ b/packages/nodes-base/nodes/Microsoft/CosmosDB/descriptions/ContainerDescription.ts @@ -21,6 +21,9 @@ export const containerOperations: INodeProperties[] = [ ignoreHttpStatusErrors: true, method: 'POST', url: '/colls', + headers: { + headers: {}, + }, }, }, action: 'Create container', diff --git a/packages/nodes-base/nodes/Microsoft/CosmosDB/descriptions/ItemDescription.ts b/packages/nodes-base/nodes/Microsoft/CosmosDB/descriptions/ItemDescription.ts index bec1b6f964..f7d44d86e2 100644 --- a/packages/nodes-base/nodes/Microsoft/CosmosDB/descriptions/ItemDescription.ts +++ b/packages/nodes-base/nodes/Microsoft/CosmosDB/descriptions/ItemDescription.ts @@ -23,6 +23,9 @@ export const itemOperations: INodeProperties[] = [ ignoreHttpStatusErrors: true, method: 'POST', url: '=/colls/{{ $parameter["collId"] }}/docs', + headers: { + // 'x-ms-documentdb-partitionkey': '={{$parameter["partitionKey"]}}', + }, }, }, action: 'Create item', @@ -108,6 +111,9 @@ export const itemOperations: INodeProperties[] = [ ignoreHttpStatusErrors: true, method: 'PATCH', url: '=/colls/{{ $parameter["collId"] }}/docs/{{ $parameter["id"] }}', + headers: { + 'Content-Type': 'application/json-patch+json', + }, }, }, action: 'Update item', @@ -198,10 +204,11 @@ export const createFields: INodeProperties[] = [ operation: ['create'], }, }, + //To-Do-add preSend function routing: { send: { type: 'body', - value: '={{ $json["id"] ? Object.assign({ id: $json["id"] }, $value) : $value }}', + value: '={{$value}}', }, }, },