Add expression support to credentials

This commit is contained in:
Jan Oberhauser 2021-01-24 13:33:57 +01:00
parent b33a5fcd13
commit 1dedb3f4b8
6 changed files with 56 additions and 27 deletions

View file

@ -4,6 +4,7 @@ import {
import { import {
ICredentialDataDecryptedObject, ICredentialDataDecryptedObject,
ICredentialsExpressionResolveValues,
ICredentialsHelper, ICredentialsHelper,
INode, INode,
INodeParameters, INodeParameters,
@ -100,7 +101,7 @@ export class CredentialsHelper extends ICredentialsHelper {
* @returns {ICredentialDataDecryptedObject} * @returns {ICredentialDataDecryptedObject}
* @memberof CredentialsHelper * @memberof CredentialsHelper
*/ */
getDecrypted(name: string, type: string, raw?: boolean): ICredentialDataDecryptedObject { getDecrypted(name: string, type: string, raw?: boolean, expressionResolveValues?: ICredentialsExpressionResolveValues): ICredentialDataDecryptedObject {
const credentials = this.getCredentials(name, type); const credentials = this.getCredentials(name, type);
const decryptedDataOriginal = credentials.getData(this.encryptionKey); const decryptedDataOriginal = credentials.getData(this.encryptionKey);
@ -109,7 +110,7 @@ export class CredentialsHelper extends ICredentialsHelper {
return decryptedDataOriginal; return decryptedDataOriginal;
} }
return this.applyDefaultsAndOverwrites(decryptedDataOriginal, type); return this.applyDefaultsAndOverwrites(decryptedDataOriginal, type, expressionResolveValues);
} }
@ -121,7 +122,7 @@ export class CredentialsHelper extends ICredentialsHelper {
* @returns {ICredentialDataDecryptedObject} * @returns {ICredentialDataDecryptedObject}
* @memberof CredentialsHelper * @memberof CredentialsHelper
*/ */
applyDefaultsAndOverwrites(decryptedDataOriginal: ICredentialDataDecryptedObject, type: string): ICredentialDataDecryptedObject { applyDefaultsAndOverwrites(decryptedDataOriginal: ICredentialDataDecryptedObject, type: string, expressionResolveValues?: ICredentialsExpressionResolveValues): ICredentialDataDecryptedObject {
const credentialsProperties = this.getCredentialsProperties(type); const credentialsProperties = this.getCredentialsProperties(type);
// Add the default credential values // Add the default credential values
@ -133,17 +134,27 @@ export class CredentialsHelper extends ICredentialsHelper {
decryptedData.oauthTokenData = decryptedDataOriginal.oauthTokenData; decryptedData.oauthTokenData = decryptedDataOriginal.oauthTokenData;
} }
const mockNode: INode = { if (expressionResolveValues) {
try {
decryptedData = expressionResolveValues.workflow.expression.getParameterValue(decryptedData as INodeParameters, expressionResolveValues.runExecutionData, expressionResolveValues.runIndex, expressionResolveValues.itemIndex, expressionResolveValues.node.name, expressionResolveValues.connectionInputData) as ICredentialDataDecryptedObject;
} catch (e) {
e.message += ' [Error resolving credentials]';
throw e;
}
} else {
const node = {
name: '', name: '',
typeVersion: 1, typeVersion: 1,
type: 'mock', type: 'mock',
position: [0, 0], position: [0, 0],
parameters: decryptedData as INodeParameters, parameters: decryptedData as INodeParameters,
}; } as INode;
const workflow = new Workflow({ nodes: [node!], connections: {}, active: false, nodeTypes: mockNodeTypes });
const workflow = new Workflow({ nodes: [mockNode], connections: {}, active: false, nodeTypes: mockNodeTypes});
// Resolve expressions if any are set // Resolve expressions if any are set
decryptedData = workflow.expression.getComplexParameterValue(mockNode, decryptedData as INodeParameters, undefined) as ICredentialDataDecryptedObject; decryptedData = workflow.expression.getComplexParameterValue(node!, decryptedData as INodeParameters, undefined) as ICredentialDataDecryptedObject;
}
// Load and apply the credentials overwrites if any exist // Load and apply the credentials overwrites if any exist
const credentialsOverwrites = CredentialsOverwrites(); const credentialsOverwrites = CredentialsOverwrites();

View file

@ -11,6 +11,7 @@ import {
IBinaryData, IBinaryData,
IContextObject, IContextObject,
ICredentialDataDecryptedObject, ICredentialDataDecryptedObject,
ICredentialsExpressionResolveValues,
IDataObject, IDataObject,
IExecuteFunctions, IExecuteFunctions,
IExecuteSingleFunctions, IExecuteSingleFunctions,
@ -298,7 +299,7 @@ export function returnJsonArray(jsonData: IDataObject | IDataObject[]): INodeExe
* @param {IWorkflowExecuteAdditionalData} additionalData * @param {IWorkflowExecuteAdditionalData} additionalData
* @returns {(ICredentialDataDecryptedObject | undefined)} * @returns {(ICredentialDataDecryptedObject | undefined)}
*/ */
export function getCredentials(workflow: Workflow, node: INode, type: string, additionalData: IWorkflowExecuteAdditionalData): ICredentialDataDecryptedObject | undefined { export function getCredentials(workflow: Workflow, node: INode, type: string, additionalData: IWorkflowExecuteAdditionalData, runExecutionData?: IRunExecutionData | null, runIndex?: number, connectionInputData?: INodeExecutionData[], itemIndex?: number): ICredentialDataDecryptedObject | undefined {
// Get the NodeType as it has the information if the credentials are required // Get the NodeType as it has the information if the credentials are required
const nodeType = workflow.nodeTypes.getByName(node.type); const nodeType = workflow.nodeTypes.getByName(node.type);
@ -338,9 +339,21 @@ export function getCredentials(workflow: Workflow, node: INode, type: string, ad
} }
} }
let expressionResolveValues: ICredentialsExpressionResolveValues | undefined;
if (connectionInputData && runExecutionData && runIndex !== undefined) {
expressionResolveValues = {
connectionInputData,
itemIndex: itemIndex || 0,
node,
runExecutionData,
runIndex,
workflow,
} as ICredentialsExpressionResolveValues;
}
const name = node.credentials[type]; const name = node.credentials[type];
const decryptedDataObject = additionalData.credentialsHelper.getDecrypted(name, type); const decryptedDataObject = additionalData.credentialsHelper.getDecrypted(name, type, false, expressionResolveValues);
return decryptedDataObject; return decryptedDataObject;
} }
@ -662,8 +675,8 @@ export function getExecuteFunctions(workflow: Workflow, runExecutionData: IRunEx
getContext(type: string): IContextObject { getContext(type: string): IContextObject {
return NodeHelpers.getContext(runExecutionData, type, node); return NodeHelpers.getContext(runExecutionData, type, node);
}, },
getCredentials(type: string): ICredentialDataDecryptedObject | undefined { getCredentials(type: string, itemIndex?: number): ICredentialDataDecryptedObject | undefined {
return getCredentials(workflow, node, type, additionalData); return getCredentials(workflow, node, type, additionalData, runExecutionData, runIndex, connectionInputData, itemIndex);
}, },
getInputData: (inputIndex = 0, inputName = 'main') => { getInputData: (inputIndex = 0, inputName = 'main') => {
@ -758,7 +771,7 @@ export function getExecuteSingleFunctions(workflow: Workflow, runExecutionData:
return NodeHelpers.getContext(runExecutionData, type, node); return NodeHelpers.getContext(runExecutionData, type, node);
}, },
getCredentials(type: string): ICredentialDataDecryptedObject | undefined { getCredentials(type: string): ICredentialDataDecryptedObject | undefined {
return getCredentials(workflow, node, type, additionalData); return getCredentials(workflow, node, type, additionalData, runExecutionData, runIndex, connectionInputData, itemIndex);
}, },
getInputData: (inputIndex = 0, inputName = 'main') => { getInputData: (inputIndex = 0, inputName = 'main') => {
if (!inputData.hasOwnProperty(inputName)) { if (!inputData.hasOwnProperty(inputName)) {

View file

@ -30,7 +30,7 @@
</el-tooltip> </el-tooltip>
</el-col> </el-col>
<el-col :span="18"> <el-col :span="18">
<parameter-input :parameter="parameter" :value="propertyValue[parameter.name]" :path="parameter.name" :isCredential="true" @valueChanged="valueChanged" /> <parameter-input :parameter="parameter" :value="propertyValue[parameter.name]" :path="parameter.name" :isCredential="true" :displayOptions="true" @valueChanged="valueChanged" />
</el-col> </el-col>
</el-row> </el-row>
</div> </div>

View file

@ -1,6 +1,6 @@
<template> <template>
<div v-if="credentialTypesNodeDescriptionDisplayed.length" class="node-credentials"> <div v-if="credentialTypesNodeDescriptionDisplayed.length" class="node-credentials">
<credentials-edit :dialogVisible="credentialNewDialogVisible" :editCredentials="editCredentials" :setCredentialType="addType" :nodesInit="nodesInit" @closeDialog="closeCredentialNewDialog" @credentialsCreated="credentialsCreated" @credentialsUpdated="credentialsUpdated"></credentials-edit> <credentials-edit :dialogVisible="credentialNewDialogVisible" :editCredentials="editCredentials" :setCredentialType="addType" :nodesInit="nodesInit" :node="node" @closeDialog="closeCredentialNewDialog" @credentialsCreated="credentialsCreated" @credentialsUpdated="credentialsUpdated"></credentials-edit>
<div class="headline"> <div class="headline">
Credentials Credentials

View file

@ -240,10 +240,6 @@ export default mixins(
return returnValues.join('|'); return returnValues.join('|');
}, },
node (): INodeUi | null { node (): INodeUi | null {
if (this.isCredential === true) {
return null;
}
return this.$store.getters.activeNode; return this.$store.getters.activeNode;
}, },
displayTitle (): string { displayTitle (): string {
@ -314,7 +310,7 @@ export default mixins(
return false; return false;
}, },
expressionValueComputed (): NodeParameterValue | null { expressionValueComputed (): NodeParameterValue | null {
if (this.isCredential === true || this.node === null) { if (this.node === null) {
return null; return null;
} }

View file

@ -84,6 +84,15 @@ export interface ICredentialsEncrypted {
data?: string; data?: string;
} }
export interface ICredentialsExpressionResolveValues {
connectionInputData: INodeExecutionData[];
itemIndex: number;
node: INode;
runExecutionData: IRunExecutionData | null;
runIndex: number;
workflow: Workflow;
}
export abstract class ICredentialsHelper { export abstract class ICredentialsHelper {
encryptionKey: string; encryptionKey: string;
workflowCredentials: IWorkflowCredentials; workflowCredentials: IWorkflowCredentials;
@ -94,7 +103,7 @@ export abstract class ICredentialsHelper {
} }
abstract getCredentials(name: string, type: string): ICredentials; abstract getCredentials(name: string, type: string): ICredentials;
abstract getDecrypted(name: string, type: string): ICredentialDataDecryptedObject; abstract getDecrypted(name: string, type: string, raw?: boolean, expressionResolveValues?: ICredentialsExpressionResolveValues): ICredentialDataDecryptedObject;
abstract updateCredentials(name: string, type: string, data: ICredentialDataDecryptedObject): Promise<void>; abstract updateCredentials(name: string, type: string, data: ICredentialDataDecryptedObject): Promise<void>;
} }
@ -203,7 +212,7 @@ export interface IExecuteFunctions {
evaluateExpression(expression: string, itemIndex: number): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[]; evaluateExpression(expression: string, itemIndex: number): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[];
executeWorkflow(workflowInfo: IExecuteWorkflowInfo, inputData?: INodeExecutionData[]): Promise<any>; // tslint:disable-line:no-any executeWorkflow(workflowInfo: IExecuteWorkflowInfo, inputData?: INodeExecutionData[]): Promise<any>; // tslint:disable-line:no-any
getContext(type: string): IContextObject; getContext(type: string): IContextObject;
getCredentials(type: string): ICredentialDataDecryptedObject | undefined; getCredentials(type: string, itemIndex?: number): ICredentialDataDecryptedObject | undefined;
getInputData(inputIndex?: number, inputName?: string): INodeExecutionData[]; getInputData(inputIndex?: number, inputName?: string): INodeExecutionData[];
getMode(): WorkflowExecuteMode; getMode(): WorkflowExecuteMode;
getNode(): INode; getNode(): INode;