n8n/packages/nodes-base/credentials/AzureStorageSharedKeyApi.credentials.ts

116 lines
3.1 KiB
TypeScript

import type {
ICredentialDataDecryptedObject,
ICredentialTestRequest,
ICredentialType,
IHttpRequestOptions,
INodeProperties,
} from 'n8n-workflow';
import { createHmac } from 'node:crypto';
import {
getCanonicalizedHeadersString,
getCanonicalizedResourceString,
HeaderConstants,
XMsVersion,
} from '../nodes/Microsoft/Storage/GenericFunctions';
export class AzureStorageSharedKeyApi implements ICredentialType {
name = 'azureStorageSharedKeyApi';
displayName = 'Azure Storage Shared Key API';
documentationUrl = 'azurestorage';
properties: INodeProperties[] = [
{
displayName: 'Account',
name: 'account',
description: 'Account name',
type: 'string',
default: '',
},
{
displayName: 'Key',
name: 'key',
description: 'Account key',
type: 'string',
typeOptions: {
password: true,
},
default: '',
},
{
displayName: 'Base URL',
name: 'baseUrl',
type: 'hidden',
default: '=https://{{ $self["account"] }}.blob.core.windows.net',
},
];
async authenticate(
credentials: ICredentialDataDecryptedObject,
requestOptions: IHttpRequestOptions,
): Promise<IHttpRequestOptions> {
if (requestOptions.qs) {
for (const [key, value] of Object.entries(requestOptions.qs)) {
if (value === undefined) {
delete requestOptions.qs[key];
}
}
}
if (requestOptions.headers) {
for (const [key, value] of Object.entries(requestOptions.headers)) {
if (value === undefined) {
delete requestOptions.headers[key];
}
}
}
requestOptions.method ??= 'GET';
requestOptions.headers ??= {};
requestOptions.headers[HeaderConstants.X_MS_VERSION] ??= XMsVersion;
requestOptions.headers[HeaderConstants.X_MS_DATE] ??= new Date().toUTCString();
const stringToSign: string = [
requestOptions.method.toUpperCase(),
requestOptions.headers[HeaderConstants.CONTENT_LANGUAGE] ?? '',
requestOptions.headers[HeaderConstants.CONTENT_ENCODING] ?? '',
requestOptions.headers[HeaderConstants.CONTENT_LENGTH] ?? '',
requestOptions.headers[HeaderConstants.CONTENT_MD5] ?? '',
requestOptions.headers[HeaderConstants.CONTENT_TYPE] ?? '',
requestOptions.headers[HeaderConstants.DATE] ?? '',
requestOptions.headers[HeaderConstants.IF_MODIFIED_SINCE] ?? '',
requestOptions.headers[HeaderConstants.IF_MATCH] ?? '',
requestOptions.headers[HeaderConstants.IF_NONE_MATCH] ?? '',
requestOptions.headers[HeaderConstants.IF_UNMODIFIED_SINCE] ?? '',
requestOptions.headers[HeaderConstants.RANGE] ?? '',
getCanonicalizedHeadersString(requestOptions) +
getCanonicalizedResourceString(requestOptions, credentials),
].join('\n');
const signature: string = createHmac('sha256', Buffer.from(credentials.key as string, 'base64'))
.update(stringToSign, 'utf8')
.digest('base64');
requestOptions.headers[HeaderConstants.AUTHORIZATION] =
`SharedKey ${credentials.account as string}:${signature}`;
return requestOptions;
}
test: ICredentialTestRequest = {
request: {
baseURL: '={{$credentials.baseUrl}}',
url: '/',
headers: {
'x-ms-date': '={{ new Date().toUTCString() }}',
'x-ms-version': '2021-12-02',
},
qs: {
comp: 'list',
},
},
};
}