first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,394 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const certificateOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
noDataExpression: true,
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['certificate'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a certificate',
|
||||
action: 'Delete a certificate',
|
||||
},
|
||||
{
|
||||
name: 'Download',
|
||||
value: 'download',
|
||||
description: 'Download a certificate',
|
||||
action: 'Download a certificate',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Retrieve a certificate',
|
||||
action: 'Get a certificate',
|
||||
},
|
||||
{
|
||||
name: 'Get Many',
|
||||
value: 'getMany',
|
||||
description: 'Retrieve many certificates',
|
||||
action: 'Get many certificates',
|
||||
},
|
||||
{
|
||||
name: 'Renew',
|
||||
value: 'renew',
|
||||
description: 'Renew a certificate',
|
||||
action: 'Renew a certificate',
|
||||
},
|
||||
],
|
||||
default: 'delete',
|
||||
},
|
||||
];
|
||||
|
||||
export const certificateFields: INodeProperties[] = [
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* certificate:download */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Certificate ID',
|
||||
name: 'certificateId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['download'],
|
||||
resource: ['certificate'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Download Item',
|
||||
name: 'downloadItem',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Certificate',
|
||||
value: 'certificate',
|
||||
},
|
||||
{
|
||||
name: 'Keystore',
|
||||
value: 'keystore',
|
||||
},
|
||||
],
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['download'],
|
||||
resource: ['certificate'],
|
||||
},
|
||||
},
|
||||
default: 'certificate',
|
||||
},
|
||||
{
|
||||
displayName: 'Keystore Type',
|
||||
name: 'keystoreType',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'JKS',
|
||||
value: 'JKS',
|
||||
},
|
||||
{
|
||||
name: 'PKCS12',
|
||||
value: 'PKCS12',
|
||||
},
|
||||
{
|
||||
name: 'PEM',
|
||||
value: 'PEM',
|
||||
},
|
||||
],
|
||||
default: 'PEM',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['download'],
|
||||
resource: ['certificate'],
|
||||
downloadItem: ['keystore'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Certificate Label',
|
||||
name: 'certificateLabel',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['download'],
|
||||
resource: ['certificate'],
|
||||
downloadItem: ['keystore'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Private Key Passphrase',
|
||||
name: 'privateKeyPassphrase',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['download'],
|
||||
resource: ['certificate'],
|
||||
downloadItem: ['keystore'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Keystore Passphrase',
|
||||
name: 'keystorePassphrase',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['download'],
|
||||
resource: ['certificate'],
|
||||
downloadItem: ['keystore'],
|
||||
keystoreType: ['JKS'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Input Data Field Name',
|
||||
name: 'binaryProperty',
|
||||
type: 'string',
|
||||
default: 'data',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['download'],
|
||||
resource: ['certificate'],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
description: 'The name of the input field containing the binary file data to be uploaded',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['download'],
|
||||
resource: ['certificate'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Chain Order',
|
||||
name: 'chainOrder',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'EE_FIRST',
|
||||
value: 'EE_FIRST',
|
||||
description: 'Download the certificate with the end-entity portion of the chain first',
|
||||
},
|
||||
{
|
||||
name: 'EE_ONLY',
|
||||
value: 'EE_ONLY',
|
||||
description: 'Download only the end-entity certificate',
|
||||
},
|
||||
{
|
||||
name: 'ROOT_FIRST',
|
||||
value: 'ROOT_FIRST',
|
||||
description: 'Download the certificate with root portion of the chain first',
|
||||
},
|
||||
],
|
||||
default: 'ROOT_FIRST',
|
||||
},
|
||||
{
|
||||
displayName: 'Format',
|
||||
name: 'format',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'PEM',
|
||||
value: 'PEM',
|
||||
},
|
||||
{
|
||||
name: 'DER',
|
||||
value: 'DER',
|
||||
},
|
||||
],
|
||||
default: 'PEM',
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* certificate:get */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Certificate ID',
|
||||
name: 'certificateId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['get', 'delete'],
|
||||
resource: ['certificate'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* certificate:getMany */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['getMany'],
|
||||
resource: ['certificate'],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'Whether to return all results or only up to a given limit',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['getMany'],
|
||||
resource: ['certificate'],
|
||||
returnAll: [false],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 500,
|
||||
},
|
||||
default: 50,
|
||||
description: 'Max number of results to return',
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['getMany'],
|
||||
resource: ['certificate'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Subject',
|
||||
name: 'subject',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* certificate:renew */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Application Name or ID',
|
||||
name: 'applicationId',
|
||||
type: 'options',
|
||||
description:
|
||||
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getApplications',
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['renew'],
|
||||
resource: ['certificate'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Existing Certificate ID',
|
||||
name: 'existingCertificateId',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['renew'],
|
||||
resource: ['certificate'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Certificate Issuing Template Name or ID',
|
||||
name: 'certificateIssuingTemplateId',
|
||||
type: 'options',
|
||||
description:
|
||||
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getCertificateIssuingTemplates',
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['renew'],
|
||||
resource: ['certificate'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Certificate Signing Request',
|
||||
name: 'certificateSigningRequest',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['renew'],
|
||||
resource: ['certificate'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['renew'],
|
||||
resource: ['certificate'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Validity Period',
|
||||
name: 'validityPeriod',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: '1 Year',
|
||||
value: 'P1Y',
|
||||
},
|
||||
{
|
||||
name: '10 Days',
|
||||
value: 'P10D',
|
||||
},
|
||||
{
|
||||
name: '12 Hours',
|
||||
value: 'PT12H',
|
||||
},
|
||||
],
|
||||
default: 'P1Y',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,41 @@
|
||||
export interface ICertficateRequest {
|
||||
isVaaSGenerated?: boolean;
|
||||
csrAttributes?: ICsrAttributes;
|
||||
applicationServerTypeId?: string;
|
||||
certificateSigningRequest?: string;
|
||||
applicationId?: string;
|
||||
certificateIssuingTemplateId?: string;
|
||||
certficateOwnerUserId?: string;
|
||||
validityPeriod?: string;
|
||||
}
|
||||
|
||||
export interface ICsrAttributes {
|
||||
commonName?: string;
|
||||
organization?: string;
|
||||
organizationalUnits?: string[];
|
||||
locality?: string;
|
||||
state?: string;
|
||||
country?: string;
|
||||
keyTypeParameters?: IKeyTypeParameters;
|
||||
subjectAlternativeNamesByType?: ISubjectAltNamesByType;
|
||||
}
|
||||
|
||||
export interface IKeyTypeParameters {
|
||||
keyType?: string;
|
||||
keyCurve?: string;
|
||||
keyLength?: number;
|
||||
}
|
||||
|
||||
export interface ISubjectAltNamesByType {
|
||||
dnsNames?: string[];
|
||||
rfc822Names?: string[];
|
||||
ipAddresses?: string[];
|
||||
uniformResourceIdentifiers?: string[];
|
||||
}
|
||||
|
||||
export interface ICertficateKeystoreRequest {
|
||||
exportFormat?: string;
|
||||
encryptedPrivateKeyPassphrase?: string;
|
||||
encryptedKeystorePassphrase?: string;
|
||||
certificateLabel?: string;
|
||||
}
|
||||
@@ -0,0 +1,359 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const certificateRequestOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
noDataExpression: true,
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['certificateRequest'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a new certificate request',
|
||||
action: 'Create a certificate request',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Retrieve a certificate request',
|
||||
action: 'Get a certificate request',
|
||||
},
|
||||
{
|
||||
name: 'Get Many',
|
||||
value: 'getMany',
|
||||
description: 'Retrieve many certificate requests',
|
||||
action: 'Get many certificate requests',
|
||||
},
|
||||
],
|
||||
default: 'create',
|
||||
},
|
||||
];
|
||||
|
||||
export const certificateRequestFields: INodeProperties[] = [
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* certificateRequest:create */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Application Name or ID',
|
||||
name: 'applicationId',
|
||||
type: 'options',
|
||||
description:
|
||||
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getApplications',
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['create'],
|
||||
resource: ['certificateRequest'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Certificate Issuing Template Name or ID',
|
||||
name: 'certificateIssuingTemplateId',
|
||||
type: 'options',
|
||||
description:
|
||||
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getCertificateIssuingTemplates',
|
||||
loadOptionsDependsOn: ['applicationId'],
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['create'],
|
||||
resource: ['certificateRequest'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Generate CSR',
|
||||
name: 'generateCsr',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['create'],
|
||||
resource: ['certificateRequest'],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Common Name',
|
||||
name: 'commonName',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['create'],
|
||||
resource: ['certificateRequest'],
|
||||
generateCsr: [true],
|
||||
},
|
||||
},
|
||||
type: 'string',
|
||||
default: 'n8n.io',
|
||||
description: 'The Common Name field for the certificate Subject (CN)',
|
||||
},
|
||||
// Optional...
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['create'],
|
||||
resource: ['certificateRequest'],
|
||||
generateCsr: [true],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Key Type',
|
||||
name: 'keyType',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'EC',
|
||||
value: 'EC',
|
||||
description: 'Elliptic Curve (EC)',
|
||||
},
|
||||
{
|
||||
name: 'RSA',
|
||||
value: 'RSA',
|
||||
description: 'Rivest, Shamir, Adleman key (RSA)',
|
||||
},
|
||||
],
|
||||
default: 'RSA',
|
||||
description: 'The encryption algorithm for the public key',
|
||||
},
|
||||
{
|
||||
displayName: 'Key Curve',
|
||||
name: 'keyCurve',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'ED25519',
|
||||
value: 'ED25519',
|
||||
description: 'Use Edwards-curve Digital Signature Algorithm (EdDSA)',
|
||||
},
|
||||
{
|
||||
name: 'P256',
|
||||
value: 'P256',
|
||||
description: 'Use Elliptic Prime Curve 256 bit encryption',
|
||||
},
|
||||
{
|
||||
name: 'P384',
|
||||
value: 'P384',
|
||||
description: 'Use Elliptic Prime Curve 384 bit encryption',
|
||||
},
|
||||
{
|
||||
name: 'P521',
|
||||
value: 'P521',
|
||||
description: 'Use Elliptic Prime Curve 521 bit encryption',
|
||||
},
|
||||
{
|
||||
name: 'UNKNOWN',
|
||||
value: 'UNKNOWN',
|
||||
},
|
||||
],
|
||||
default: 'ED25519',
|
||||
},
|
||||
{
|
||||
displayName: 'Key Length',
|
||||
name: 'keyLength',
|
||||
type: 'number',
|
||||
default: 2048,
|
||||
description: 'The number of bits to allow for key generation',
|
||||
},
|
||||
{
|
||||
displayName: '(O) Organization',
|
||||
name: 'organization',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The name of a company or organization',
|
||||
},
|
||||
{
|
||||
displayName: '(OU) Organizational Unit(s)',
|
||||
name: 'organizationalUnits',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
default: '',
|
||||
description: 'The name of a department or section',
|
||||
},
|
||||
{
|
||||
displayName: '(L) City/Locality',
|
||||
name: 'locality',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The name of a city or town',
|
||||
},
|
||||
|
||||
{
|
||||
displayName: '(ST) State',
|
||||
name: 'state',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The name of a state or province',
|
||||
},
|
||||
{
|
||||
displayName: '(C) Country',
|
||||
name: 'country',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'A 2 letter country code',
|
||||
},
|
||||
{
|
||||
displayName: 'Subject Alt Names',
|
||||
name: 'SubjectAltNamesUi',
|
||||
placeholder: 'Add Subject',
|
||||
type: 'fixedCollection',
|
||||
default: {},
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'SubjectAltNamesValues',
|
||||
displayName: 'Subject Alt Name',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Typename',
|
||||
name: 'Typename',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'DNS',
|
||||
value: 'dnsNames',
|
||||
},
|
||||
/*{
|
||||
name: 'IP Address',
|
||||
value: 'ipAddresses',
|
||||
},
|
||||
{
|
||||
name: 'RFC822 Names',
|
||||
value: 'rfc822Names',
|
||||
},
|
||||
|
||||
{
|
||||
name: 'URI',
|
||||
value: 'uniformResourceIdentifiers',
|
||||
},*/
|
||||
],
|
||||
description: 'What type of SAN is being used',
|
||||
default: 'dnsNames',
|
||||
},
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: 'community.n8n.io',
|
||||
description:
|
||||
'The SAN friendly name that corresponds to the Type or TypeName parameter. For example, if a TypeName is IPAddress, the Name value is a valid IP address.',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
// End CSR Builder
|
||||
{
|
||||
displayName: 'Certificate Signing Request',
|
||||
name: 'certificateSigningRequest',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['create'],
|
||||
resource: ['certificateRequest'],
|
||||
generateCsr: [false],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['create'],
|
||||
resource: ['certificateRequest'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Validity Period',
|
||||
name: 'validityPeriod',
|
||||
type: 'string',
|
||||
placeholder: 'P1Y',
|
||||
default: 'P1Y',
|
||||
description:
|
||||
'Specify how long the issued certificate should be valid for. Use ISO8601 format.',
|
||||
hint: 'e.g. 1 year -> P1Y',
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* certificateRequest:get */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Certificate Request ID',
|
||||
name: 'certificateRequestId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['get'],
|
||||
resource: ['certificateRequest'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* certificateRequest:getMany */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['getMany'],
|
||||
resource: ['certificateRequest'],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'Whether to return all results or only up to a given limit',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['getMany'],
|
||||
resource: ['certificateRequest'],
|
||||
returnAll: [false],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 500,
|
||||
},
|
||||
default: 50,
|
||||
description: 'Max number of results to return',
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,143 @@
|
||||
import * as nacl_factory from 'js-nacl';
|
||||
import get from 'lodash/get';
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
IDataObject,
|
||||
IHookFunctions,
|
||||
JsonObject,
|
||||
IHttpRequestMethods,
|
||||
IRequestOptions,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeApiError } from 'n8n-workflow';
|
||||
|
||||
export async function venafiApiRequest(
|
||||
this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions,
|
||||
method: IHttpRequestMethods,
|
||||
resource: string,
|
||||
body = {},
|
||||
qs: IDataObject = {},
|
||||
option: IDataObject = {},
|
||||
): Promise<any> {
|
||||
const operation = this.getNodeParameter('operation', 0);
|
||||
const credentials = await this.getCredentials('venafiTlsProtectCloudApi');
|
||||
|
||||
const region = credentials.region ?? 'cloud';
|
||||
|
||||
const options: IRequestOptions = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
method,
|
||||
body,
|
||||
qs,
|
||||
uri: `https://api.venafi.${region}${resource}`,
|
||||
json: true,
|
||||
};
|
||||
|
||||
if (Object.keys(option).length) {
|
||||
Object.assign(options, option);
|
||||
}
|
||||
|
||||
// For cert download we don't need any headers
|
||||
// If we remove for everything the key fetch fails
|
||||
if (operation === 'download') {
|
||||
// We need content-type for keystore
|
||||
if (!resource.endsWith('keystore')) {
|
||||
delete options.headers!.Accept;
|
||||
delete options.headers!['content-type'];
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (Object.keys(body).length === 0) {
|
||||
delete options.body;
|
||||
}
|
||||
return await this.helpers.requestWithAuthentication.call(
|
||||
this,
|
||||
'venafiTlsProtectCloudApi',
|
||||
options,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error as JsonObject);
|
||||
}
|
||||
}
|
||||
|
||||
export async function venafiApiRequestAllItems(
|
||||
this: IExecuteFunctions | ILoadOptionsFunctions,
|
||||
propertyName: string,
|
||||
method: IHttpRequestMethods,
|
||||
endpoint: string,
|
||||
|
||||
body: IDataObject = {},
|
||||
query: IDataObject = {},
|
||||
) {
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
let responseData;
|
||||
|
||||
do {
|
||||
responseData = await venafiApiRequest.call(this, method, endpoint, body, query);
|
||||
endpoint = get(responseData, '_links[0].Next');
|
||||
returnData.push.apply(returnData, responseData[propertyName] as IDataObject[]);
|
||||
} while (responseData._links?.[0].Next);
|
||||
|
||||
return returnData;
|
||||
}
|
||||
|
||||
export async function encryptPassphrase(
|
||||
this: IExecuteFunctions | ILoadOptionsFunctions,
|
||||
certificateId: string,
|
||||
passphrase: string,
|
||||
storePassphrase: string,
|
||||
) {
|
||||
let dekHash = '';
|
||||
const dekResponse = await venafiApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/outagedetection/v1/certificates/${certificateId}`,
|
||||
);
|
||||
|
||||
if (dekResponse.dekHash) {
|
||||
dekHash = dekResponse.dekHash;
|
||||
}
|
||||
|
||||
let pubKey = '';
|
||||
const pubKeyResponse = await venafiApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/v1/edgeencryptionkeys/${dekHash}`,
|
||||
);
|
||||
|
||||
if (pubKeyResponse.key) {
|
||||
pubKey = pubKeyResponse.key;
|
||||
}
|
||||
|
||||
let encryptedKeyPass = '';
|
||||
let encryptedKeyStorePass = '';
|
||||
|
||||
const promise = async () => {
|
||||
return await new Promise((resolve, reject) => {
|
||||
nacl_factory.instantiate((nacl: any) => {
|
||||
try {
|
||||
const passphraseUTF8 = nacl.encode_utf8(passphrase) as string;
|
||||
const keyPassBuffer = nacl.crypto_box_seal(passphraseUTF8, Buffer.from(pubKey, 'base64'));
|
||||
encryptedKeyPass = Buffer.from(keyPassBuffer as Buffer).toString('base64');
|
||||
|
||||
const storePassphraseUTF8 = nacl.encode_utf8(storePassphrase) as string;
|
||||
const keyStorePassBuffer = nacl.crypto_box_seal(
|
||||
storePassphraseUTF8,
|
||||
Buffer.from(pubKey, 'base64'),
|
||||
);
|
||||
encryptedKeyStorePass = Buffer.from(keyStorePassBuffer as Buffer).toString('base64');
|
||||
|
||||
return resolve([encryptedKeyPass, encryptedKeyStorePass]);
|
||||
} catch (error) {
|
||||
return reject(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
return await promise();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"node": "n8n-nodes-base.venafiTlsProtectCloud",
|
||||
"nodeVersion": "1.0",
|
||||
"codexVersion": "1.0",
|
||||
"categories": ["Development"],
|
||||
"resources": {
|
||||
"credentialDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/credentials/venafitlsprotectcloud/"
|
||||
}
|
||||
],
|
||||
"primaryDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.venafitlsprotectcloud/"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,469 @@
|
||||
import {
|
||||
type IExecuteFunctions,
|
||||
type IDataObject,
|
||||
type ILoadOptionsFunctions,
|
||||
type INodeExecutionData,
|
||||
type INodePropertyOptions,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
NodeConnectionTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { certificateFields, certificateOperations } from './CertificateDescription';
|
||||
import type {
|
||||
ICertficateKeystoreRequest,
|
||||
ICertficateRequest,
|
||||
ICsrAttributes,
|
||||
IKeyTypeParameters,
|
||||
ISubjectAltNamesByType,
|
||||
} from './CertificateInterface';
|
||||
import {
|
||||
certificateRequestFields,
|
||||
certificateRequestOperations,
|
||||
} from './CertificateRequestDescription';
|
||||
import { encryptPassphrase, venafiApiRequest, venafiApiRequestAllItems } from './GenericFunctions';
|
||||
|
||||
export class VenafiTlsProtectCloud implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Venafi TLS Protect Cloud',
|
||||
name: 'venafiTlsProtectCloud',
|
||||
icon: 'file:../venafi.svg',
|
||||
group: ['input'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||
description: 'Consume Venafi TLS Protect Cloud API',
|
||||
defaults: {
|
||||
name: 'Venafi TLS Protect Cloud',
|
||||
},
|
||||
usableAsTool: true,
|
||||
inputs: [NodeConnectionTypes.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
credentials: [
|
||||
{
|
||||
name: 'venafiTlsProtectCloudApi',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
noDataExpression: true,
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Certificate',
|
||||
value: 'certificate',
|
||||
},
|
||||
{
|
||||
name: 'Certificate Request',
|
||||
value: 'certificateRequest',
|
||||
},
|
||||
],
|
||||
default: 'certificateRequest',
|
||||
},
|
||||
...certificateOperations,
|
||||
...certificateFields,
|
||||
...certificateRequestOperations,
|
||||
...certificateRequestFields,
|
||||
],
|
||||
};
|
||||
|
||||
methods = {
|
||||
loadOptions: {
|
||||
async getApplications(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const { applications } = await venafiApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
'/outagedetection/v1/applications',
|
||||
);
|
||||
|
||||
for (const application of applications) {
|
||||
returnData.push({
|
||||
name: application.name,
|
||||
value: application.id,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
async getCertificateIssuingTemplates(
|
||||
this: ILoadOptionsFunctions,
|
||||
): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const currentApplication: string = this.getCurrentNodeParameter('applicationId') as string;
|
||||
|
||||
const { certificateIssuingTemplateAliasIdMap } = (await venafiApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/outagedetection/v1/applications/${currentApplication}`,
|
||||
)) as { certificateIssuingTemplateAliasIdMap: { [key: string]: string } };
|
||||
|
||||
for (const [templateName, templateId] of Object.entries(
|
||||
certificateIssuingTemplateAliasIdMap,
|
||||
)) {
|
||||
returnData.push({
|
||||
name: templateName,
|
||||
value: templateId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const returnData: IDataObject[] = [];
|
||||
const length = items.length;
|
||||
const qs: IDataObject = {};
|
||||
let responseData;
|
||||
const resource = this.getNodeParameter('resource', 0);
|
||||
const operation = this.getNodeParameter('operation', 0);
|
||||
for (let i = 0; i < length; i++) {
|
||||
try {
|
||||
if (resource === 'certificateRequest') {
|
||||
//https://api.venafi.cloud/webjars/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config&urls.primaryName=outagedetection-service#//v1/certificaterequests_create
|
||||
if (operation === 'create') {
|
||||
const applicationId = this.getNodeParameter('applicationId', i) as string;
|
||||
const certificateIssuingTemplateId = this.getNodeParameter(
|
||||
'certificateIssuingTemplateId',
|
||||
i,
|
||||
) as string;
|
||||
const options = this.getNodeParameter('options', i);
|
||||
const generateCsr = this.getNodeParameter('generateCsr', i) as boolean;
|
||||
|
||||
const body: ICertficateRequest = {
|
||||
applicationId,
|
||||
certificateIssuingTemplateId,
|
||||
};
|
||||
|
||||
if (generateCsr) {
|
||||
const commonName = this.getNodeParameter('commonName', i) as string;
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i);
|
||||
|
||||
const keyTypeDetails: IKeyTypeParameters = {};
|
||||
const csrAttributes: ICsrAttributes = {};
|
||||
const subjectAltNamesByType: ISubjectAltNamesByType = {};
|
||||
|
||||
body.isVaaSGenerated = true;
|
||||
|
||||
csrAttributes.commonName = commonName;
|
||||
|
||||
// Csr Generation
|
||||
if (additionalFields.organization) {
|
||||
csrAttributes.organization = additionalFields.organization as string;
|
||||
}
|
||||
if (additionalFields.organizationalUnits) {
|
||||
csrAttributes.organizationalUnits =
|
||||
additionalFields.organizationalUnits as string[];
|
||||
}
|
||||
if (additionalFields.locality) {
|
||||
csrAttributes.locality = additionalFields.locality as string;
|
||||
}
|
||||
if (additionalFields.state) {
|
||||
csrAttributes.state = additionalFields.state as string;
|
||||
}
|
||||
if (additionalFields.country) {
|
||||
csrAttributes.country = additionalFields.country as string;
|
||||
}
|
||||
body.csrAttributes = csrAttributes;
|
||||
|
||||
// Key type
|
||||
if (additionalFields.keyType) {
|
||||
keyTypeDetails.keyType = additionalFields.keyType as string;
|
||||
}
|
||||
if (additionalFields.keyCurve) {
|
||||
keyTypeDetails.keyCurve = additionalFields.keyCurve as string;
|
||||
}
|
||||
if (additionalFields.keyLength) {
|
||||
keyTypeDetails.keyLength = additionalFields.keyLength as number;
|
||||
}
|
||||
if (Object.keys(keyTypeDetails).length !== 0) {
|
||||
body.csrAttributes.keyTypeParameters = keyTypeDetails;
|
||||
}
|
||||
|
||||
// SAN
|
||||
if (additionalFields.SubjectAltNamesUi) {
|
||||
for (const key of (additionalFields.SubjectAltNamesUi as IDataObject)
|
||||
.SubjectAltNamesValues as IDataObject[]) {
|
||||
if (key.Typename === 'dnsNames') {
|
||||
subjectAltNamesByType.dnsNames
|
||||
? subjectAltNamesByType.dnsNames.push(key.name as string)
|
||||
: (subjectAltNamesByType.dnsNames = [key.name as string]);
|
||||
}
|
||||
/*if (key.Typename === 'ipAddresses') {
|
||||
subjectAltNamesByType.ipAddresses ? subjectAltNamesByType.ipAddresses.push(key.name as string) : subjectAltNamesByType.ipAddresses = [key.name as string];
|
||||
}
|
||||
if (key.Typename === 'rfc822Names') {
|
||||
subjectAltNamesByType.rfc822Names ? subjectAltNamesByType.rfc822Names.push(key.name as string) : subjectAltNamesByType.rfc822Names = [key.name as string];
|
||||
}
|
||||
if (key.Typename === 'uniformResourceIdentifiers') {
|
||||
subjectAltNamesByType.uniformResourceIdentifiers ? subjectAltNamesByType.uniformResourceIdentifiers.push(key.name as string) : subjectAltNamesByType.uniformResourceIdentifiers = [key.name as string];
|
||||
}*/
|
||||
}
|
||||
}
|
||||
if (Object.keys(subjectAltNamesByType).length !== 0) {
|
||||
body.csrAttributes.subjectAlternativeNamesByType = subjectAltNamesByType;
|
||||
}
|
||||
} else {
|
||||
const certificateSigningRequest = this.getNodeParameter(
|
||||
'certificateSigningRequest',
|
||||
i,
|
||||
) as string;
|
||||
body.isVaaSGenerated = false;
|
||||
body.certificateSigningRequest = certificateSigningRequest;
|
||||
}
|
||||
|
||||
Object.assign(body, options);
|
||||
|
||||
responseData = await venafiApiRequest.call(
|
||||
this,
|
||||
'POST',
|
||||
'/outagedetection/v1/certificaterequests',
|
||||
body,
|
||||
qs,
|
||||
);
|
||||
|
||||
responseData = responseData.certificateRequests;
|
||||
}
|
||||
|
||||
//https://api.venafi.cloud/webjars/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config&urls.primaryName=outagedetection-service#//v1/certificaterequests_getById
|
||||
if (operation === 'get') {
|
||||
const certificateId = this.getNodeParameter('certificateRequestId', i) as string;
|
||||
|
||||
responseData = await venafiApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/outagedetection/v1/certificaterequests/${certificateId}`,
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
}
|
||||
|
||||
//https://api.venafi.cloud/webjars/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config&urls.primaryName=outagedetection-service#//v1/certificaterequests_getAll
|
||||
if (operation === 'getMany') {
|
||||
const returnAll = this.getNodeParameter('returnAll', i);
|
||||
|
||||
if (returnAll) {
|
||||
responseData = await venafiApiRequestAllItems.call(
|
||||
this,
|
||||
'certificateRequests',
|
||||
'GET',
|
||||
'/outagedetection/v1/certificaterequests',
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
} else {
|
||||
const limit = this.getNodeParameter('limit', i);
|
||||
responseData = await venafiApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
'/outagedetection/v1/certificaterequests',
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
|
||||
responseData = responseData.certificateRequests.splice(0, limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (resource === 'certificate') {
|
||||
//https://api.venafi.cloud/webjars/swagger-ui/index.html?configUrl=%2Fv3%2Fapi-docs%2Fswagger-config&urls.primaryName=outagedetection-service#/%2Fv1/certificateretirement_deleteCertificates
|
||||
if (operation === 'delete') {
|
||||
const certificateId = this.getNodeParameter('certificateId', i) as string;
|
||||
|
||||
responseData = await venafiApiRequest.call(
|
||||
this,
|
||||
'POST',
|
||||
'/outagedetection/v1/certificates/deletion',
|
||||
{ certificateIds: [certificateId] },
|
||||
);
|
||||
|
||||
responseData = responseData.certificates;
|
||||
}
|
||||
|
||||
//https://api.venafi.cloud/webjars/swagger-ui/index.html?configUrl=%2Fv3%2Fapi-docs%2Fswagger-config&urls.primaryName=outagedetection-service#/
|
||||
if (operation === 'download') {
|
||||
const certificateId = this.getNodeParameter('certificateId', i) as string;
|
||||
const binaryProperty = this.getNodeParameter('binaryProperty', i);
|
||||
const downloadItem = this.getNodeParameter('downloadItem', i) as string;
|
||||
const options = this.getNodeParameter('options', i);
|
||||
|
||||
// Cert Download
|
||||
if (downloadItem === 'certificate') {
|
||||
Object.assign(qs, options);
|
||||
responseData = await venafiApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/outagedetection/v1/certificates/${certificateId}/contents`,
|
||||
{},
|
||||
qs,
|
||||
{ encoding: null, json: false, resolveWithFullResponse: true, cert: true },
|
||||
);
|
||||
} else {
|
||||
const exportFormat = this.getNodeParameter('keystoreType', i) as string;
|
||||
|
||||
const body: ICertficateKeystoreRequest = {
|
||||
exportFormat,
|
||||
};
|
||||
|
||||
const privateKeyPassphrase = this.getNodeParameter(
|
||||
'privateKeyPassphrase',
|
||||
i,
|
||||
) as string;
|
||||
const certificateLabel = this.getNodeParameter('certificateLabel', i) as string;
|
||||
|
||||
body.certificateLabel = certificateLabel;
|
||||
|
||||
let keystorePassphrase = '';
|
||||
|
||||
if (exportFormat === 'JKS') {
|
||||
keystorePassphrase = this.getNodeParameter('keystorePassphrase', i) as string;
|
||||
}
|
||||
|
||||
const encryptedValues = (await encryptPassphrase.call(
|
||||
this,
|
||||
certificateId,
|
||||
privateKeyPassphrase,
|
||||
keystorePassphrase,
|
||||
)) as string;
|
||||
body.encryptedPrivateKeyPassphrase = encryptedValues[0];
|
||||
if (exportFormat === 'JKS') {
|
||||
body.encryptedKeystorePassphrase = encryptedValues[1];
|
||||
}
|
||||
|
||||
responseData = await venafiApiRequest.call(
|
||||
this,
|
||||
'POST',
|
||||
`/outagedetection/v1/certificates/${certificateId}/keystore`,
|
||||
body,
|
||||
{},
|
||||
{ encoding: null, json: false, resolveWithFullResponse: true },
|
||||
);
|
||||
}
|
||||
|
||||
const contentDisposition: string = responseData.headers['content-disposition'];
|
||||
const fileNameRegex = /(?<=filename=").*\b/;
|
||||
const match = fileNameRegex.exec(contentDisposition);
|
||||
let fileName = '';
|
||||
|
||||
if (match !== null) {
|
||||
fileName = match[0];
|
||||
}
|
||||
|
||||
const binaryData = await this.helpers.prepareBinaryData(
|
||||
Buffer.from(responseData.body as Buffer),
|
||||
fileName,
|
||||
);
|
||||
|
||||
responseData = {
|
||||
json: {},
|
||||
binary: {
|
||||
[binaryProperty]: binaryData,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
//https://api.venafi.cloud/webjars/swagger-ui/index.html?configUrl=%2Fv3%2Fapi-docs%2Fswagger-config&urls.primaryName=outagedetection-service#/%2Fv1/certificates_getById
|
||||
if (operation === 'get') {
|
||||
const certificateId = this.getNodeParameter('certificateId', i) as string;
|
||||
|
||||
responseData = await venafiApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/outagedetection/v1/certificates/${certificateId}`,
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
}
|
||||
|
||||
//https://api.venafi.cloud/webjars/swagger-ui/index.html?configUrl=%2Fv3%2Fapi-docs%2Fswagger-config&urls.primaryName=outagedetection-service#/%2Fv1/certificates_getAllAsCsv
|
||||
if (operation === 'getMany') {
|
||||
const returnAll = this.getNodeParameter('returnAll', i);
|
||||
const filters = this.getNodeParameter('filters', i);
|
||||
|
||||
Object.assign(qs, filters);
|
||||
|
||||
if (returnAll) {
|
||||
responseData = await venafiApiRequestAllItems.call(
|
||||
this,
|
||||
'certificates',
|
||||
'GET',
|
||||
'/outagedetection/v1/certificates',
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
} else {
|
||||
qs.limit = this.getNodeParameter('limit', i);
|
||||
responseData = await venafiApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
'/outagedetection/v1/certificates',
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
|
||||
responseData = responseData.certificates;
|
||||
}
|
||||
}
|
||||
|
||||
//https://docs.venafi.cloud/api/t-cloud-api-renew-cert/
|
||||
if (operation === 'renew') {
|
||||
const applicationId = this.getNodeParameter('applicationId', i) as string;
|
||||
const certificateIssuingTemplateId = this.getNodeParameter(
|
||||
'certificateIssuingTemplateId',
|
||||
i,
|
||||
) as string;
|
||||
const certificateSigningRequest = this.getNodeParameter(
|
||||
'certificateSigningRequest',
|
||||
i,
|
||||
) as string;
|
||||
const existingCertificateId = this.getNodeParameter(
|
||||
'existingCertificateId',
|
||||
i,
|
||||
) as string;
|
||||
const options = this.getNodeParameter('options', i);
|
||||
|
||||
const body: IDataObject = {
|
||||
certificateSigningRequest,
|
||||
certificateIssuingTemplateId,
|
||||
applicationId,
|
||||
existingCertificateId,
|
||||
};
|
||||
|
||||
Object.assign(body, options);
|
||||
|
||||
responseData = await venafiApiRequest.call(
|
||||
this,
|
||||
'POST',
|
||||
'/outagedetection/v1/certificaterequests',
|
||||
body,
|
||||
qs,
|
||||
);
|
||||
|
||||
responseData = responseData.certificateRequests;
|
||||
}
|
||||
}
|
||||
|
||||
returnData.push(
|
||||
...this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(responseData as IDataObject[]),
|
||||
{
|
||||
itemData: { item: i },
|
||||
},
|
||||
),
|
||||
);
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
returnData.push({ json: { error: error.message } });
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
return [returnData as INodeExecutionData[]];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"node": "n8n-nodes-base.venafiTlsProtectCloudTrigger",
|
||||
"nodeVersion": "1.0",
|
||||
"codexVersion": "1.0",
|
||||
"categories": ["Development"],
|
||||
"resources": {
|
||||
"credentialDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/credentials/venafitlsprotectcloud/"
|
||||
}
|
||||
],
|
||||
"primaryDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/trigger-nodes/n8n-nodes-base.venafitlsprotectcloudtrigger/"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
import {
|
||||
NodeConnectionTypes,
|
||||
type IHookFunctions,
|
||||
type ILoadOptionsFunctions,
|
||||
type INodePropertyOptions,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type IWebhookFunctions,
|
||||
type IWebhookResponseData,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { venafiApiRequest } from './GenericFunctions';
|
||||
|
||||
export class VenafiTlsProtectCloudTrigger implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Venafi TLS Protect Cloud Trigger',
|
||||
name: 'venafiTlsProtectCloudTrigger',
|
||||
icon: 'file:../venafi.svg',
|
||||
group: ['trigger'],
|
||||
version: 1,
|
||||
description: 'Starts the workflow when Venafi events occur',
|
||||
defaults: {
|
||||
name: 'Venafi TLS Protect Cloud Trigger',
|
||||
},
|
||||
credentials: [
|
||||
{
|
||||
name: 'venafiTlsProtectCloudApi',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
webhooks: [
|
||||
{
|
||||
name: 'default',
|
||||
httpMethod: 'POST',
|
||||
responseMode: 'onReceived',
|
||||
path: 'webhook',
|
||||
},
|
||||
],
|
||||
inputs: [],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
properties: [
|
||||
{
|
||||
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getActivityTypes',
|
||||
},
|
||||
required: true,
|
||||
default: [],
|
||||
description:
|
||||
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code/expressions/">expression</a>. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
||||
},
|
||||
{
|
||||
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-multi-options
|
||||
displayName: 'Trigger On',
|
||||
name: 'triggerOn',
|
||||
type: 'multiOptions',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getActivitySubTypes',
|
||||
loadOptionsDependsOn: ['resource'],
|
||||
},
|
||||
required: true,
|
||||
default: [],
|
||||
description:
|
||||
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code/expressions/">expression</a>. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
methods = {
|
||||
loadOptions: {
|
||||
async getActivityTypes(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const activitytypes = await venafiApiRequest.call(this, 'GET', '/v1/activitytypes');
|
||||
return activitytypes.map(
|
||||
({ key, readableName }: { key: string; readableName: string }) => ({
|
||||
name: readableName,
|
||||
value: key,
|
||||
}),
|
||||
);
|
||||
},
|
||||
async getActivitySubTypes(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const resource = this.getCurrentNodeParameter('resource') as string;
|
||||
const activitytypes = await venafiApiRequest.call(this, 'GET', '/v1/activitytypes');
|
||||
const activity = activitytypes.find(({ key }: { key: string }) => key === resource) as {
|
||||
values: [{ key: string; readableName: string }];
|
||||
};
|
||||
const subActivities = activity.values.map(({ key, readableName }) => ({
|
||||
name: readableName,
|
||||
value: key,
|
||||
}));
|
||||
subActivities.unshift({ name: '[All]', value: '*' });
|
||||
return subActivities;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
webhookMethods = {
|
||||
default: {
|
||||
async checkExists(this: IHookFunctions): Promise<boolean> {
|
||||
const webhookUrl = this.getNodeWebhookUrl('default');
|
||||
|
||||
const { connectors } = await venafiApiRequest.call(this, 'GET', '/v1/connectors');
|
||||
|
||||
for (const connector of connectors) {
|
||||
const {
|
||||
id,
|
||||
status,
|
||||
properties: {
|
||||
target: {
|
||||
connection: { url },
|
||||
},
|
||||
},
|
||||
} = connector;
|
||||
|
||||
if (url === webhookUrl && status === 'Active') {
|
||||
await venafiApiRequest.call(this, 'DELETE', `/v1/connectors/${id}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
async create(this: IHookFunctions): Promise<boolean> {
|
||||
const webhookUrl = this.getNodeWebhookUrl('default');
|
||||
const resource = this.getNodeParameter('resource') as string;
|
||||
const body = {
|
||||
name: `n8n-webhook (${webhookUrl})`,
|
||||
properties: {
|
||||
connectorKind: 'WEBHOOK',
|
||||
target: {
|
||||
type: 'generic',
|
||||
connection: {
|
||||
url: webhookUrl,
|
||||
},
|
||||
},
|
||||
filter: {
|
||||
activityTypes: [resource],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const responseData = await venafiApiRequest.call(this, 'POST', '/v1/connectors', body);
|
||||
|
||||
if (responseData.id === undefined) {
|
||||
// Required data is missing so was not successful
|
||||
return false;
|
||||
}
|
||||
|
||||
const webhookData = this.getWorkflowStaticData('node');
|
||||
webhookData.webhookId = responseData.id as string;
|
||||
|
||||
return true;
|
||||
},
|
||||
async delete(this: IHookFunctions): Promise<boolean> {
|
||||
const webhookData = this.getWorkflowStaticData('node');
|
||||
|
||||
if (webhookData.webhookId !== undefined) {
|
||||
try {
|
||||
await venafiApiRequest.call(this, 'DELETE', `/v1/connectors/${webhookData.webhookId}`);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove from the static workflow data so that it is clear
|
||||
// that no webhooks are registered anymore
|
||||
delete webhookData.webhookId;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
|
||||
const { events } = this.getBodyData() as { events: [{ message: string; eventName: string }] };
|
||||
const triggerOn = this.getNodeParameter('triggerOn') as string;
|
||||
|
||||
if (Array.isArray(events) && events[0]?.message?.includes('TESTING CONNECTION...')) {
|
||||
// Is a create webhook confirmation request
|
||||
const res = this.getResponseObject();
|
||||
res.status(200).end();
|
||||
return {
|
||||
noWebhookResponse: true,
|
||||
};
|
||||
}
|
||||
|
||||
if (!triggerOn.includes('*') && !triggerOn.includes(events[0]?.eventName)) return {};
|
||||
|
||||
return {
|
||||
workflowData: [this.helpers.returnJsonArray(events)],
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user