docs: Branding tweaks for Cal and Citrix ADC (no-changelog) (#10042)

This commit is contained in:
Jon
2024-07-15 15:16:41 +01:00
committed by GitHub
parent 0b021ab6a5
commit ef8c867ec7
12 changed files with 45 additions and 27 deletions

View File

@@ -0,0 +1,457 @@
import type { INodeProperties } from 'n8n-workflow';
export const certificateDescription: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Create',
value: 'create',
action: 'Create a certificate',
},
{
name: 'Install',
value: 'install',
action: 'Install a certificate',
},
],
default: 'create',
displayOptions: {
show: {
resource: ['certificate'],
},
},
},
/* -------------------------------------------------------------------------- */
/* certificate:create */
/* -------------------------------------------------------------------------- */
{
displayName: 'Certificate File Name',
name: 'certificateFileName',
type: 'string',
required: true,
displayOptions: {
show: {
resource: ['certificate'],
operation: ['create'],
},
},
default: '',
description:
'Name for and, optionally, path to the generated certificate file. /nsconfig/ssl/ is the default path.',
},
{
displayName: 'Certificate Format',
name: 'certificateFormat',
type: 'options',
options: [
{
name: 'PEM',
value: 'PEM',
},
{
name: 'DER',
value: 'DER',
},
],
required: true,
displayOptions: {
show: {
resource: ['certificate'],
operation: ['create'],
},
},
default: 'PEM',
description: 'Format in which the certificate is stored on the appliance',
},
{
displayName: 'Certificate Type',
name: 'certificateType',
type: 'options',
options: [
{
name: 'Root-CA',
value: 'ROOT_CERT',
description:
'You must specify the key file name. The generated Root-CA certificate can be used for signing end-user client or server certificates or to create Intermediate-CA certificates.',
},
{
name: 'Intermediate-CA',
value: 'INTM_CERT',
description: 'Intermediate-CA certificate',
},
{
name: 'Server',
value: 'SRVR_CERT',
description: 'SSL server certificate used on SSL servers for end-to-end encryption',
},
{
name: 'Client',
value: 'CLNT_CERT',
description: 'End-user client certificate used for client authentication',
},
],
required: true,
displayOptions: {
show: {
resource: ['certificate'],
operation: ['create'],
},
},
default: 'ROOT_CERT',
},
{
displayName: 'Certificate Request File Name',
name: 'certificateRequestFileName',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
operation: ['create'],
resource: ['certificate'],
},
},
description:
'Name for and, optionally, path to the certificate-signing request (CSR). /nsconfig/ssl/ is the default path.',
},
{
displayName: 'CA Certificate File Name',
name: 'caCertificateFileName',
type: 'string',
required: true,
displayOptions: {
show: {
resource: ['certificate'],
operation: ['create'],
certificateType: ['INTM_CERT', 'SRVR_CERT', 'CLNT_CERT'],
},
},
default: '',
description:
'Name of the CA certificate file that issues and signs the Intermediate-CA certificate or the end-user client and server certificates',
},
{
displayName: 'CA Certificate File Format',
name: 'caCertificateFileFormat',
type: 'options',
options: [
{
name: 'PEM',
value: 'PEM',
},
{
name: 'DER',
value: 'DER',
},
],
required: true,
displayOptions: {
show: {
resource: ['certificate'],
operation: ['create'],
certificateType: ['INTM_CERT', 'SRVR_CERT', 'CLNT_CERT'],
},
},
default: 'PEM',
description: 'Format of the CA certificate',
},
{
displayName: 'CA Private Key File Name',
name: 'caPrivateKeyFileName',
type: 'string',
required: true,
displayOptions: {
show: {
resource: ['certificate'],
operation: ['create'],
certificateType: ['INTM_CERT', 'SRVR_CERT', 'CLNT_CERT'],
},
},
default: '',
description:
'Private key, associated with the CA certificate that is used to sign the Intermediate-CA certificate or the end-user client and server certificate. If the CA key file is password protected, the user is prompted to enter the pass phrase that was used to encrypt the key.',
},
{
displayName: 'CA Private Key File Format',
name: 'caPrivateKeyFileFormat',
type: 'options',
options: [
{
name: 'PEM',
value: 'PEM',
},
{
name: 'DER',
value: 'DER',
},
],
required: true,
displayOptions: {
show: {
resource: ['certificate'],
operation: ['create'],
certificateType: ['INTM_CERT', 'SRVR_CERT', 'CLNT_CERT'],
},
},
default: 'PEM',
description: 'Format of the CA certificate',
},
{
displayName: 'Private Key File Name',
name: 'privateKeyFileName',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
operation: ['create'],
resource: ['certificate'],
certificateType: ['ROOT_CERT'],
},
},
description:
'Name for and, optionally, path to the private key. You can either use an existing RSA or DSA key that you own or create a new private key on the Netscaler ADC. This file is required only when creating a self-signed Root-CA certificate. The key file is stored in the /nsconfig/ssl directory by default.',
},
{
displayName: 'CA Serial File Number',
name: 'caSerialFileNumber',
type: 'string',
required: true,
displayOptions: {
show: {
resource: ['certificate'],
operation: ['create'],
certificateType: ['INTM_CERT', 'SRVR_CERT', 'CLNT_CERT'],
},
},
default: '',
description:
'Serial number file maintained for the CA certificate. This file contains the serial number of the next certificate to be issued or signed by the CA.',
},
{
displayName: 'Private Key Format',
name: 'privateKeyFormat',
type: 'options',
options: [
{
name: 'PEM',
value: 'PEM',
},
{
name: 'DER',
value: 'DER',
},
],
required: true,
displayOptions: {
show: {
resource: ['certificate'],
operation: ['create'],
certificateType: ['ROOT_CERT'],
},
},
default: 'PEM',
description: 'Format in which the key is stored on the appliance',
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: ['certificate'],
operation: ['create'],
},
},
options: [
{
displayName: 'PEM Passphrase (For Encrypted Key)',
name: 'pempassphrase',
type: 'string',
displayOptions: {
show: {
'/certificateType': ['ROOT_CERT'],
},
},
default: '',
description:
'Name for and, optionally, path to the private key. You can either use an existing RSA or DSA key that you own or create a new private key on the Netscaler ADC. This file is required only when creating a self-signed Root-CA certificate. The key file is stored in the /nsconfig/ssl directory by default.',
},
{
displayName: 'PEM Passphrase (For Encrypted CA Key)',
name: 'pempassphrase',
type: 'string',
displayOptions: {
hide: {
'/certificateType': ['ROOT_CERT'],
},
},
default: '',
description:
'Name for and, optionally, path to the private key. You can either use an existing RSA or DSA key that you own or create a new private key on the Netscaler ADC. This file is required only when creating a self-signed Root-CA certificate. The key file is stored in the /nsconfig/ssl directory by default.',
},
{
displayName: 'Subject Alternative Name',
name: 'subjectaltname',
type: 'string',
default: '',
description:
'Subject Alternative Name (SAN) is an extension to X.509 that allows various values to be associated with a security certificate using a subjectAltName field',
},
{
displayName: 'Validity Period (Number of Days)',
name: 'days',
type: 'string',
default: '',
description:
'Number of days for which the certificate will be valid, beginning with the time and day (system time) of creation',
},
],
},
/* -------------------------------------------------------------------------- */
/* certificate:install */
/* -------------------------------------------------------------------------- */
{
displayName: 'Certificate-Key Pair Name',
name: 'certificateKeyPairName',
type: 'string',
required: true,
displayOptions: {
show: {
resource: ['certificate'],
operation: ['install'],
},
},
default: '',
description: 'Name for the certificate and private-key pair',
},
{
displayName: 'Certificate File Name',
name: 'certificateFileName',
type: 'string',
required: true,
displayOptions: {
show: {
resource: ['certificate'],
operation: ['install'],
},
},
default: '',
description:
'Name of and, optionally, path to the X509 certificate file that is used to form the certificate-key pair. /nsconfig/ssl/ is the default path.',
},
{
displayName: 'Private Key File Name',
name: 'privateKeyFileName',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['certificate'],
operation: ['install'],
},
},
description:
'Name of and, optionally, path to the X509 certificate file that is used to form the certificate-key pair. /nsconfig/ssl/ is the default path.',
},
{
displayName: 'Certificate Format',
name: 'certificateFormat',
type: 'options',
options: [
{
name: 'PEM',
value: 'PEM',
},
{
name: 'DER',
value: 'DER',
},
],
required: true,
displayOptions: {
show: {
resource: ['certificate'],
operation: ['install'],
},
},
default: 'PEM',
description:
'Input format of the certificate and the private-key files. The three formats supported by the appliance are: PEM - Privacy Enhanced Mail DER - Distinguished Encoding Rule PFX - Personal Information Exchange.',
},
{
displayName: 'Password',
name: 'password',
type: 'string',
typeOptions: {
password: true,
},
required: true,
displayOptions: {
show: {
resource: ['certificate'],
operation: ['install'],
certificateFormat: ['PEM'],
},
},
default: '',
description:
'Input format of the certificate and the private-key files. The three formats supported by the appliance are: PEM - Privacy Enhanced Mail DER - Distinguished Encoding Rule PFX - Personal Information Exchange.',
},
{
displayName: 'Notify When Expires',
name: 'notifyExpiration',
type: 'boolean',
required: true,
displayOptions: {
show: {
resource: ['certificate'],
operation: ['install'],
},
},
default: false,
description: 'Whether to alert when the certificate is about to expire',
},
{
displayName: 'Notification Period (Days)',
name: 'notificationPeriod',
type: 'number',
default: 10,
required: true,
typeOptions: {
minValue: 10,
maxValue: 100,
},
displayOptions: {
show: {
resource: ['certificate'],
operation: ['install'],
notifyExpiration: [true],
},
},
description:
'Time, in number of days, before certificate expiration, at which to generate an alert that the certificate is about to expire',
},
{
displayName: 'Certificate Bundle',
name: 'certificateBundle',
type: 'boolean',
default: false,
displayOptions: {
show: {
resource: ['certificate'],
operation: ['install'],
certificateFormat: ['PEM'],
},
},
description:
"Whether to parse the certificate chain as a single file after linking the server certificate to its issuer's certificate within the file",
},
];

