fix: Prevent workflow breaking when credential type is unknown (#6923)

This commit is contained in:
Mutasem Aldmour 2023-08-14 14:55:38 +02:00 committed by GitHub
parent 297c3c91f2
commit e83b93f293
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 51 additions and 60 deletions

View file

@ -91,7 +91,7 @@ export default defineComponent({
currentUser(): IUser | null { currentUser(): IUser | null {
return this.usersStore.currentUser; return this.usersStore.currentUser;
}, },
credentialType(): ICredentialType { credentialType(): ICredentialType | undefined {
return this.credentialsStore.getCredentialTypeByName(this.data.type); return this.credentialsStore.getCredentialTypeByName(this.data.type);
}, },
credentialPermissions(): IPermissions | null { credentialPermissions(): IPermissions | null {

View file

@ -304,7 +304,7 @@ export default defineComponent({
// If there is already selected type, use it // If there is already selected type, use it
if (this.selectedCredential !== '') { if (this.selectedCredential !== '') {
return this.credentialsStore.getCredentialTypeByName(this.selectedCredential); return this.credentialsStore.getCredentialTypeByName(this.selectedCredential) ?? null;
} else if (this.requiredCredentials) { } else if (this.requiredCredentials) {
// Otherwise, use credential type that corresponds to the first auth option in the node definition // Otherwise, use credential type that corresponds to the first auth option in the node definition
const nodeAuthOptions = getNodeAuthOptions(this.activeNodeType); const nodeAuthOptions = getNodeAuthOptions(this.activeNodeType);

View file

@ -109,6 +109,7 @@ export default defineComponent({
const supported = this.getSupportedSets(this.parameter.credentialTypes); const supported = this.getSupportedSets(this.parameter.credentialTypes);
const checkedCredType = this.credentialsStore.getCredentialTypeByName(name); const checkedCredType = this.credentialsStore.getCredentialTypeByName(name);
if (!checkedCredType) return false;
for (const property of supported.has) { for (const property of supported.has) {
if (checkedCredType[property as keyof ICredentialType] !== undefined) { if (checkedCredType[property as keyof ICredentialType] !== undefined) {

View file

@ -291,14 +291,14 @@ export default defineComponent({
}); });
}, },
credentialTypesNodeDescription(): INodeCredentialDescription[] { credentialTypesNodeDescription(): INodeCredentialDescription[] {
const node = this.node as INodeUi; const node = this.node;
const credType = this.credentialsStore.getCredentialTypeByName(this.overrideCredType); const credType = this.credentialsStore.getCredentialTypeByName(this.overrideCredType);
if (credType) return [credType]; if (credType) return [credType];
const activeNodeType = this.nodeTypesStore.getNodeType(node.type, node.typeVersion); const activeNodeType = this.nodeTypesStore.getNodeType(node.type, node.typeVersion);
if (activeNodeType && activeNodeType.credentials) { if (activeNodeType?.credentials) {
return activeNodeType.credentials; return activeNodeType.credentials;
} }
@ -308,11 +308,12 @@ export default defineComponent({
const returnData: { const returnData: {
[key: string]: string; [key: string]: string;
} = {}; } = {};
let credentialType: ICredentialType | null; let credentialType: ICredentialType | undefined;
for (const credentialTypeName of this.credentialTypesNode) { for (const credentialTypeName of this.credentialTypesNode) {
credentialType = this.credentialsStore.getCredentialTypeByName(credentialTypeName); credentialType = this.credentialsStore.getCredentialTypeByName(credentialTypeName);
returnData[credentialTypeName] = returnData[credentialTypeName] = credentialType
credentialType !== null ? credentialType.displayName : credentialTypeName; ? credentialType.displayName
: credentialTypeName;
} }
return returnData; return returnData;
}, },
@ -347,7 +348,7 @@ export default defineComponent({
options = options.concat( options = options.concat(
this.credentialsStore.allUsableCredentialsByType[type].map((option: any) => ({ this.credentialsStore.allUsableCredentialsByType[type].map((option: any) => ({
...option, ...option,
typeDisplayName: this.credentialsStore.getCredentialTypeByName(type).displayName, typeDisplayName: this.credentialsStore.getCredentialTypeByName(type)?.displayName,
})), })),
); );
}); });
@ -436,10 +437,9 @@ export default defineComponent({
const selectedCredentials = this.credentialsStore.getCredentialById(credentialId); const selectedCredentials = this.credentialsStore.getCredentialById(credentialId);
const selectedCredentialsType = this.showAll ? selectedCredentials.type : credentialType; const selectedCredentialsType = this.showAll ? selectedCredentials.type : credentialType;
const oldCredentials = const oldCredentials = this.node.credentials?.[selectedCredentialsType]
this.node.credentials && this.node.credentials[selectedCredentialsType] ? this.node.credentials[selectedCredentialsType]
? this.node.credentials[selectedCredentialsType] : {};
: {};
const selected = { id: selectedCredentials.id, name: selectedCredentials.name }; const selected = { id: selectedCredentials.id, name: selectedCredentials.name };
@ -513,9 +513,9 @@ export default defineComponent({
}, },
getIssues(credentialTypeName: string): string[] { getIssues(credentialTypeName: string): string[] {
const node = this.node as INodeUi; const node = this.node;
if (node.issues === undefined || node.issues.credentials === undefined) { if (node.issues?.credentials === undefined) {
return []; return [];
} }
@ -526,11 +526,7 @@ export default defineComponent({
}, },
isCredentialExisting(credentialType: string): boolean { isCredentialExisting(credentialType: string): boolean {
if ( if (!this.node.credentials?.[credentialType]?.id) {
!this.node.credentials ||
!this.node.credentials[credentialType] ||
!this.node.credentials[credentialType].id
) {
return false; return false;
} }
const { id } = this.node.credentials[credentialType]; const { id } = this.node.credentials[credentialType];

View file

@ -35,10 +35,12 @@ export default defineComponent({
const oauth1Api = this.$locale.baseText('generic.oauth1Api'); const oauth1Api = this.$locale.baseText('generic.oauth1Api');
const oauth2Api = this.$locale.baseText('generic.oauth2Api'); const oauth2Api = this.$locale.baseText('generic.oauth2Api');
return this.credentialsStore return (
.getCredentialTypeByName(this.activeCredentialType) this.credentialsStore
.displayName.replace(new RegExp(`${oauth1Api}|${oauth2Api}`), '') .getCredentialTypeByName(this.activeCredentialType)
.trim(); ?.displayName.replace(new RegExp(`${oauth1Api}|${oauth2Api}`), '')
.trim() || ''
);
}, },
}, },
}); });

View file

@ -126,7 +126,7 @@ export const nodeHelpers = defineComponent({
} }
} }
if (this.hasNodeExecutionIssues(node) === true && !ignoreIssues.includes('execution')) { if (this.hasNodeExecutionIssues(node) && !ignoreIssues.includes('execution')) {
if (nodeIssues === null) { if (nodeIssues === null) {
nodeIssues = {}; nodeIssues = {};
} }
@ -245,7 +245,7 @@ export const nodeHelpers = defineComponent({
const foundIssues: INodeIssueObjectProperty = {}; const foundIssues: INodeIssueObjectProperty = {};
let userCredentials: ICredentialsResponse[] | null; let userCredentials: ICredentialsResponse[] | null;
let credentialType: ICredentialType | null; let credentialType: ICredentialType | undefined;
let credentialDisplayName: string; let credentialDisplayName: string;
let selectedCredentials: INodeCredentialsDetails; let selectedCredentials: INodeCredentialsDetails;
@ -258,7 +258,7 @@ export const nodeHelpers = defineComponent({
selectedCredsAreUnusable(node, genericAuthType) selectedCredsAreUnusable(node, genericAuthType)
) { ) {
const credential = this.credentialsStore.getCredentialTypeByName(genericAuthType); const credential = this.credentialsStore.getCredentialTypeByName(genericAuthType);
return this.reportUnsetCredential(credential); return credential ? this.reportUnsetCredential(credential) : null;
} }
if ( if (
@ -271,7 +271,7 @@ export const nodeHelpers = defineComponent({
if (selectedCredsDoNotExist(node, nodeCredentialType, stored)) { if (selectedCredsDoNotExist(node, nodeCredentialType, stored)) {
const credential = this.credentialsStore.getCredentialTypeByName(nodeCredentialType); const credential = this.credentialsStore.getCredentialTypeByName(nodeCredentialType);
return this.reportUnsetCredential(credential); return credential ? this.reportUnsetCredential(credential) : null;
} }
} }
@ -282,7 +282,7 @@ export const nodeHelpers = defineComponent({
selectedCredsAreUnusable(node, nodeCredentialType) selectedCredsAreUnusable(node, nodeCredentialType)
) { ) {
const credential = this.credentialsStore.getCredentialTypeByName(nodeCredentialType); const credential = this.credentialsStore.getCredentialTypeByName(nodeCredentialType);
return this.reportUnsetCredential(credential); return credential ? this.reportUnsetCredential(credential) : null;
} }
for (const credentialTypeDescription of nodeType.credentials) { for (const credentialTypeDescription of nodeType.credentials) {
@ -301,7 +301,7 @@ export const nodeHelpers = defineComponent({
credentialDisplayName = credentialType.displayName; credentialDisplayName = credentialType.displayName;
} }
if (!node.credentials || !node.credentials?.[credentialTypeDescription.name]) { if (!node.credentials?.[credentialTypeDescription.name]) {
// Credentials are not set // Credentials are not set
if (credentialTypeDescription.required) { if (credentialTypeDescription.required) {
foundIssues[credentialTypeDescription.name] = [ foundIssues[credentialTypeDescription.name] = [
@ -312,9 +312,7 @@ export const nodeHelpers = defineComponent({
} }
} else { } else {
// If they are set check if the value is valid // If they are set check if the value is valid
selectedCredentials = node.credentials[ selectedCredentials = node.credentials[credentialTypeDescription.name];
credentialTypeDescription.name
] as INodeCredentialsDetails;
if (typeof selectedCredentials === 'string') { if (typeof selectedCredentials === 'string') {
selectedCredentials = { selectedCredentials = {
id: null, id: null,
@ -409,16 +407,14 @@ export const nodeHelpers = defineComponent({
return []; return [];
} }
const executionData = this.workflowsStore.getWorkflowExecution.data; const executionData = this.workflowsStore.getWorkflowExecution.data;
if (!executionData || !executionData.resultData) { if (!executionData?.resultData) {
// unknown status // unknown status
return []; return [];
} }
const runData = executionData.resultData.runData; const runData = executionData.resultData.runData;
if ( if (
runData === null || !runData?.[node.name]?.[runIndex].data ||
runData[node.name] === undefined ||
!runData[node.name][runIndex].data ||
runData[node.name][runIndex].data === undefined runData[node.name][runIndex].data === undefined
) { ) {
return []; return [];
@ -457,12 +453,7 @@ export const nodeHelpers = defineComponent({
const runData: IRunData | null = workflowRunData; const runData: IRunData | null = workflowRunData;
if ( if (!runData?.[node]?.[runIndex]?.data) {
runData === null ||
!runData[node] ||
!runData[node][runIndex] ||
!runData[node][runIndex].data
) {
return []; return [];
} }

View file

@ -1,4 +1,12 @@
import type { INodeUi, IUsedCredential } from '../Interface'; import type {
INodeUi,
IUsedCredential,
ICredentialMap,
ICredentialsDecryptedResponse,
ICredentialsResponse,
ICredentialsState,
ICredentialTypeMap,
} from '../Interface';
import { import {
createNewCredential, createNewCredential,
deleteCredential, deleteCredential,
@ -15,19 +23,11 @@ import { setCredentialSharedWith } from '@/api/credentials.ee';
import { makeRestApiRequest } from '@/utils/apiUtils'; import { makeRestApiRequest } from '@/utils/apiUtils';
import { getAppNameFromCredType } from '@/utils/nodeTypesUtils'; import { getAppNameFromCredType } from '@/utils/nodeTypesUtils';
import { EnterpriseEditionFeature, STORES } from '@/constants'; import { EnterpriseEditionFeature, STORES } from '@/constants';
import type {
ICredentialMap,
ICredentialsDecryptedResponse,
ICredentialsResponse,
ICredentialsState,
ICredentialTypeMap,
} from '@/Interface';
import { i18n } from '@/plugins/i18n'; import { i18n } from '@/plugins/i18n';
import type { import type {
ICredentialsDecrypted, ICredentialsDecrypted,
ICredentialType, ICredentialType,
INodeCredentialTestResult, INodeCredentialTestResult,
INodeProperties,
INodeTypeDescription, INodeTypeDescription,
IUser, IUser,
} from 'n8n-workflow'; } from 'n8n-workflow';
@ -77,7 +77,7 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, {
return (node: INodeUi): ICredentialsResponse[] => { return (node: INodeUi): ICredentialsResponse[] => {
let credentials: ICredentialsResponse[] = []; let credentials: ICredentialsResponse[] = [];
const nodeType = useNodeTypesStore().getNodeType(node.type, node.typeVersion); const nodeType = useNodeTypesStore().getNodeType(node.type, node.typeVersion);
if (nodeType && nodeType.credentials) { if (nodeType?.credentials) {
nodeType.credentials.forEach((cred) => { nodeType.credentials.forEach((cred) => {
credentials = credentials.concat(this.allUsableCredentialsByType[cred.name]); credentials = credentials.concat(this.allUsableCredentialsByType[cred.name]);
}); });
@ -106,7 +106,7 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, {
); );
}, },
getCredentialTypeByName() { getCredentialTypeByName() {
return (type: string): ICredentialType => this.credentialTypes[type]; return (type: string): ICredentialType | undefined => this.credentialTypes[type];
}, },
getCredentialById() { getCredentialById() {
return (id: string): ICredentialsResponse => this.credentials[id]; return (id: string): ICredentialsResponse => this.credentials[id];
@ -149,9 +149,10 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, {
}, },
getScopesByCredentialType() { getScopesByCredentialType() {
return (credentialTypeName: string) => { return (credentialTypeName: string) => {
const credentialType = this.getCredentialTypeByName(credentialTypeName) as { const credentialType = this.getCredentialTypeByName(credentialTypeName);
properties: INodeProperties[]; if (!credentialType) {
}; return [];
}
const scopeProperty = credentialType.properties.find((p) => p.name === 'scope'); const scopeProperty = credentialType.properties.find((p) => p.name === 'scope');
@ -232,7 +233,7 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, {
// enable oauth event to track change between modals // enable oauth event to track change between modals
}, },
async fetchCredentialTypes(forceFetch: boolean): Promise<void> { async fetchCredentialTypes(forceFetch: boolean): Promise<void> {
if (this.allCredentialTypes.length > 0 && forceFetch !== true) { if (this.allCredentialTypes.length > 0 && !forceFetch) {
return; return;
} }
const rootStore = useRootStore(); const rootStore = useRootStore();
@ -337,8 +338,8 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, {
const { credentialTypeName } = params; const { credentialTypeName } = params;
let newName = DEFAULT_CREDENTIAL_NAME; let newName = DEFAULT_CREDENTIAL_NAME;
if (!TYPES_WITH_DEFAULT_NAME.includes(credentialTypeName)) { if (!TYPES_WITH_DEFAULT_NAME.includes(credentialTypeName)) {
const { displayName } = this.getCredentialTypeByName(credentialTypeName); const cred = this.getCredentialTypeByName(credentialTypeName);
newName = getAppNameFromCredType(displayName); newName = cred ? getAppNameFromCredType(cred.displayName) : '';
newName = newName =
newName.length > 0 newName.length > 0
? `${newName} ${DEFAULT_CREDENTIAL_POSTFIX}` ? `${newName} ${DEFAULT_CREDENTIAL_POSTFIX}`

View file

@ -212,7 +212,7 @@ export const getNodeAuthOptions = (
const cred = getNodeCredentialForSelectedAuthType(nodeType, option.value); const cred = getNodeCredentialForSelectedAuthType(nodeType, option.value);
if (cred) { if (cred) {
hasOverrides = hasOverrides =
useCredentialsStore().getCredentialTypeByName(cred.name).__overwrittenProperties !== useCredentialsStore().getCredentialTypeByName(cred.name)?.__overwrittenProperties !==
undefined; undefined;
} }
return { return {