n8n-nodes-base
Version:
Base nodes of n8n
456 lines • 19.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.HeaderConstants = exports.XMsVersion = void 0;
exports.azureStorageApiRequest = azureStorageApiRequest;
exports.handleErrorPostReceive = handleErrorPostReceive;
exports.getCanonicalizedHeadersString = getCanonicalizedHeadersString;
exports.getCanonicalizedResourceString = getCanonicalizedResourceString;
exports.parseHeaders = parseHeaders;
exports.parseBlobList = parseBlobList;
exports.parseContainerList = parseContainerList;
exports.getBlobs = getBlobs;
exports.getContainers = getContainers;
const change_case_1 = require("change-case");
const n8n_workflow_1 = require("n8n-workflow");
const xml2js_1 = require("xml2js");
const processors_1 = require("xml2js/lib/processors");
const http_1 = require("../../../credentials/common/http");
const compare_header_1 = require("./compare-header");
exports.XMsVersion = '2021-12-02';
exports.HeaderConstants = {
AUTHORIZATION: 'authorization',
CONTENT_ENCODING: 'content-encoding',
CONTENT_LANGUAGE: 'content-language',
CONTENT_LENGTH: 'content-length',
CONTENT_MD5: 'content-md5',
CONTENT_TYPE: 'content-Type',
DATE: 'date',
ETAG: 'etag',
IF_MATCH: 'if-match',
IF_MODIFIED_SINCE: 'if-Modified-since',
IF_NONE_MATCH: 'if-none-match',
IF_UNMODIFIED_SINCE: 'if-unmodified-since',
ORIGIN: 'origin',
RANGE: 'range',
X_MS_COPY_SOURCE: 'x-ms-copy-source',
X_MS_DATE: 'x-ms-date',
X_MS_VERSION: 'x-ms-version',
X_MS_BLOB_TYPE: 'x-ms-blob-type',
X_MS_BLOB_CONTENT_DISPOSITION: 'x-ms-blob-content-disposition',
X_MS_BLOB_PUBLIC_ACCESS: 'x-ms-blob-public-access',
X_MS_HAS_IMMUTABILITY_POLICY: 'x-ms-has-immutability-policy',
X_MS_HAS_LEGAL_HOLD: 'x-ms-has-legal-hold',
X_MS_CONTENT_CRC64: 'x-ms-content-crc64',
X_MS_REQUEST_SERVER_ENCRYPTED: 'x-ms-request-server-encrypted',
X_MS_ENCRYPTION_SCOPE: 'x-ms-encryption-scope',
X_MS_VERSION_ID: 'x-ms-version-id',
X_MS_TAG_COUNT: 'x-ms-tag-count',
X_MS_COPY_PROGRESS: 'x-ms-copy-progress',
X_MS_INCREMENTAL_COPY: 'x-ms-incremental-copy',
X_MS_BLOB_SEQUENCE_NUMBER: 'x-ms-blob-sequence-number',
X_MS_BLOB_COMMITTED_BLOCK_COUNT: 'x-ms-blob-committed-block-count',
X_MS_SERVER_ENCRYPTED: 'x-ms-server-encrypted',
X_MS_ENCRYPTION_CONTEXT: 'x-ms-encryption-context',
X_MS_BLOB_CONTENT_MD5: 'x-ms-blob-content-md5',
X_MS_BLOB_SEALED: 'x-ms-blob-sealed',
X_MS_IMMUTABILITY_POLICY_UNTIL_DATE: 'x-ms-immutability-policy-until-date',
X_MS_IMMUTABILITY_POLICY_MODE: 'x-ms-immutability-policy-mode',
X_MS_LEGAL_HOLD: 'x-ms-legal-hold',
X_MS_DELETE_TYPE_PERMANENT: 'x-ms-delete-type-permanent',
X_MS_ACCESS_TIER: 'x-ms-access-tier',
X_MS_BLOB_CACHE_CONTROL: 'x-ms-blob-cache-control',
X_MS_LEASE_ID: 'x-ms-lease-id',
X_MS_BLOB_CONTENT_ENCODING: 'x-ms-blob-content-encoding',
X_MS_BLOB_CONTENT_LANGUAGE: 'x-ms-blob-content-language',
X_MS_BLOB_CONTENT_TYPE: 'x-ms-blob-content-type',
X_MS_EXPIRY_OPTION: 'x-ms-expiry-option',
X_MS_EXPIRY_TIME: 'x-ms-expiry-time',
X_MS_TAGS: 'x-ms-tags',
X_MS_UPN: 'x-ms-upn',
PREFIX_X_MS: 'x-ms-',
PREFIX_X_MS_META: 'x-ms-meta-',
};
async function azureStorageApiRequest(method, endpoint, body = {}, qs, headers, url) {
const authentication = this.getNodeParameter('authentication', 0);
const credentialsType = authentication === 'oAuth2' ? 'azureStorageOAuth2Api' : 'azureStorageSharedKeyApi';
const credentials = await this.getCredentials(credentialsType);
const options = {
method,
url: url ?? `${credentials.baseUrl}${endpoint}`,
headers,
body,
qs,
};
options.headers ??= {};
options.headers[exports.HeaderConstants.X_MS_DATE] = new Date().toUTCString();
options.headers[exports.HeaderConstants.X_MS_VERSION] = exports.XMsVersion;
// XML response
const response = (await this.helpers.requestWithAuthentication.call(this, credentialsType, options));
return response;
}
async function handleErrorPostReceive(data, response) {
if (String(response.statusCode).startsWith('4') || String(response.statusCode).startsWith('5')) {
const resource = this.getNodeParameter('resource');
const operation = this.getNodeParameter('operation');
const parser = new xml2js_1.Parser({
explicitArray: false,
tagNameProcessors: [processors_1.firstCharLowerCase],
});
const { error } = (await parser.parseStringPromise(data[0].json)) ?? {};
if (error?.code === 'InvalidAuthenticationInfo' &&
error?.authenticationErrorDetail ===
'Lifetime validation failed. The token is expired.') {
throw new n8n_workflow_1.NodeApiError(this.getNode(), error, {
message: 'Lifetime validation failed. The token is expired.',
description: 'Please check your credentials and try again',
});
}
if (resource === 'blob') {
if (error?.code === 'ContainerNotFound') {
throw new n8n_workflow_1.NodeApiError(this.getNode(), error, {
message: "The required container doesn't match any existing one",
description: "Double-check the value in the parameter 'Container Name' and try again",
});
}
if (operation === 'create') {
if (this.getNodeParameter('from') === 'url' &&
((error?.code === 'InvalidHeaderValue' &&
error?.headerName === exports.HeaderConstants.X_MS_COPY_SOURCE) ||
error?.code === 'CannotVerifyCopySource')) {
throw new n8n_workflow_1.NodeApiError(this.getNode(), error, {
message: 'The provided URL is invalid',
description: "Double-check the value in the parameter 'URL' and try again",
});
}
}
else if (operation === 'delete') {
if (error?.code === 'BlobNotFound') {
throw new n8n_workflow_1.NodeApiError(this.getNode(), error, {
message: "The required blob doesn't match any existing one",
description: "Double-check the value in the parameter 'Blob to Delete' and try again",
});
}
}
else if (operation === 'get') {
if (error?.code === 'BlobNotFound') {
throw new n8n_workflow_1.NodeApiError(this.getNode(), error, {
message: "The required blob doesn't match any existing one",
description: "Double-check the value in the parameter 'Blob to Get' and try again",
});
}
}
else if (operation === 'getAll') {
if (error?.code === 'InvalidQueryParameterValue' &&
this.getNodeParameter('fields', []).includes('permissions')) {
throw new n8n_workflow_1.NodeApiError(this.getNode(), error, {
message: 'Permissions field is only supported for accounts with a hierarchical namespace enabled',
description: "Exclude 'Permissions' from 'Fields' and try again",
});
}
if (error?.code === 'UnsupportedQueryParameter' &&
this.getNodeParameter('fields', []).includes('deleted') &&
this.getNodeParameter('filter', []).includes('deleted')) {
throw new n8n_workflow_1.NodeApiError(this.getNode(), error, {
message: "Including 'Deleted' field and filter is not supported",
description: "Exclude 'Deleted' from 'Fields' or 'Filter' and try again",
});
}
}
}
else if (resource === 'container') {
if (operation === 'create') {
if (error?.code === 'ContainerAlreadyExists') {
throw new n8n_workflow_1.NodeApiError(this.getNode(), error, {
message: 'The specified container already exists',
description: "Use a unique value for 'Container Name' and try again",
});
}
if (error?.code === 'PublicAccessNotPermitted') {
throw new n8n_workflow_1.NodeApiError(this.getNode(), error, {
message: 'Public access is not permitted on this storage account',
description: "Check the 'Access Level' and try again",
});
}
}
else if (operation === 'delete') {
if (error?.code === 'ContainerNotFound') {
throw new n8n_workflow_1.NodeApiError(this.getNode(), error, {
message: "The required container doesn't match any existing one",
description: "Double-check the value in the parameter 'Container to Delete' and try again",
});
}
}
else if (operation === 'get') {
if (error?.code === 'ContainerNotFound') {
throw new n8n_workflow_1.NodeApiError(this.getNode(), error, {
message: "The required container doesn't match any existing one",
description: "Double-check the value in the parameter 'Container to Get' and try again",
});
}
}
else if (operation === 'getAll') {
}
}
if (error) {
throw new n8n_workflow_1.NodeApiError(this.getNode(), response, {
message: error.code,
description: error.message,
});
}
else {
throw new n8n_workflow_1.NodeApiError(this.getNode(), response, {
parseXml: true,
});
}
}
return data;
}
function getCanonicalizedHeadersString(requestOptions) {
let headersArray = [];
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
for (const [name, value] of Object.entries(requestOptions.headers)) {
if (name.toLowerCase().startsWith(exports.HeaderConstants.PREFIX_X_MS)) {
headersArray.push({ name, value });
}
}
headersArray.sort((a, b) => {
return (0, compare_header_1.compareHeader)(a.name.toLowerCase(), b.name.toLowerCase());
});
// Remove duplicate headers
headersArray = headersArray.filter((value, index, array) => {
if (index > 0 && value.name.toLowerCase() === array[index - 1].name.toLowerCase()) {
return false;
}
return true;
});
let canonicalizedHeadersStringToSign = '';
headersArray.forEach((header) => {
canonicalizedHeadersStringToSign += `${header.name
.toLowerCase()
.trimEnd()}:${header.value.trimStart()}\n`;
});
return canonicalizedHeadersStringToSign;
}
function getCanonicalizedResourceString(requestOptions, credentials) {
const path = new URL((0, http_1.getUrl)(requestOptions)).pathname || '/';
let canonicalizedResourceString = `/${credentials.account}${path}`;
if (requestOptions.qs && Object.keys(requestOptions.qs).length > 0) {
canonicalizedResourceString +=
'\n' +
Object.keys(requestOptions.qs)
.sort()
.map(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
(key) => `${key.toLowerCase()}:${decodeURIComponent(requestOptions.qs[key])}`)
.join('\n');
}
return canonicalizedResourceString;
}
function parseHeaders(headers) {
const parseBooleanHeaders = [
exports.HeaderConstants.X_MS_DELETE_TYPE_PERMANENT,
exports.HeaderConstants.X_MS_INCREMENTAL_COPY,
exports.HeaderConstants.X_MS_SERVER_ENCRYPTED,
exports.HeaderConstants.X_MS_BLOB_SEALED,
exports.HeaderConstants.X_MS_REQUEST_SERVER_ENCRYPTED,
exports.HeaderConstants.X_MS_HAS_IMMUTABILITY_POLICY,
exports.HeaderConstants.X_MS_HAS_LEGAL_HOLD,
];
const parseNumberHeaders = [
exports.HeaderConstants.X_MS_TAG_COUNT,
exports.HeaderConstants.CONTENT_LENGTH,
exports.HeaderConstants.X_MS_BLOB_SEQUENCE_NUMBER,
exports.HeaderConstants.X_MS_COPY_PROGRESS,
exports.HeaderConstants.X_MS_BLOB_COMMITTED_BLOCK_COUNT,
];
const result = {};
const metadataKeys = Object.keys(headers).filter((x) => x.startsWith(exports.HeaderConstants.PREFIX_X_MS_META));
for (const key in headers) {
if (metadataKeys.includes(key)) {
continue;
}
let newKey = key.startsWith(exports.HeaderConstants.PREFIX_X_MS)
? (0, change_case_1.camelCase)(key.replace(exports.HeaderConstants.PREFIX_X_MS, ''))
: (0, change_case_1.camelCase)(key);
newKey = newKey.replace('-', '');
const newValue = parseBooleanHeaders.includes(key)
? (0, processors_1.parseBooleans)(headers[key])
: parseNumberHeaders.includes(key)
? (0, processors_1.parseNumbers)(headers[key])
: headers[key];
result[newKey] = newValue;
}
if (metadataKeys.length > 0) {
result.metadata = {};
for (const key of metadataKeys) {
result.metadata[key.replace(exports.HeaderConstants.PREFIX_X_MS_META, '')] =
headers[key];
}
}
return result;
}
async function parseBlobList(xml) {
const parser = new xml2js_1.Parser({
explicitArray: false,
tagNameProcessors: [processors_1.firstCharLowerCase, (name) => name.replace('-', '')],
valueProcessors: [
function (value, name) {
if ([
'deleted',
'isCurrentVersion',
'serverEncrypted',
'incrementalCopy',
'accessTierInferred',
'isSealed',
'legalHold',
].includes(name)) {
return (0, processors_1.parseBooleans)(value);
}
else if ([
'maxResults',
'contentLength',
'blobSequenceNumber',
'remainingRetentionDays',
'tagCount',
'content-Length',
].includes(name)) {
return (0, processors_1.parseNumbers)(value);
}
return value;
},
],
});
const data = (await parser.parseStringPromise(xml));
if (typeof data.enumerationResults.blobs !== 'object') {
// No items
return { blobs: [] };
}
if (!Array.isArray(data.enumerationResults.blobs.blob)) {
// Single item
data.enumerationResults.blobs.blob = [data.enumerationResults.blobs.blob];
}
for (const blob of data.enumerationResults.blobs.blob) {
if (blob.tags) {
if (!Array.isArray(blob.tags.tagSet.tag)) {
blob.tags.tagSet.tag = [
blob.tags.tagSet.tag,
];
}
blob.tags = blob.tags.tagSet.tag;
}
}
for (const container of data.enumerationResults.blobs.blob) {
if (container.metadata === '') {
delete container.metadata;
}
if (container.orMetadata === '') {
delete container.orMetadata;
}
}
return {
blobs: data.enumerationResults.blobs.blob,
maxResults: data.enumerationResults.maxResults,
nextMarker: data.enumerationResults.nextMarker,
};
}
async function parseContainerList(xml) {
const parser = new xml2js_1.Parser({
explicitArray: false,
tagNameProcessors: [processors_1.firstCharLowerCase, (name) => name.replace('-', '')],
valueProcessors: [
function (value, name) {
if ([
'deleted',
'hasImmutabilityPolicy',
'hasLegalHold',
'preventEncryptionScopeOverride',
'isImmutableStorageWithVersioningEnabled',
].includes(name)) {
return (0, processors_1.parseBooleans)(value);
}
else if (['maxResults', 'remainingRetentionDays'].includes(name)) {
return (0, processors_1.parseNumbers)(value);
}
return value;
},
],
});
const data = (await parser.parseStringPromise(xml));
if (typeof data.enumerationResults.containers !== 'object') {
// No items
return { containers: [] };
}
if (!Array.isArray(data.enumerationResults.containers.container)) {
// Single item
data.enumerationResults.containers.container = [data.enumerationResults.containers.container];
}
for (const container of data.enumerationResults.containers.container) {
if (container.metadata === '') {
delete container.metadata;
}
}
return {
containers: data.enumerationResults.containers.container,
maxResults: data.enumerationResults.maxResults,
nextMarker: data.enumerationResults.nextMarker,
};
}
async function getBlobs(filter, paginationToken) {
const container = this.getNodeParameter('container');
let response;
const qs = {
restype: 'container',
comp: 'list',
};
if (paginationToken) {
qs.marker = paginationToken;
response = await azureStorageApiRequest.call(this, 'GET', `/${container.value}`, {}, qs);
}
else {
qs.maxresults = 5000;
if (filter) {
qs.prefix = filter;
}
response = await azureStorageApiRequest.call(this, 'GET', `/${container.value}`, {}, qs);
}
const data = await parseBlobList(response);
const results = data.blobs
.map((c) => ({
name: c.name,
value: c.name,
}))
.sort((a, b) => a.name.localeCompare(b.name, undefined, { numeric: true, sensitivity: 'base' }));
return {
results,
paginationToken: data.nextMarker,
};
}
async function getContainers(filter, paginationToken) {
let response;
const qs = {
comp: 'list',
};
if (paginationToken) {
qs.marker = paginationToken;
response = await azureStorageApiRequest.call(this, 'GET', '/', {}, qs);
}
else {
qs.maxresults = 5000;
if (filter) {
qs.prefix = filter;
}
response = await azureStorageApiRequest.call(this, 'GET', '/', {}, qs);
}
const data = await parseContainerList(response);
const results = data.containers
.map((c) => ({
name: c.name,
value: c.name,
}))
.sort((a, b) => a.name.localeCompare(b.name, undefined, { numeric: true, sensitivity: 'base' }));
return {
results,
paginationToken: data.nextMarker,
};
}
//# sourceMappingURL=GenericFunctions.js.map