View File

@@ -0,0 +1,125 @@
import type { INodeProperties } from 'n8n-workflow';
export const fileDescription: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Delete',
value: 'delete',
action: 'Delete a file',
},
{
name: 'Download',
value: 'download',
action: 'Download a file',
},
{
name: 'Upload',
value: 'upload',
action: 'Upload a file',
},
],
default: 'upload',
displayOptions: {
show: {
resource: ['file'],
},
},
},
// Upload --------------------------------------------------------------------------
{
displayName: 'File Location',
name: 'fileLocation',
type: 'string',
required: true,
displayOptions: {
show: {
operation: ['upload'],
resource: ['file'],
},
},
default: '/nsconfig/ssl/',
},
{
displayName: 'Input Data Field Name',
name: 'binaryProperty',
type: 'string',
required: true,
displayOptions: {
show: {
operation: ['upload'],
resource: ['file'],
},
},
default: 'data',
description: 'The name of the incoming field containing the binary file data to be processed',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
operation: ['upload'],
resource: ['file'],
},
},
options: [
{
displayName: 'File Name',
name: 'fileName',
type: 'string',
default: '',
description: 'Name of the file. It should not include filepath.',
},
],
},
// Delete, Download ---------------------------------------------------------------
{
displayName: 'File Location',
name: 'fileLocation',
type: 'string',
required: true,
displayOptions: {
show: {
operation: ['delete', 'download'],
resource: ['file'],
},
},
default: '/nsconfig/ssl/',
},
{
displayName: 'File Name',
name: 'fileName',
type: 'string',
default: '',
required: true,
description: 'Name of the file. It should not include filepath.',
displayOptions: {
show: {
operation: ['delete', 'download'],
resource: ['file'],
},
},
},
{
displayName: 'Put Output in Field',
name: 'binaryProperty',
type: 'string',
required: true,
default: 'data',
description: 'The name of the output field to put the binary file data in',
displayOptions: {
show: {
operation: ['download'],
resource: ['file'],
},
},
},
];

