mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 12:57:29 -08:00
✨ Add expression support to credentials
This commit is contained in:
parent
b33a5fcd13
commit
1dedb3f4b8
|
@ -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();
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue