From aa98a096c6c3a1496c10088567eccab27f8cf70d Mon Sep 17 00:00:00 2001 From: Mutasem Date: Mon, 14 Aug 2023 13:07:33 +0200 Subject: [PATCH] fix: Prevent workflow breaking when credential type is unknown --- .../src/components/CredentialCard.vue | 2 +- .../CredentialEdit/CredentialEdit.vue | 2 +- .../src/components/CredentialsSelect.vue | 1 + .../src/components/NodeCredentials.vue | 30 +++++++--------- .../editor-ui/src/components/ScopesNotice.vue | 10 +++--- packages/editor-ui/src/mixins/nodeHelpers.ts | 29 ++++++--------- .../editor-ui/src/stores/credentials.store.ts | 35 ++++++++++--------- .../editor-ui/src/utils/nodeTypesUtils.ts | 2 +- 8 files changed, 51 insertions(+), 60 deletions(-) diff --git a/packages/editor-ui/src/components/CredentialCard.vue b/packages/editor-ui/src/components/CredentialCard.vue index 642a8c8887575..e96e49ce3416f 100644 --- a/packages/editor-ui/src/components/CredentialCard.vue +++ b/packages/editor-ui/src/components/CredentialCard.vue @@ -91,7 +91,7 @@ export default defineComponent({ currentUser(): IUser | null { return this.usersStore.currentUser; }, - credentialType(): ICredentialType { + credentialType(): ICredentialType | undefined { return this.credentialsStore.getCredentialTypeByName(this.data.type); }, credentialPermissions(): IPermissions | null { diff --git a/packages/editor-ui/src/components/CredentialEdit/CredentialEdit.vue b/packages/editor-ui/src/components/CredentialEdit/CredentialEdit.vue index 676c9d1b0b976..782c51a889a2f 100644 --- a/packages/editor-ui/src/components/CredentialEdit/CredentialEdit.vue +++ b/packages/editor-ui/src/components/CredentialEdit/CredentialEdit.vue @@ -304,7 +304,7 @@ export default defineComponent({ // If there is already selected type, use it if (this.selectedCredential !== '') { - return this.credentialsStore.getCredentialTypeByName(this.selectedCredential); + return this.credentialsStore.getCredentialTypeByName(this.selectedCredential) ?? null; } else if (this.requiredCredentials) { // Otherwise, use credential type that corresponds to the first auth option in the node definition const nodeAuthOptions = getNodeAuthOptions(this.activeNodeType); diff --git a/packages/editor-ui/src/components/CredentialsSelect.vue b/packages/editor-ui/src/components/CredentialsSelect.vue index 4e44770842480..245787cad0c68 100644 --- a/packages/editor-ui/src/components/CredentialsSelect.vue +++ b/packages/editor-ui/src/components/CredentialsSelect.vue @@ -109,6 +109,7 @@ export default defineComponent({ const supported = this.getSupportedSets(this.parameter.credentialTypes); const checkedCredType = this.credentialsStore.getCredentialTypeByName(name); + if (!checkedCredType) return false; for (const property of supported.has) { if (checkedCredType[property as keyof ICredentialType] !== undefined) { diff --git a/packages/editor-ui/src/components/NodeCredentials.vue b/packages/editor-ui/src/components/NodeCredentials.vue index c463765217e9a..c58729d9d4c9e 100644 --- a/packages/editor-ui/src/components/NodeCredentials.vue +++ b/packages/editor-ui/src/components/NodeCredentials.vue @@ -291,14 +291,14 @@ export default defineComponent({ }); }, credentialTypesNodeDescription(): INodeCredentialDescription[] { - const node = this.node as INodeUi; + const node = this.node; const credType = this.credentialsStore.getCredentialTypeByName(this.overrideCredType); if (credType) return [credType]; const activeNodeType = this.nodeTypesStore.getNodeType(node.type, node.typeVersion); - if (activeNodeType && activeNodeType.credentials) { + if (activeNodeType?.credentials) { return activeNodeType.credentials; } @@ -308,11 +308,12 @@ export default defineComponent({ const returnData: { [key: string]: string; } = {}; - let credentialType: ICredentialType | null; + let credentialType: ICredentialType | undefined; for (const credentialTypeName of this.credentialTypesNode) { credentialType = this.credentialsStore.getCredentialTypeByName(credentialTypeName); - returnData[credentialTypeName] = - credentialType !== null ? credentialType.displayName : credentialTypeName; + returnData[credentialTypeName] = credentialType + ? credentialType.displayName + : credentialTypeName; } return returnData; }, @@ -347,7 +348,7 @@ export default defineComponent({ options = options.concat( this.credentialsStore.allUsableCredentialsByType[type].map((option: any) => ({ ...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 selectedCredentialsType = this.showAll ? selectedCredentials.type : credentialType; - const oldCredentials = - this.node.credentials && this.node.credentials[selectedCredentialsType] - ? this.node.credentials[selectedCredentialsType] - : {}; + const oldCredentials = this.node.credentials?.[selectedCredentialsType] + ? this.node.credentials[selectedCredentialsType] + : {}; const selected = { id: selectedCredentials.id, name: selectedCredentials.name }; @@ -513,9 +513,9 @@ export default defineComponent({ }, 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 []; } @@ -526,11 +526,7 @@ export default defineComponent({ }, isCredentialExisting(credentialType: string): boolean { - if ( - !this.node.credentials || - !this.node.credentials[credentialType] || - !this.node.credentials[credentialType].id - ) { + if (!this.node.credentials?.[credentialType]?.id) { return false; } const { id } = this.node.credentials[credentialType]; diff --git a/packages/editor-ui/src/components/ScopesNotice.vue b/packages/editor-ui/src/components/ScopesNotice.vue index 0f7a0bcbf1007..b18637eae2e60 100644 --- a/packages/editor-ui/src/components/ScopesNotice.vue +++ b/packages/editor-ui/src/components/ScopesNotice.vue @@ -35,10 +35,12 @@ export default defineComponent({ const oauth1Api = this.$locale.baseText('generic.oauth1Api'); const oauth2Api = this.$locale.baseText('generic.oauth2Api'); - return this.credentialsStore - .getCredentialTypeByName(this.activeCredentialType) - .displayName.replace(new RegExp(`${oauth1Api}|${oauth2Api}`), '') - .trim(); + return ( + this.credentialsStore + .getCredentialTypeByName(this.activeCredentialType) + ?.displayName.replace(new RegExp(`${oauth1Api}|${oauth2Api}`), '') + .trim() || '' + ); }, }, }); diff --git a/packages/editor-ui/src/mixins/nodeHelpers.ts b/packages/editor-ui/src/mixins/nodeHelpers.ts index 73f2b053863ad..073c5f5e232d3 100644 --- a/packages/editor-ui/src/mixins/nodeHelpers.ts +++ b/packages/editor-ui/src/mixins/nodeHelpers.ts @@ -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) { nodeIssues = {}; } @@ -245,7 +245,7 @@ export const nodeHelpers = defineComponent({ const foundIssues: INodeIssueObjectProperty = {}; let userCredentials: ICredentialsResponse[] | null; - let credentialType: ICredentialType | null; + let credentialType: ICredentialType | undefined; let credentialDisplayName: string; let selectedCredentials: INodeCredentialsDetails; @@ -258,7 +258,7 @@ export const nodeHelpers = defineComponent({ selectedCredsAreUnusable(node, genericAuthType) ) { const credential = this.credentialsStore.getCredentialTypeByName(genericAuthType); - return this.reportUnsetCredential(credential); + return credential ? this.reportUnsetCredential(credential) : null; } if ( @@ -271,7 +271,7 @@ export const nodeHelpers = defineComponent({ if (selectedCredsDoNotExist(node, nodeCredentialType, stored)) { 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) ) { const credential = this.credentialsStore.getCredentialTypeByName(nodeCredentialType); - return this.reportUnsetCredential(credential); + return credential ? this.reportUnsetCredential(credential) : null; } for (const credentialTypeDescription of nodeType.credentials) { @@ -301,7 +301,7 @@ export const nodeHelpers = defineComponent({ credentialDisplayName = credentialType.displayName; } - if (!node.credentials || !node.credentials?.[credentialTypeDescription.name]) { + if (!node.credentials?.[credentialTypeDescription.name]) { // Credentials are not set if (credentialTypeDescription.required) { foundIssues[credentialTypeDescription.name] = [ @@ -312,9 +312,7 @@ export const nodeHelpers = defineComponent({ } } else { // If they are set check if the value is valid - selectedCredentials = node.credentials[ - credentialTypeDescription.name - ] as INodeCredentialsDetails; + selectedCredentials = node.credentials[credentialTypeDescription.name]; if (typeof selectedCredentials === 'string') { selectedCredentials = { id: null, @@ -409,16 +407,14 @@ export const nodeHelpers = defineComponent({ return []; } const executionData = this.workflowsStore.getWorkflowExecution.data; - if (!executionData || !executionData.resultData) { + if (!executionData?.resultData) { // unknown status return []; } const runData = executionData.resultData.runData; if ( - runData === null || - runData[node.name] === undefined || - !runData[node.name][runIndex].data || + !runData?.[node.name]?.[runIndex].data || runData[node.name][runIndex].data === undefined ) { return []; @@ -457,12 +453,7 @@ export const nodeHelpers = defineComponent({ const runData: IRunData | null = workflowRunData; - if ( - runData === null || - !runData[node] || - !runData[node][runIndex] || - !runData[node][runIndex].data - ) { + if (!runData?.[node]?.[runIndex]?.data) { return []; } diff --git a/packages/editor-ui/src/stores/credentials.store.ts b/packages/editor-ui/src/stores/credentials.store.ts index a856777f17b36..4b5d5474918ef 100644 --- a/packages/editor-ui/src/stores/credentials.store.ts +++ b/packages/editor-ui/src/stores/credentials.store.ts @@ -1,4 +1,12 @@ -import type { INodeUi, IUsedCredential } from '../Interface'; +import type { + INodeUi, + IUsedCredential, + ICredentialMap, + ICredentialsDecryptedResponse, + ICredentialsResponse, + ICredentialsState, + ICredentialTypeMap, +} from '../Interface'; import { createNewCredential, deleteCredential, @@ -15,19 +23,11 @@ import { setCredentialSharedWith } from '@/api/credentials.ee'; import { makeRestApiRequest } from '@/utils/apiUtils'; import { getAppNameFromCredType } from '@/utils/nodeTypesUtils'; import { EnterpriseEditionFeature, STORES } from '@/constants'; -import type { - ICredentialMap, - ICredentialsDecryptedResponse, - ICredentialsResponse, - ICredentialsState, - ICredentialTypeMap, -} from '@/Interface'; import { i18n } from '@/plugins/i18n'; import type { ICredentialsDecrypted, ICredentialType, INodeCredentialTestResult, - INodeProperties, INodeTypeDescription, IUser, } from 'n8n-workflow'; @@ -77,7 +77,7 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, { return (node: INodeUi): ICredentialsResponse[] => { let credentials: ICredentialsResponse[] = []; const nodeType = useNodeTypesStore().getNodeType(node.type, node.typeVersion); - if (nodeType && nodeType.credentials) { + if (nodeType?.credentials) { nodeType.credentials.forEach((cred) => { credentials = credentials.concat(this.allUsableCredentialsByType[cred.name]); }); @@ -106,7 +106,7 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, { ); }, getCredentialTypeByName() { - return (type: string): ICredentialType => this.credentialTypes[type]; + return (type: string): ICredentialType | undefined => this.credentialTypes[type]; }, getCredentialById() { return (id: string): ICredentialsResponse => this.credentials[id]; @@ -149,9 +149,10 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, { }, getScopesByCredentialType() { return (credentialTypeName: string) => { - const credentialType = this.getCredentialTypeByName(credentialTypeName) as { - properties: INodeProperties[]; - }; + const credentialType = this.getCredentialTypeByName(credentialTypeName); + if (!credentialType) { + return []; + } 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 }, async fetchCredentialTypes(forceFetch: boolean): Promise { - if (this.allCredentialTypes.length > 0 && forceFetch !== true) { + if (this.allCredentialTypes.length > 0 && !forceFetch) { return; } const rootStore = useRootStore(); @@ -337,8 +338,8 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, { const { credentialTypeName } = params; let newName = DEFAULT_CREDENTIAL_NAME; if (!TYPES_WITH_DEFAULT_NAME.includes(credentialTypeName)) { - const { displayName } = this.getCredentialTypeByName(credentialTypeName); - newName = getAppNameFromCredType(displayName); + const cred = this.getCredentialTypeByName(credentialTypeName); + newName = cred ? getAppNameFromCredType(cred.displayName) : ''; newName = newName.length > 0 ? `${newName} ${DEFAULT_CREDENTIAL_POSTFIX}` diff --git a/packages/editor-ui/src/utils/nodeTypesUtils.ts b/packages/editor-ui/src/utils/nodeTypesUtils.ts index 7957d66531c0e..27f11a52ce60e 100644 --- a/packages/editor-ui/src/utils/nodeTypesUtils.ts +++ b/packages/editor-ui/src/utils/nodeTypesUtils.ts @@ -212,7 +212,7 @@ export const getNodeAuthOptions = ( const cred = getNodeCredentialForSelectedAuthType(nodeType, option.value); if (cred) { hasOverrides = - useCredentialsStore().getCredentialTypeByName(cred.name).__overwrittenProperties !== + useCredentialsStore().getCredentialTypeByName(cred.name)?.__overwrittenProperties !== undefined; } return {