View File

@@ -0,0 +1,42 @@
import type {
IExecuteFunctions,
ILoadOptionsFunctions,
IDataObject,
IHookFunctions,
IWebhookFunctions,
JsonObject,
IHttpRequestMethods,
IRequestOptions,
} from 'n8n-workflow';
import { NodeApiError } from 'n8n-workflow';
export async function netscalerADCApiRequest(
this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions,
method: IHttpRequestMethods,
resource: string,
body: IDataObject = {},
qs: IDataObject = {},
uri?: string,
option: IDataObject = {},
): Promise<any> {
const { url } = (await this.getCredentials('citrixAdcApi')) as { url: string };
let options: IRequestOptions = {
headers: {
'Content-Type': 'application/json',
},
method,
body,
qs,
uri: uri || `${url.replace(new RegExp('/$'), '')}/nitro/v1${resource}`,
json: true,
};
options = Object.assign({}, options, option);
try {
return await this.helpers.requestWithAuthentication.call(this, 'citrixAdcApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error as JsonObject);
}
}

View File

@@ -0,0 +1,19 @@
{
"node": "n8n-nodes-base.netscalerAdc",
"nodeVersion": "1.0",
"codexVersion": "1.0",
"categories": ["Development"],
"resources": {
"credentialDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/credentials/netscalerAdc/"
}
],
"primaryDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.netscaleradc/"
}
]
},
"alias": ["Citrix"]
}

View File

@@ -0,0 +1,253 @@
/* eslint-disable n8n-nodes-base/node-filename-against-convention */
import type {
IDataObject,
IExecuteFunctions,
INodeExecutionData,
INodeType,
INodeTypeDescription,
JsonObject,
} from 'n8n-workflow';
import { netscalerADCApiRequest } from './GenericFunctions';
import { fileDescription } from './FileDescription';
import { certificateDescription } from './CertificateDescription';
export class NetscalerAdc implements INodeType {
description: INodeTypeDescription = {
displayName: 'Netscaler ADC',
// This prevents a breaking change
name: 'citrixAdc',
icon: { light: 'file:netscaler.svg', dark: 'file:netscaler.dark.svg' },
group: ['output'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Consume Netscaler ADC API',
defaults: {
name: 'Netscaler ADC',
},
credentials: [
{
name: 'citrixAdcApi',
required: true,
},
],
inputs: ['main'],
outputs: ['main'],
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Certificate',
value: 'certificate',
},
{
name: 'File',
value: 'file',
},
],
default: 'file',
},
...certificateDescription,
...fileDescription,
],
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const returnData: IDataObject[] = [];
const resource = this.getNodeParameter('resource', 0);
const operation = this.getNodeParameter('operation', 0);
let responseData: IDataObject | IDataObject[] = {};
for (let i = 0; i < items.length; i++) {
try {
if (resource === 'file') {
if (operation === 'upload') {
const fileLocation = this.getNodeParameter('fileLocation', i) as string;
const binaryProperty = this.getNodeParameter('binaryProperty', i);
const options = this.getNodeParameter('options', i);
const endpoint = '/config/systemfile';
const binaryData = this.helpers.assertBinaryData(i, binaryProperty);
const buffer = await this.helpers.getBinaryDataBuffer(i, binaryProperty);
const body = {
systemfile: {
filename: binaryData.fileName,
filecontent: Buffer.from(buffer).toString('base64'),
filelocation: fileLocation,
fileencoding: 'BASE64',
},
};
if (options.fileName) {
body.systemfile.filename = options.fileName as string;
}
await netscalerADCApiRequest.call(this, 'POST', endpoint, body);
responseData = { success: true };
}
if (operation === 'delete') {
const fileName = this.getNodeParameter('fileName', i) as string;
const fileLocation = this.getNodeParameter('fileLocation', i) as string;
const endpoint = `/config/systemfile?args=filename:${fileName},filelocation:${encodeURIComponent(
fileLocation,
)}`;
await netscalerADCApiRequest.call(this, 'DELETE', endpoint);
responseData = { success: true };
}
if (operation === 'download') {
const fileName = this.getNodeParameter('fileName', i) as string;
const fileLocation = this.getNodeParameter('fileLocation', i) as string;
const binaryProperty = this.getNodeParameter('binaryProperty', i);
const endpoint = `/config/systemfile?args=filename:${fileName},filelocation:${encodeURIComponent(
fileLocation,
)}`;
const { systemfile } = await netscalerADCApiRequest.call(this, 'GET', endpoint);
const file = systemfile[0];
const binaryData = await this.helpers.prepareBinaryData(
Buffer.from(file.filecontent as string, 'base64'),
file.filename as string,
);
responseData = {
json: file,
binary: {
[binaryProperty]: binaryData,
},
};
}
}
if (resource === 'certificate') {
if (operation === 'create') {
const certificateFileName = this.getNodeParameter('certificateFileName', i) as string;
const certificateFormat = this.getNodeParameter('certificateFormat', i) as string;
const certificateType = this.getNodeParameter('certificateType', i) as string;
const certificateRequestFileName = this.getNodeParameter(
'certificateRequestFileName',
i,
) as string;
const additionalFields = this.getNodeParameter('additionalFields', i, {});
let body: IDataObject = {
reqfile: certificateRequestFileName,
certfile: certificateFileName,
certform: certificateFormat,
certType: certificateType,
...additionalFields,
};
if (certificateType === 'ROOT_CERT') {
const privateKeyFileName = this.getNodeParameter('privateKeyFileName', i) as string;
body = {
...body,
keyfile: privateKeyFileName,
};
} else {
const caCertificateFileName = this.getNodeParameter(
'caCertificateFileName',
i,
) as string;
const caCertificateFileFormat = this.getNodeParameter(
'caCertificateFileFormat',
i,
) as string;
const caPrivateKeyFileFormat = this.getNodeParameter(
'caPrivateKeyFileFormat',
i,
) as string;
const caPrivateKeyFileName = this.getNodeParameter(
'caPrivateKeyFileName',
i,
) as string;
const caSerialFileNumber = this.getNodeParameter('caSerialFileNumber', i) as string;
body = {
...body,
cacert: caCertificateFileName,
cacertform: caCertificateFileFormat,
cakey: caPrivateKeyFileName,
cakeyform: caPrivateKeyFileFormat,
caserial: caSerialFileNumber,
};
}
const endpoint = '/config/sslcert?action=create';
await netscalerADCApiRequest.call(this, 'POST', endpoint, { sslcert: body });
responseData = { success: true };
}
if (operation === 'install') {
const certificateKeyPairName = this.getNodeParameter(
'certificateKeyPairName',
i,
) as string;
const certificateFileName = this.getNodeParameter('certificateFileName', i) as string;
const privateKeyFileName = this.getNodeParameter('privateKeyFileName', i) as string;
const certificateFormat = this.getNodeParameter('certificateFormat', i) as string;
const notifyExpiration = this.getNodeParameter('notifyExpiration', i) as boolean;
const body: IDataObject = {
cert: certificateFileName,
certkey: certificateKeyPairName,
key: privateKeyFileName,
inform: certificateFormat,
};
if (certificateFormat === 'PEM') {
const password = this.getNodeParameter('password', i) as string;
const certificateBundle = this.getNodeParameter('certificateBundle', i) as boolean;
Object.assign(body, {
passplain: password,
bundle: certificateBundle ? 'YES' : 'NO',
});
}
if (notifyExpiration) {
const notificationPeriod = this.getNodeParameter('notificationPeriod', i) as number;
Object.assign(body, {
expirymonitor: 'ENABLED',
notificationperiod: notificationPeriod,
});
}
const endpoint = '/config/sslcertkey';
await netscalerADCApiRequest.call(this, 'POST', endpoint, { sslcertkey: body });
responseData = { success: true };
}
}
returnData.push(
...this.helpers.constructExecutionMetaData(this.helpers.returnJsonArray(responseData), {
itemData: { item: i },
}),
);
} catch (error) {
if (this.continueOnFail(error)) {
returnData.push({ error: (error as JsonObject).toString() });
continue;
}
throw error;
}
}
return [returnData as INodeExecutionData[]];
}
}

View File

@@ -0,0 +1,3 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19.5206 27.2873L9.29324 39.2473C8.88891 39.7695 8.36894 40 7.79043 40C6.7505 40 6 39.1905 6 38.2663C6 37.8616 6.11527 37.3983 6.51997 36.9373L17.2095 24.8608L6.92467 13.0739C6.51996 12.6105 6.28943 12.2059 6.28943 11.686C6.28943 10.7615 7.03994 9.95234 8.13841 9.95234C8.71474 9.95234 9.11944 10.185 9.58268 10.7051L19.5206 22.3755L29.4585 10.7051C29.9221 10.185 30.3268 9.95234 30.9031 9.95234C32.0016 9.95234 32.7521 10.7615 32.7521 11.686C32.7521 12.2059 32.5216 12.6105 32.1169 13.0739L21.8321 24.8608L32.5216 36.9373C32.9263 37.3983 33.0415 37.8616 33.0415 38.2663C33.0415 39.1905 32.291 40 31.2511 40C30.6722 40 30.1526 39.7694 29.7479 39.2473L19.5206 27.2873ZM22.472 2.95109C22.472 4.58094 21.1507 5.90231 19.5206 5.90231C17.8909 5.90231 16.5695 4.58094 16.5695 2.95109C16.5695 1.32137 17.8909 -3.9211e-07 19.5206 -3.9211e-07C21.1507 -3.9211e-07 22.472 1.32137 22.472 2.95109Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1013 B

View File

@@ -0,0 +1,3 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19.5206 27.2873L9.29324 39.2473C8.88891 39.7695 8.36894 40 7.79043 40C6.7505 40 6 39.1905 6 38.2663C6 37.8616 6.11527 37.3983 6.51997 36.9373L17.2095 24.8608L6.92467 13.0739C6.51996 12.6105 6.28943 12.2059 6.28943 11.686C6.28943 10.7615 7.03994 9.95234 8.13841 9.95234C8.71474 9.95234 9.11944 10.185 9.58268 10.7051L19.5206 22.3755L29.4585 10.7051C29.9221 10.185 30.3268 9.95234 30.9031 9.95234C32.0016 9.95234 32.7521 10.7615 32.7521 11.686C32.7521 12.2059 32.5216 12.6105 32.1169 13.0739L21.8321 24.8608L32.5216 36.9373C32.9263 37.3983 33.0415 37.8616 33.0415 38.2663C33.0415 39.1905 32.291 40 31.2511 40C30.6722 40 30.1526 39.7694 29.7479 39.2473L19.5206 27.2873ZM22.472 2.95109C22.472 4.58094 21.1507 5.90231 19.5206 5.90231C17.8909 5.90231 16.5695 4.58094 16.5695 2.95109C16.5695 1.32137 17.8909 -3.9211e-07 19.5206 -3.9211e-07C21.1507 -3.9211e-07 22.472 1.32137 22.472 2.95109Z" fill="#100F0D"/>
</svg>

After

Width:  |  Height:  |  Size: 1015 B