n8n 0.167.0 → 0.168.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/execute.js +3 -0
- package/dist/commands/execute.js.map +1 -1
- package/dist/commands/executeBatch.d.ts +2 -0
- package/dist/commands/executeBatch.js +3 -0
- package/dist/commands/executeBatch.js.map +1 -1
- package/dist/commands/import/credentials.d.ts +10 -0
- package/dist/commands/import/credentials.js +87 -26
- package/dist/commands/import/credentials.js.map +1 -1
- package/dist/commands/import/workflow.d.ts +11 -1
- package/dist/commands/import/workflow.js +109 -48
- package/dist/commands/import/workflow.js.map +1 -1
- package/dist/commands/start.js +25 -0
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/user-management/reset.d.ts +7 -0
- package/dist/commands/user-management/reset.js +66 -0
- package/dist/commands/user-management/reset.js.map +1 -0
- package/dist/commands/worker.js +4 -1
- package/dist/commands/worker.js.map +1 -1
- package/dist/config/index.d.ts +23 -0
- package/dist/config/index.js +92 -4
- package/dist/config/index.js.map +1 -1
- package/dist/src/ActiveWorkflowRunner.d.ts +2 -1
- package/dist/src/ActiveWorkflowRunner.js +44 -24
- package/dist/src/ActiveWorkflowRunner.js.map +1 -1
- package/dist/src/CredentialsHelper.d.ts +10 -2
- package/dist/src/CredentialsHelper.js +40 -11
- package/dist/src/CredentialsHelper.js.map +1 -1
- package/dist/src/Db.d.ts +4 -1
- package/dist/src/Db.js +90 -66
- package/dist/src/Db.js.map +1 -1
- package/dist/src/GenericHelpers.d.ts +6 -0
- package/dist/src/GenericHelpers.js +18 -1
- package/dist/src/GenericHelpers.js.map +1 -1
- package/dist/src/Interfaces.d.ts +74 -9
- package/dist/src/InternalHooks.d.ts +42 -6
- package/dist/src/InternalHooks.js +54 -13
- package/dist/src/InternalHooks.js.map +1 -1
- package/dist/src/ResponseHelper.js +5 -0
- package/dist/src/ResponseHelper.js.map +1 -1
- package/dist/src/Server.d.ts +2 -0
- package/dist/src/Server.js +585 -458
- package/dist/src/Server.js.map +1 -1
- package/dist/src/TagHelpers.d.ts +3 -3
- package/dist/src/TagHelpers.js +5 -24
- package/dist/src/TagHelpers.js.map +1 -1
- package/dist/src/UserManagement/Interfaces.d.ts +34 -0
- package/dist/src/UserManagement/Interfaces.js +3 -0
- package/dist/src/UserManagement/Interfaces.js.map +1 -0
- package/dist/src/UserManagement/UserManagementHelper.d.ts +17 -0
- package/dist/src/UserManagement/UserManagementHelper.js +158 -0
- package/dist/src/UserManagement/UserManagementHelper.js.map +1 -0
- package/dist/src/UserManagement/auth/jwt.d.ts +7 -0
- package/dist/src/UserManagement/auth/jwt.js +57 -0
- package/dist/src/UserManagement/auth/jwt.js.map +1 -0
- package/dist/src/UserManagement/email/Interfaces.d.ts +29 -0
- package/dist/src/UserManagement/email/Interfaces.js +3 -0
- package/dist/src/UserManagement/email/Interfaces.js.map +1 -0
- package/dist/src/UserManagement/email/NodeMailer.d.ts +7 -0
- package/dist/src/UserManagement/email/NodeMailer.js +67 -0
- package/dist/src/UserManagement/email/NodeMailer.js.map +1 -0
- package/dist/src/UserManagement/email/UserManagementMailer.d.ts +9 -0
- package/dist/src/UserManagement/email/UserManagementMailer.js +77 -0
- package/dist/src/UserManagement/email/UserManagementMailer.js.map +1 -0
- package/dist/src/UserManagement/email/index.d.ts +2 -0
- package/dist/src/UserManagement/email/index.js +7 -0
- package/dist/src/UserManagement/email/index.js.map +1 -0
- package/dist/src/UserManagement/index.d.ts +4 -0
- package/dist/src/UserManagement/index.js +6 -0
- package/dist/src/UserManagement/index.js.map +1 -0
- package/dist/src/UserManagement/routes/auth.d.ts +2 -0
- package/dist/src/UserManagement/routes/auth.js +74 -0
- package/dist/src/UserManagement/routes/auth.js.map +1 -0
- package/dist/src/UserManagement/routes/index.d.ts +2 -0
- package/dist/src/UserManagement/routes/index.js +100 -0
- package/dist/src/UserManagement/routes/index.js.map +1 -0
- package/dist/src/UserManagement/routes/me.d.ts +2 -0
- package/dist/src/UserManagement/routes/me.js +85 -0
- package/dist/src/UserManagement/routes/me.js.map +1 -0
- package/dist/src/UserManagement/routes/owner.d.ts +2 -0
- package/dist/src/UserManagement/routes/owner.js +68 -0
- package/dist/src/UserManagement/routes/owner.js.map +1 -0
- package/dist/src/UserManagement/routes/passwordReset.d.ts +2 -0
- package/dist/src/UserManagement/routes/passwordReset.js +129 -0
- package/dist/src/UserManagement/routes/passwordReset.js.map +1 -0
- package/dist/src/UserManagement/routes/users.d.ts +2 -0
- package/dist/src/UserManagement/routes/users.js +334 -0
- package/dist/src/UserManagement/routes/users.js.map +1 -0
- package/dist/src/WaitTracker.js +6 -0
- package/dist/src/WaitTracker.js.map +1 -1
- package/dist/src/WaitingWebhooks.js +9 -1
- package/dist/src/WaitingWebhooks.js.map +1 -1
- package/dist/src/WebhookHelpers.js +17 -1
- package/dist/src/WebhookHelpers.js.map +1 -1
- package/dist/src/WorkflowExecuteAdditionalData.d.ts +3 -3
- package/dist/src/WorkflowExecuteAdditionalData.js +41 -13
- package/dist/src/WorkflowExecuteAdditionalData.js.map +1 -1
- package/dist/src/WorkflowHelpers.d.ts +9 -10
- package/dist/src/WorkflowHelpers.js +48 -17
- package/dist/src/WorkflowHelpers.js.map +1 -1
- package/dist/src/WorkflowRunner.js +4 -2
- package/dist/src/WorkflowRunner.js.map +1 -1
- package/dist/src/WorkflowRunnerProcess.js +7 -4
- package/dist/src/WorkflowRunnerProcess.js.map +1 -1
- package/dist/src/api/credentials.api.d.ts +1 -0
- package/dist/src/api/credentials.api.js +222 -0
- package/dist/src/api/credentials.api.js.map +1 -0
- package/dist/src/constants.d.ts +5 -0
- package/dist/src/constants.js +9 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/databases/entities/CredentialsEntity.d.ts +2 -0
- package/dist/src/databases/entities/CredentialsEntity.js +13 -2
- package/dist/src/databases/entities/CredentialsEntity.js.map +1 -1
- package/dist/src/databases/entities/Role.d.ts +16 -0
- package/dist/src/databases/entities/Role.js +87 -0
- package/dist/src/databases/entities/Role.js.map +1 -0
- package/dist/src/databases/entities/Settings.d.ts +6 -0
- package/dist/src/databases/entities/Settings.js +32 -0
- package/dist/src/databases/entities/Settings.js.map +1 -0
- package/dist/src/databases/entities/SharedCredentials.d.ts +13 -0
- package/dist/src/databases/entities/SharedCredentials.js +83 -0
- package/dist/src/databases/entities/SharedCredentials.js.map +1 -0
- package/dist/src/databases/entities/SharedWorkflow.d.ts +13 -0
- package/dist/src/databases/entities/SharedWorkflow.js +83 -0
- package/dist/src/databases/entities/SharedWorkflow.js.map +1 -0
- package/dist/src/databases/entities/TagEntity.js +6 -2
- package/dist/src/databases/entities/TagEntity.js.map +1 -1
- package/dist/src/databases/entities/User.d.ts +24 -0
- package/dist/src/databases/entities/User.js +145 -0
- package/dist/src/databases/entities/User.js.map +1 -0
- package/dist/src/databases/entities/WorkflowEntity.d.ts +2 -0
- package/dist/src/databases/entities/WorkflowEntity.js +8 -1
- package/dist/src/databases/entities/WorkflowEntity.js.map +1 -1
- package/dist/src/databases/entities/index.d.ts +10 -0
- package/dist/src/databases/entities/index.js +10 -0
- package/dist/src/databases/entities/index.js.map +1 -1
- package/dist/src/databases/mysqldb/migrations/1626183952959-AddWaitColumn.js +0 -1
- package/dist/src/databases/mysqldb/migrations/1626183952959-AddWaitColumn.js.map +1 -1
- package/dist/src/databases/mysqldb/migrations/1630451444017-UpdateWorkflowCredentials.js +0 -3
- package/dist/src/databases/mysqldb/migrations/1630451444017-UpdateWorkflowCredentials.js.map +1 -1
- package/dist/src/databases/mysqldb/migrations/1644424784709-AddExecutionEntityIndexes.js +21 -8
- package/dist/src/databases/mysqldb/migrations/1644424784709-AddExecutionEntityIndexes.js.map +1 -1
- package/dist/src/databases/mysqldb/migrations/1646992772331-CreateUserManagement.d.ts +6 -0
- package/dist/src/databases/mysqldb/migrations/1646992772331-CreateUserManagement.js +100 -0
- package/dist/src/databases/mysqldb/migrations/1646992772331-CreateUserManagement.js.map +1 -0
- package/dist/src/databases/mysqldb/migrations/index.js +2 -0
- package/dist/src/databases/mysqldb/migrations/index.js.map +1 -1
- package/dist/src/databases/postgresdb/migrations/1620824779533-UniqueWorkflowNames.d.ts +1 -1
- package/dist/src/databases/postgresdb/migrations/1620824779533-UniqueWorkflowNames.js +1 -1
- package/dist/src/databases/postgresdb/migrations/1620824779533-UniqueWorkflowNames.js.map +1 -1
- package/dist/src/databases/postgresdb/migrations/1626176912946-AddwaitTill.js +0 -1
- package/dist/src/databases/postgresdb/migrations/1626176912946-AddwaitTill.js.map +1 -1
- package/dist/src/databases/postgresdb/migrations/1630419189837-UpdateWorkflowCredentials.js +0 -3
- package/dist/src/databases/postgresdb/migrations/1630419189837-UpdateWorkflowCredentials.js.map +1 -1
- package/dist/src/databases/postgresdb/migrations/1644422880309-AddExecutionEntityIndexes.js +16 -17
- package/dist/src/databases/postgresdb/migrations/1644422880309-AddExecutionEntityIndexes.js.map +1 -1
- package/dist/src/databases/postgresdb/migrations/1646992772331-CreateUserManagement.d.ts +6 -0
- package/dist/src/databases/postgresdb/migrations/1646992772331-CreateUserManagement.js +106 -0
- package/dist/src/databases/postgresdb/migrations/1646992772331-CreateUserManagement.js.map +1 -0
- package/dist/src/databases/postgresdb/migrations/index.js +2 -0
- package/dist/src/databases/postgresdb/migrations/index.js.map +1 -1
- package/dist/src/databases/sqlite/migrations/1588102412422-InitialMigration.js +3 -0
- package/dist/src/databases/sqlite/migrations/1588102412422-InitialMigration.js.map +1 -1
- package/dist/src/databases/sqlite/migrations/1592445003908-WebhookModel.js +3 -0
- package/dist/src/databases/sqlite/migrations/1592445003908-WebhookModel.js.map +1 -1
- package/dist/src/databases/sqlite/migrations/1594825041918-CreateIndexStoppedAt.d.ts +1 -1
- package/dist/src/databases/sqlite/migrations/1594825041918-CreateIndexStoppedAt.js +3 -0
- package/dist/src/databases/sqlite/migrations/1594825041918-CreateIndexStoppedAt.js.map +1 -1
- package/dist/src/databases/sqlite/migrations/1607431743769-MakeStoppedAtNullable.d.ts +2 -1
- package/dist/src/databases/sqlite/migrations/1607431743769-MakeStoppedAtNullable.js +6 -0
- package/dist/src/databases/sqlite/migrations/1607431743769-MakeStoppedAtNullable.js.map +1 -1
- package/dist/src/databases/sqlite/migrations/1611071044839-AddWebhookId.d.ts +1 -1
- package/dist/src/databases/sqlite/migrations/1611071044839-AddWebhookId.js +3 -0
- package/dist/src/databases/sqlite/migrations/1611071044839-AddWebhookId.js.map +1 -1
- package/dist/src/databases/sqlite/migrations/1617213344594-CreateTagEntity.d.ts +1 -1
- package/dist/src/databases/sqlite/migrations/1617213344594-CreateTagEntity.js +3 -0
- package/dist/src/databases/sqlite/migrations/1617213344594-CreateTagEntity.js.map +1 -1
- package/dist/src/databases/sqlite/migrations/1620821879465-UniqueWorkflowNames.d.ts +1 -1
- package/dist/src/databases/sqlite/migrations/1620821879465-UniqueWorkflowNames.js +3 -0
- package/dist/src/databases/sqlite/migrations/1620821879465-UniqueWorkflowNames.js.map +1 -1
- package/dist/src/databases/sqlite/migrations/1621707690587-AddWaitColumn.js +3 -1
- package/dist/src/databases/sqlite/migrations/1621707690587-AddWaitColumn.js.map +1 -1
- package/dist/src/databases/sqlite/migrations/1630330987096-UpdateWorkflowCredentials.js +3 -3
- package/dist/src/databases/sqlite/migrations/1630330987096-UpdateWorkflowCredentials.js.map +1 -1
- package/dist/src/databases/sqlite/migrations/1644421939510-AddExecutionEntityIndexes.js +17 -13
- package/dist/src/databases/sqlite/migrations/1644421939510-AddExecutionEntityIndexes.js.map +1 -1
- package/dist/src/databases/sqlite/migrations/1646992772331-CreateUserManagement.d.ts +6 -0
- package/dist/src/databases/sqlite/migrations/1646992772331-CreateUserManagement.js +73 -0
- package/dist/src/databases/sqlite/migrations/1646992772331-CreateUserManagement.js.map +1 -0
- package/dist/src/databases/sqlite/migrations/index.d.ts +3 -2
- package/dist/src/databases/sqlite/migrations/index.js +4 -1
- package/dist/src/databases/sqlite/migrations/index.js.map +1 -1
- package/dist/src/databases/utils/customValidators.d.ts +1 -0
- package/dist/src/databases/utils/customValidators.js +22 -0
- package/dist/src/databases/utils/customValidators.js.map +1 -0
- package/dist/src/databases/utils/migrationHelpers.d.ts +3 -0
- package/dist/src/databases/utils/migrationHelpers.js +60 -0
- package/dist/src/databases/utils/migrationHelpers.js.map +1 -0
- package/dist/src/databases/utils/transformers.d.ts +9 -0
- package/dist/src/databases/utils/transformers.js +16 -0
- package/dist/src/databases/utils/transformers.js.map +1 -0
- package/dist/src/telemetry/index.d.ts +4 -1
- package/dist/src/telemetry/index.js +4 -2
- package/dist/src/telemetry/index.js.map +1 -1
- package/dist/test/{CredentialsHelper.test.d.ts → integration/auth.endpoints.test.d.ts} +0 -0
- package/dist/test/integration/auth.endpoints.test.js +99 -0
- package/dist/test/integration/auth.endpoints.test.js.map +1 -0
- package/dist/test/integration/auth.middleware.test.d.ts +1 -0
- package/dist/test/integration/auth.middleware.test.js +46 -0
- package/dist/test/integration/auth.middleware.test.js.map +1 -0
- package/dist/test/integration/credentials.api.test.d.ts +1 -0
- package/dist/test/integration/credentials.api.test.js +401 -0
- package/dist/test/integration/credentials.api.test.js.map +1 -0
- package/dist/test/integration/me.endpoints.test.d.ts +1 -0
- package/dist/test/integration/me.endpoints.test.js +383 -0
- package/dist/test/integration/me.endpoints.test.js.map +1 -0
- package/dist/test/integration/owner.endpoints.test.d.ts +1 -0
- package/dist/test/integration/owner.endpoints.test.js +125 -0
- package/dist/test/integration/owner.endpoints.test.js.map +1 -0
- package/dist/test/integration/passwordReset.endpoints.test.d.ts +1 -0
- package/dist/test/integration/passwordReset.endpoints.test.js +221 -0
- package/dist/test/integration/passwordReset.endpoints.test.js.map +1 -0
- package/dist/test/integration/shared/constants.d.ts +16 -0
- package/dist/test/integration/shared/constants.js +41 -0
- package/dist/test/integration/shared/constants.js.map +1 -0
- package/dist/test/integration/shared/random.d.ts +5 -0
- package/dist/test/integration/shared/random.js +34 -0
- package/dist/test/integration/shared/random.js.map +1 -0
- package/dist/test/integration/shared/testDb.d.ts +47 -0
- package/dist/test/integration/shared/testDb.js +280 -0
- package/dist/test/integration/shared/testDb.js.map +1 -0
- package/dist/test/integration/shared/utils.d.ts +20 -0
- package/dist/test/integration/shared/utils.js +132 -0
- package/dist/test/integration/shared/utils.js.map +1 -0
- package/dist/test/integration/users.endpoints.test.d.ts +1 -0
- package/dist/test/integration/users.endpoints.test.js +420 -0
- package/dist/test/integration/users.endpoints.test.js.map +1 -0
- package/dist/test/setup.d.ts +1 -0
- package/dist/test/setup.js +27 -0
- package/dist/test/setup.js.map +1 -0
- package/dist/test/teardown.d.ts +2 -0
- package/dist/test/teardown.js +33 -0
- package/dist/test/teardown.js.map +1 -0
- package/dist/test/unit/CredentialsHelper.test.d.ts +1 -0
- package/dist/test/{CredentialsHelper.test.js → unit/CredentialsHelper.test.js} +1 -1
- package/dist/test/unit/CredentialsHelper.test.js.map +1 -0
- package/dist/test/{Helpers.d.ts → unit/Helpers.d.ts} +0 -0
- package/dist/test/{Helpers.js → unit/Helpers.js} +0 -0
- package/dist/test/unit/Helpers.js.map +1 -0
- package/oclif.manifest.json +1 -1
- package/package.json +29 -28
- package/dist/src/PersonalizationSurvey.d.ts +0 -3
- package/dist/src/PersonalizationSurvey.js +0 -48
- package/dist/src/PersonalizationSurvey.js.map +0 -1
- package/dist/test/CredentialsHelper.test.js.map +0 -1
- package/dist/test/Helpers.js.map +0 -1
package/dist/src/Server.js
CHANGED
|
@@ -11,13 +11,15 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
11
11
|
return t;
|
|
12
12
|
};
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.start = void 0;
|
|
14
|
+
exports.start = exports.externalHooks = void 0;
|
|
15
15
|
const express = require("express");
|
|
16
16
|
const fs_1 = require("fs");
|
|
17
17
|
const promises_1 = require("fs/promises");
|
|
18
|
+
const lodash_1 = require("lodash");
|
|
18
19
|
const path_1 = require("path");
|
|
19
20
|
const typeorm_1 = require("typeorm");
|
|
20
21
|
const bodyParser = require("body-parser");
|
|
22
|
+
const cookieParser = require("cookie-parser");
|
|
21
23
|
const history = require("connect-history-api-fallback");
|
|
22
24
|
const os = require("os");
|
|
23
25
|
const _ = require("lodash");
|
|
@@ -41,13 +43,21 @@ const Queue = require("./Queue");
|
|
|
41
43
|
const _1 = require(".");
|
|
42
44
|
const config = require("../config");
|
|
43
45
|
const TagHelpers = require("./TagHelpers");
|
|
44
|
-
const PersonalizationSurvey = require("./PersonalizationSurvey");
|
|
45
46
|
const InternalHooksManager_1 = require("./InternalHooksManager");
|
|
46
47
|
const TagEntity_1 = require("./databases/entities/TagEntity");
|
|
47
48
|
const WorkflowEntity_1 = require("./databases/entities/WorkflowEntity");
|
|
49
|
+
const WorkflowHelpers_1 = require("./WorkflowHelpers");
|
|
48
50
|
const TranslationHelpers_1 = require("./TranslationHelpers");
|
|
49
51
|
const WebhookHelpers_1 = require("./WebhookHelpers");
|
|
52
|
+
const UserManagement_1 = require("./UserManagement");
|
|
53
|
+
const jwt_1 = require("./UserManagement/auth/jwt");
|
|
54
|
+
const GenericHelpers_1 = require("./GenericHelpers");
|
|
55
|
+
const SharedWorkflow_1 = require("./databases/entities/SharedWorkflow");
|
|
56
|
+
const constants_1 = require("./constants");
|
|
57
|
+
const credentials_api_1 = require("./api/credentials.api");
|
|
58
|
+
const UserManagementHelper_1 = require("./UserManagement/UserManagementHelper");
|
|
50
59
|
require('body-parser-xml')(bodyParser);
|
|
60
|
+
exports.externalHooks = _1.ExternalHooks();
|
|
51
61
|
class App {
|
|
52
62
|
constructor() {
|
|
53
63
|
this.app = express();
|
|
@@ -72,7 +82,7 @@ class App {
|
|
|
72
82
|
this.protocol = config.get('protocol');
|
|
73
83
|
this.sslKey = config.get('ssl_key');
|
|
74
84
|
this.sslCert = config.get('ssl_cert');
|
|
75
|
-
this.externalHooks =
|
|
85
|
+
this.externalHooks = exports.externalHooks;
|
|
76
86
|
this.presetCredentialsLoaded = false;
|
|
77
87
|
this.endpointPresetCredentials = config.get('credentials.overwrite.endpoint');
|
|
78
88
|
const urlBaseWebhook = _1.WebhookHelpers.getWebhookBaseUrl();
|
|
@@ -98,6 +108,7 @@ class App {
|
|
|
98
108
|
maxExecutionTimeout: this.maxExecutionTimeout,
|
|
99
109
|
timezone: this.timezone,
|
|
100
110
|
urlBaseWebhook,
|
|
111
|
+
urlBaseEditor: UserManagementHelper_1.getInstanceBaseUrl(),
|
|
101
112
|
versionCli: '',
|
|
102
113
|
oauthCallbackUrls: {
|
|
103
114
|
oauth1: `${urlBaseWebhook}${this.restEndpoint}/oauth1-credential/callback`,
|
|
@@ -110,10 +121,17 @@ class App {
|
|
|
110
121
|
},
|
|
111
122
|
instanceId: '',
|
|
112
123
|
telemetry: telemetrySettings,
|
|
113
|
-
|
|
114
|
-
shouldShow: false,
|
|
115
|
-
},
|
|
124
|
+
personalizationSurveyEnabled: config.get('personalization.enabled') && config.get('diagnostics.enabled'),
|
|
116
125
|
defaultLocale: config.get('defaultLocale'),
|
|
126
|
+
userManagement: {
|
|
127
|
+
enabled: config.get('userManagement.disabled') === false ||
|
|
128
|
+
config.get('userManagement.isInstanceOwnerSetUp') === true,
|
|
129
|
+
showSetupOnFirstLoad: config.get('userManagement.disabled') === false &&
|
|
130
|
+
config.get('userManagement.isInstanceOwnerSetUp') === false &&
|
|
131
|
+
config.get('userManagement.skipInstanceOwnerSetup') === false,
|
|
132
|
+
smtpSetup: UserManagementHelper_1.isEmailSetUp(),
|
|
133
|
+
},
|
|
134
|
+
workflowTagsDisabled: config.get('workflowTagsDisabled'),
|
|
117
135
|
logLevel: config.get('logs.level'),
|
|
118
136
|
hiringBannerEnabled: config.get('hiringBanner.enabled'),
|
|
119
137
|
templates: {
|
|
@@ -125,6 +143,16 @@ class App {
|
|
|
125
143
|
getCurrentDate() {
|
|
126
144
|
return new Date();
|
|
127
145
|
}
|
|
146
|
+
getSettingsForFrontend() {
|
|
147
|
+
Object.assign(this.frontendSettings.userManagement, {
|
|
148
|
+
enabled: config.get('userManagement.disabled') === false ||
|
|
149
|
+
config.get('userManagement.isInstanceOwnerSetUp') === true,
|
|
150
|
+
showSetupOnFirstLoad: config.get('userManagement.disabled') === false &&
|
|
151
|
+
config.get('userManagement.isInstanceOwnerSetUp') === false &&
|
|
152
|
+
config.get('userManagement.skipInstanceOwnerSetup') === false,
|
|
153
|
+
});
|
|
154
|
+
return this.frontendSettings;
|
|
155
|
+
}
|
|
128
156
|
async config() {
|
|
129
157
|
const enableMetrics = config.get('endpoints.metrics.enable');
|
|
130
158
|
let register;
|
|
@@ -137,8 +165,6 @@ class App {
|
|
|
137
165
|
this.versions = await _1.GenericHelpers.getVersions();
|
|
138
166
|
this.frontendSettings.versionCli = this.versions.cli;
|
|
139
167
|
this.frontendSettings.instanceId = await n8n_core_1.UserSettings.getInstanceId();
|
|
140
|
-
this.frontendSettings.personalizationSurvey =
|
|
141
|
-
await PersonalizationSurvey.preparePersonalizationSurvey();
|
|
142
168
|
await this.externalHooks.run('frontend.settings', [this.frontendSettings]);
|
|
143
169
|
const excludeEndpoints = config.get('security.excludeEndpoints');
|
|
144
170
|
const ignoredEndpoints = [
|
|
@@ -163,7 +189,8 @@ class App {
|
|
|
163
189
|
const basicAuthHashEnabled = (await _1.GenericHelpers.getConfigValue('security.basicAuth.hash'));
|
|
164
190
|
let validPassword = null;
|
|
165
191
|
this.app.use(async (req, res, next) => {
|
|
166
|
-
if (authIgnoreRegex.exec(req.url)
|
|
192
|
+
if (authIgnoreRegex.exec(req.url) ||
|
|
193
|
+
config.get('userManagement.isInstanceOwnerSetUp')) {
|
|
167
194
|
return next();
|
|
168
195
|
}
|
|
169
196
|
const realm = 'n8n - Editor UI';
|
|
@@ -254,12 +281,22 @@ class App {
|
|
|
254
281
|
});
|
|
255
282
|
});
|
|
256
283
|
}
|
|
257
|
-
this.app.use((
|
|
284
|
+
this.app.use(cookieParser());
|
|
285
|
+
this.app.use(async (req, res, next) => {
|
|
286
|
+
var _a, _b;
|
|
258
287
|
if (req.url.indexOf(`/${this.restEndpoint}/push`) === 0) {
|
|
259
288
|
if (req.query.sessionId === undefined) {
|
|
260
289
|
next(new Error('The query parameter "sessionId" is missing!'));
|
|
261
290
|
return;
|
|
262
291
|
}
|
|
292
|
+
try {
|
|
293
|
+
const authCookie = (_b = (_a = req.cookies) === null || _a === void 0 ? void 0 : _a[constants_1.AUTH_COOKIE_NAME]) !== null && _b !== void 0 ? _b : '';
|
|
294
|
+
await jwt_1.resolveJwt(authCookie);
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
res.status(401).send('Unauthorized');
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
263
300
|
this.push.add(req.query.sessionId, req, res);
|
|
264
301
|
return;
|
|
265
302
|
}
|
|
@@ -311,6 +348,7 @@ class App {
|
|
|
311
348
|
if (process.env.NODE_ENV !== 'production') {
|
|
312
349
|
this.app.use((req, res, next) => {
|
|
313
350
|
res.header('Access-Control-Allow-Origin', 'http://localhost:8080');
|
|
351
|
+
res.header('Access-Control-Allow-Credentials', 'true');
|
|
314
352
|
res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
|
|
315
353
|
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, sessionid');
|
|
316
354
|
next();
|
|
@@ -323,6 +361,8 @@ class App {
|
|
|
323
361
|
}
|
|
324
362
|
next();
|
|
325
363
|
});
|
|
364
|
+
await UserManagement_1.userManagementRouter.addRoutes.apply(this, [ignoredEndpoints, this.restEndpoint]);
|
|
365
|
+
this.app.use(`/${this.restEndpoint}/credentials`, credentials_api_1.credentialsController);
|
|
326
366
|
this.app.get('/healthz', async (req, res) => {
|
|
327
367
|
n8n_workflow_1.LoggerProxy.debug('Health check started!');
|
|
328
368
|
const connection = typeorm_1.getConnectionManager().get();
|
|
@@ -350,29 +390,47 @@ class App {
|
|
|
350
390
|
_1.ResponseHelper.sendSuccessResponse(res, response, true, 200);
|
|
351
391
|
});
|
|
352
392
|
}
|
|
353
|
-
this.app.post(`/${this.restEndpoint}/workflows`, _1.ResponseHelper.send(async (req
|
|
393
|
+
this.app.post(`/${this.restEndpoint}/workflows`, _1.ResponseHelper.send(async (req) => {
|
|
354
394
|
delete req.body.id;
|
|
355
|
-
const incomingData = req.body;
|
|
356
395
|
const newWorkflow = new WorkflowEntity_1.WorkflowEntity();
|
|
357
|
-
Object.assign(newWorkflow,
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
396
|
+
Object.assign(newWorkflow, req.body);
|
|
397
|
+
await GenericHelpers_1.validateEntity(newWorkflow);
|
|
398
|
+
await this.externalHooks.run('workflow.create', [newWorkflow]);
|
|
399
|
+
const { tags: tagIds } = req.body;
|
|
400
|
+
if ((tagIds === null || tagIds === void 0 ? void 0 : tagIds.length) && !config.get('workflowTagsDisabled')) {
|
|
401
|
+
newWorkflow.tags = await _1.Db.collections.Tag.findByIds(tagIds, {
|
|
362
402
|
select: ['id', 'name'],
|
|
363
403
|
});
|
|
364
404
|
}
|
|
365
405
|
await _1.WorkflowHelpers.replaceInvalidCredentials(newWorkflow);
|
|
366
|
-
|
|
367
|
-
await
|
|
368
|
-
|
|
369
|
-
.
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
406
|
+
let savedWorkflow;
|
|
407
|
+
await typeorm_1.getConnection().transaction(async (transactionManager) => {
|
|
408
|
+
savedWorkflow = await transactionManager.save(newWorkflow);
|
|
409
|
+
const role = await _1.Db.collections.Role.findOneOrFail({
|
|
410
|
+
name: 'owner',
|
|
411
|
+
scope: 'workflow',
|
|
412
|
+
});
|
|
413
|
+
const newSharedWorkflow = new SharedWorkflow_1.SharedWorkflow();
|
|
414
|
+
Object.assign(newSharedWorkflow, {
|
|
415
|
+
role,
|
|
416
|
+
user: req.user,
|
|
417
|
+
workflow: savedWorkflow,
|
|
418
|
+
});
|
|
419
|
+
await transactionManager.save(newSharedWorkflow);
|
|
420
|
+
});
|
|
421
|
+
if (!savedWorkflow) {
|
|
422
|
+
n8n_workflow_1.LoggerProxy.error('Failed to create workflow', { userId: req.user.id });
|
|
423
|
+
throw new _1.ResponseHelper.ResponseError('Failed to save workflow');
|
|
424
|
+
}
|
|
425
|
+
if (tagIds && !config.get('workflowTagsDisabled')) {
|
|
426
|
+
savedWorkflow.tags = TagHelpers.sortByRequestOrder(savedWorkflow.tags, {
|
|
427
|
+
requestOrder: tagIds,
|
|
428
|
+
});
|
|
429
|
+
}
|
|
373
430
|
await this.externalHooks.run('workflow.afterCreate', [savedWorkflow]);
|
|
374
|
-
void InternalHooksManager_1.InternalHooksManager.getInstance().onWorkflowCreated(newWorkflow);
|
|
375
|
-
|
|
431
|
+
void InternalHooksManager_1.InternalHooksManager.getInstance().onWorkflowCreated(req.user.id, newWorkflow);
|
|
432
|
+
const { id } = savedWorkflow, rest = __rest(savedWorkflow, ["id"]);
|
|
433
|
+
return Object.assign({ id: id.toString() }, rest);
|
|
376
434
|
}));
|
|
377
435
|
this.app.get(`/${this.restEndpoint}/workflows/from-url`, _1.ResponseHelper.send(async (req, res) => {
|
|
378
436
|
if (req.query.url === undefined) {
|
|
@@ -399,45 +457,92 @@ class App {
|
|
|
399
457
|
}
|
|
400
458
|
return workflowData;
|
|
401
459
|
}));
|
|
402
|
-
this.app.get(`/${this.restEndpoint}/workflows`, _1.ResponseHelper.send(async (req
|
|
403
|
-
|
|
460
|
+
this.app.get(`/${this.restEndpoint}/workflows`, _1.ResponseHelper.send(async (req) => {
|
|
461
|
+
let workflows = [];
|
|
462
|
+
const filter = req.query.filter ? JSON.parse(req.query.filter) : {};
|
|
463
|
+
const query = {
|
|
404
464
|
select: ['id', 'name', 'active', 'createdAt', 'updatedAt'],
|
|
405
465
|
relations: ['tags'],
|
|
406
466
|
};
|
|
407
|
-
if (
|
|
408
|
-
|
|
467
|
+
if (config.get('workflowTagsDisabled')) {
|
|
468
|
+
delete query.relations;
|
|
409
469
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
470
|
+
if (req.user.globalRole.name === 'owner') {
|
|
471
|
+
workflows = await _1.Db.collections.Workflow.find(Object.assign(query, {
|
|
472
|
+
where: filter,
|
|
473
|
+
}));
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
const shared = await _1.Db.collections.SharedWorkflow.find({
|
|
477
|
+
relations: ['workflow'],
|
|
478
|
+
where: WorkflowHelpers_1.whereClause({
|
|
479
|
+
user: req.user,
|
|
480
|
+
entityType: 'workflow',
|
|
481
|
+
}),
|
|
482
|
+
});
|
|
483
|
+
if (!shared.length)
|
|
484
|
+
return [];
|
|
485
|
+
workflows = await _1.Db.collections.Workflow.find(Object.assign(query, {
|
|
486
|
+
where: Object.assign({ id: typeorm_1.In(shared.map(({ workflow }) => workflow.id)) }, filter),
|
|
487
|
+
}));
|
|
488
|
+
}
|
|
489
|
+
return workflows.map((workflow) => {
|
|
490
|
+
const { id } = workflow, rest = __rest(workflow, ["id"]);
|
|
491
|
+
return Object.assign({ id: id.toString() }, rest);
|
|
414
492
|
});
|
|
415
|
-
return workflows;
|
|
416
493
|
}));
|
|
417
|
-
this.app.get(`/${this.restEndpoint}/workflows/new`, _1.ResponseHelper.send(async (req
|
|
494
|
+
this.app.get(`/${this.restEndpoint}/workflows/new`, _1.ResponseHelper.send(async (req) => {
|
|
418
495
|
const requestedName = req.query.name && req.query.name !== '' ? req.query.name : this.defaultWorkflowName;
|
|
419
496
|
return await _1.GenericHelpers.generateUniqueName(requestedName, 'workflow');
|
|
420
497
|
}));
|
|
421
|
-
this.app.get(`/${this.restEndpoint}/workflows/:id`, _1.ResponseHelper.send(async (req
|
|
422
|
-
const
|
|
423
|
-
|
|
498
|
+
this.app.get(`/${this.restEndpoint}/workflows/:id`, _1.ResponseHelper.send(async (req) => {
|
|
499
|
+
const { id: workflowId } = req.params;
|
|
500
|
+
let relations = ['workflow', 'workflow.tags'];
|
|
501
|
+
if (config.get('workflowTagsDisabled')) {
|
|
502
|
+
relations = relations.filter((relation) => relation !== 'workflow.tags');
|
|
503
|
+
}
|
|
504
|
+
const shared = await _1.Db.collections.SharedWorkflow.findOne({
|
|
505
|
+
relations,
|
|
506
|
+
where: WorkflowHelpers_1.whereClause({
|
|
507
|
+
user: req.user,
|
|
508
|
+
entityType: 'workflow',
|
|
509
|
+
entityId: workflowId,
|
|
510
|
+
}),
|
|
424
511
|
});
|
|
425
|
-
if (
|
|
426
|
-
|
|
512
|
+
if (!shared) {
|
|
513
|
+
n8n_workflow_1.LoggerProxy.info('User attempted to access a workflow without permissions', {
|
|
514
|
+
workflowId,
|
|
515
|
+
userId: req.user.id,
|
|
516
|
+
});
|
|
517
|
+
throw new _1.ResponseHelper.ResponseError(`Workflow with ID "${workflowId}" could not be found.`, undefined, 404);
|
|
427
518
|
}
|
|
428
|
-
workflow
|
|
429
|
-
|
|
430
|
-
return workflow;
|
|
519
|
+
const _a = shared.workflow, { id } = _a, rest = __rest(_a, ["id"]);
|
|
520
|
+
return Object.assign({ id: id.toString() }, rest);
|
|
431
521
|
}));
|
|
432
|
-
this.app.patch(`/${this.restEndpoint}/workflows/:id`, _1.ResponseHelper.send(async (req
|
|
433
|
-
const
|
|
434
|
-
const
|
|
435
|
-
|
|
522
|
+
this.app.patch(`/${this.restEndpoint}/workflows/:id`, _1.ResponseHelper.send(async (req) => {
|
|
523
|
+
const { id: workflowId } = req.params;
|
|
524
|
+
const updateData = new WorkflowEntity_1.WorkflowEntity();
|
|
525
|
+
const _a = req.body, { tags } = _a, rest = __rest(_a, ["tags"]);
|
|
526
|
+
Object.assign(updateData, rest);
|
|
527
|
+
const shared = await _1.Db.collections.SharedWorkflow.findOne({
|
|
528
|
+
relations: ['workflow'],
|
|
529
|
+
where: WorkflowHelpers_1.whereClause({
|
|
530
|
+
user: req.user,
|
|
531
|
+
entityType: 'workflow',
|
|
532
|
+
entityId: workflowId,
|
|
533
|
+
}),
|
|
534
|
+
});
|
|
535
|
+
if (!shared) {
|
|
536
|
+
n8n_workflow_1.LoggerProxy.info('User attempted to update a workflow without permissions', {
|
|
537
|
+
workflowId,
|
|
538
|
+
userId: req.user.id,
|
|
539
|
+
});
|
|
540
|
+
throw new _1.ResponseHelper.ResponseError(`Workflow with ID "${workflowId}" could not be found to be updated.`, undefined, 404);
|
|
541
|
+
}
|
|
436
542
|
await _1.WorkflowHelpers.replaceInvalidCredentials(updateData);
|
|
437
543
|
await this.externalHooks.run('workflow.update', [updateData]);
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
await this.activeWorkflowRunner.remove(id);
|
|
544
|
+
if (shared.workflow.active) {
|
|
545
|
+
await this.activeWorkflowRunner.remove(workflowId);
|
|
441
546
|
}
|
|
442
547
|
if (updateData.settings) {
|
|
443
548
|
if (updateData.settings.timezone === 'DEFAULT') {
|
|
@@ -456,55 +561,78 @@ class App {
|
|
|
456
561
|
delete updateData.settings.executionTimeout;
|
|
457
562
|
}
|
|
458
563
|
}
|
|
459
|
-
updateData.
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
if (tags) {
|
|
564
|
+
if (updateData.name) {
|
|
565
|
+
updateData.updatedAt = this.getCurrentDate();
|
|
566
|
+
await GenericHelpers_1.validateEntity(updateData);
|
|
567
|
+
}
|
|
568
|
+
await _1.Db.collections.Workflow.update(workflowId, updateData);
|
|
569
|
+
if (tags && !config.get('workflowTagsDisabled')) {
|
|
465
570
|
const tablePrefix = config.get('database.tablePrefix');
|
|
466
|
-
await TagHelpers.removeRelations(
|
|
571
|
+
await TagHelpers.removeRelations(workflowId, tablePrefix);
|
|
467
572
|
if (tags.length) {
|
|
468
|
-
await TagHelpers.createRelations(
|
|
573
|
+
await TagHelpers.createRelations(workflowId, tags, tablePrefix);
|
|
469
574
|
}
|
|
470
575
|
}
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
|
|
576
|
+
const options = {
|
|
577
|
+
relations: ['tags'],
|
|
578
|
+
};
|
|
579
|
+
if (config.get('workflowTagsDisabled')) {
|
|
580
|
+
delete options.relations;
|
|
581
|
+
}
|
|
582
|
+
const updatedWorkflow = await _1.Db.collections.Workflow.findOne(workflowId, options);
|
|
583
|
+
if (updatedWorkflow === undefined) {
|
|
584
|
+
throw new _1.ResponseHelper.ResponseError(`Workflow with ID "${workflowId}" could not be found to be updated.`, undefined, 400);
|
|
474
585
|
}
|
|
475
|
-
if (tags === null || tags === void 0 ? void 0 : tags.length) {
|
|
476
|
-
|
|
586
|
+
if (updatedWorkflow.tags.length && (tags === null || tags === void 0 ? void 0 : tags.length)) {
|
|
587
|
+
updatedWorkflow.tags = TagHelpers.sortByRequestOrder(updatedWorkflow.tags, {
|
|
588
|
+
requestOrder: tags,
|
|
589
|
+
});
|
|
477
590
|
}
|
|
478
|
-
await this.externalHooks.run('workflow.afterUpdate', [
|
|
479
|
-
void InternalHooksManager_1.InternalHooksManager.getInstance().onWorkflowSaved(
|
|
480
|
-
if (
|
|
591
|
+
await this.externalHooks.run('workflow.afterUpdate', [updatedWorkflow]);
|
|
592
|
+
void InternalHooksManager_1.InternalHooksManager.getInstance().onWorkflowSaved(req.user.id, updatedWorkflow);
|
|
593
|
+
if (updatedWorkflow.active) {
|
|
481
594
|
try {
|
|
482
|
-
await this.externalHooks.run('workflow.activate', [
|
|
483
|
-
await this.activeWorkflowRunner.add(
|
|
595
|
+
await this.externalHooks.run('workflow.activate', [updatedWorkflow]);
|
|
596
|
+
await this.activeWorkflowRunner.add(workflowId, shared.workflow.active ? 'update' : 'activate');
|
|
484
597
|
}
|
|
485
598
|
catch (error) {
|
|
486
599
|
updateData.active = false;
|
|
487
|
-
await _1.Db.collections.Workflow.update(
|
|
488
|
-
|
|
600
|
+
await _1.Db.collections.Workflow.update(workflowId, updateData);
|
|
601
|
+
updatedWorkflow.active = false;
|
|
489
602
|
throw error;
|
|
490
603
|
}
|
|
491
604
|
}
|
|
492
|
-
|
|
493
|
-
return
|
|
605
|
+
const { id } = updatedWorkflow, remainder = __rest(updatedWorkflow, ["id"]);
|
|
606
|
+
return Object.assign({ id: id.toString() }, remainder);
|
|
494
607
|
}));
|
|
495
|
-
this.app.delete(`/${this.restEndpoint}/workflows/:id`, _1.ResponseHelper.send(async (req
|
|
496
|
-
const { id } = req.params;
|
|
497
|
-
await this.externalHooks.run('workflow.delete', [
|
|
498
|
-
const
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
608
|
+
this.app.delete(`/${this.restEndpoint}/workflows/:id`, _1.ResponseHelper.send(async (req) => {
|
|
609
|
+
const { id: workflowId } = req.params;
|
|
610
|
+
await this.externalHooks.run('workflow.delete', [workflowId]);
|
|
611
|
+
const shared = await _1.Db.collections.SharedWorkflow.findOne({
|
|
612
|
+
relations: ['workflow'],
|
|
613
|
+
where: WorkflowHelpers_1.whereClause({
|
|
614
|
+
user: req.user,
|
|
615
|
+
entityType: 'workflow',
|
|
616
|
+
entityId: workflowId,
|
|
617
|
+
}),
|
|
618
|
+
});
|
|
619
|
+
if (!shared) {
|
|
620
|
+
n8n_workflow_1.LoggerProxy.info('User attempted to delete a workflow without permissions', {
|
|
621
|
+
workflowId,
|
|
622
|
+
userId: req.user.id,
|
|
623
|
+
});
|
|
624
|
+
throw new _1.ResponseHelper.ResponseError(`Workflow with ID "${workflowId}" could not be found to be deleted.`, undefined, 400);
|
|
625
|
+
}
|
|
626
|
+
if (shared.workflow.active) {
|
|
627
|
+
await this.activeWorkflowRunner.remove(workflowId);
|
|
628
|
+
}
|
|
629
|
+
await _1.Db.collections.Workflow.delete(workflowId);
|
|
630
|
+
void InternalHooksManager_1.InternalHooksManager.getInstance().onWorkflowDeleted(req.user.id, workflowId);
|
|
631
|
+
await this.externalHooks.run('workflow.afterDelete', [workflowId]);
|
|
505
632
|
return true;
|
|
506
633
|
}));
|
|
507
634
|
this.app.post(`/${this.restEndpoint}/workflows/run`, _1.ResponseHelper.send(async (req, res) => {
|
|
635
|
+
var _a;
|
|
508
636
|
const { workflowData } = req.body;
|
|
509
637
|
const { runData } = req.body;
|
|
510
638
|
const { startNodes } = req.body;
|
|
@@ -516,10 +644,10 @@ class App {
|
|
|
516
644
|
startNodes === undefined ||
|
|
517
645
|
startNodes.length === 0 ||
|
|
518
646
|
destinationNode === undefined) {
|
|
519
|
-
const additionalData = await _1.WorkflowExecuteAdditionalData.getBase();
|
|
647
|
+
const additionalData = await _1.WorkflowExecuteAdditionalData.getBase(req.user.id);
|
|
520
648
|
const nodeTypes = _1.NodeTypes();
|
|
521
649
|
const workflowInstance = new n8n_workflow_1.Workflow({
|
|
522
|
-
id: workflowData.id,
|
|
650
|
+
id: (_a = workflowData.id) === null || _a === void 0 ? void 0 : _a.toString(),
|
|
523
651
|
name: workflowData.name,
|
|
524
652
|
nodes: workflowData.nodes,
|
|
525
653
|
connections: workflowData.connections,
|
|
@@ -543,6 +671,7 @@ class App {
|
|
|
543
671
|
sessionId,
|
|
544
672
|
startNodes,
|
|
545
673
|
workflowData,
|
|
674
|
+
userId: req.user.id,
|
|
546
675
|
};
|
|
547
676
|
const workflowRunner = new _1.WorkflowRunner();
|
|
548
677
|
const executionId = await workflowRunner.run(data);
|
|
@@ -551,61 +680,68 @@ class App {
|
|
|
551
680
|
};
|
|
552
681
|
}));
|
|
553
682
|
this.app.get(`/${this.restEndpoint}/tags`, _1.ResponseHelper.send(async (req, res) => {
|
|
683
|
+
if (config.get('workflowTagsDisabled')) {
|
|
684
|
+
throw new _1.ResponseHelper.ResponseError('Workflow tags are disabled');
|
|
685
|
+
}
|
|
554
686
|
if (req.query.withUsageCount === 'true') {
|
|
555
687
|
const tablePrefix = config.get('database.tablePrefix');
|
|
556
688
|
return TagHelpers.getTagsWithCountDb(tablePrefix);
|
|
557
689
|
}
|
|
558
|
-
|
|
559
|
-
tags.forEach((tag) => (tag.id = tag.id.toString()));
|
|
560
|
-
return tags;
|
|
690
|
+
return _1.Db.collections.Tag.find({ select: ['id', 'name'] });
|
|
561
691
|
}));
|
|
562
692
|
this.app.post(`/${this.restEndpoint}/tags`, _1.ResponseHelper.send(async (req, res) => {
|
|
693
|
+
if (config.get('workflowTagsDisabled')) {
|
|
694
|
+
throw new _1.ResponseHelper.ResponseError('Workflow tags are disabled');
|
|
695
|
+
}
|
|
563
696
|
const newTag = new TagEntity_1.TagEntity();
|
|
564
697
|
newTag.name = req.body.name.trim();
|
|
565
698
|
await this.externalHooks.run('tag.beforeCreate', [newTag]);
|
|
566
|
-
await
|
|
567
|
-
const tag = await _1.Db.collections
|
|
568
|
-
.Tag.save(newTag)
|
|
569
|
-
.catch(TagHelpers.throwDuplicateEntryError);
|
|
699
|
+
await GenericHelpers_1.validateEntity(newTag);
|
|
700
|
+
const tag = await _1.Db.collections.Tag.save(newTag);
|
|
570
701
|
await this.externalHooks.run('tag.afterCreate', [tag]);
|
|
571
|
-
tag.id = tag.id.toString();
|
|
572
702
|
return tag;
|
|
573
703
|
}));
|
|
574
704
|
this.app.patch(`/${this.restEndpoint}/tags/:id`, _1.ResponseHelper.send(async (req, res) => {
|
|
705
|
+
if (config.get('workflowTagsDisabled')) {
|
|
706
|
+
throw new _1.ResponseHelper.ResponseError('Workflow tags are disabled');
|
|
707
|
+
}
|
|
575
708
|
const { name } = req.body;
|
|
576
709
|
const { id } = req.params;
|
|
577
710
|
const newTag = new TagEntity_1.TagEntity();
|
|
578
|
-
newTag.id =
|
|
711
|
+
newTag.id = id;
|
|
579
712
|
newTag.name = name.trim();
|
|
580
713
|
await this.externalHooks.run('tag.beforeUpdate', [newTag]);
|
|
581
|
-
await
|
|
582
|
-
const tag = await _1.Db.collections
|
|
583
|
-
.Tag.save(newTag)
|
|
584
|
-
.catch(TagHelpers.throwDuplicateEntryError);
|
|
714
|
+
await GenericHelpers_1.validateEntity(newTag);
|
|
715
|
+
const tag = await _1.Db.collections.Tag.save(newTag);
|
|
585
716
|
await this.externalHooks.run('tag.afterUpdate', [tag]);
|
|
586
|
-
tag.id = tag.id.toString();
|
|
587
717
|
return tag;
|
|
588
718
|
}));
|
|
589
719
|
this.app.delete(`/${this.restEndpoint}/tags/:id`, _1.ResponseHelper.send(async (req, res) => {
|
|
720
|
+
if (config.get('workflowTagsDisabled')) {
|
|
721
|
+
throw new _1.ResponseHelper.ResponseError('Workflow tags are disabled');
|
|
722
|
+
}
|
|
723
|
+
if (config.get('userManagement.isInstanceOwnerSetUp') === true &&
|
|
724
|
+
req.user.globalRole.name !== 'owner') {
|
|
725
|
+
throw new _1.ResponseHelper.ResponseError('You are not allowed to perform this action', undefined, 403, 'Only owners can remove tags');
|
|
726
|
+
}
|
|
590
727
|
const id = Number(req.params.id);
|
|
591
728
|
await this.externalHooks.run('tag.beforeDelete', [id]);
|
|
592
729
|
await _1.Db.collections.Tag.delete({ id });
|
|
593
730
|
await this.externalHooks.run('tag.afterDelete', [id]);
|
|
594
731
|
return true;
|
|
595
732
|
}));
|
|
596
|
-
this.app.get(`/${this.restEndpoint}/node-parameter-options`, _1.ResponseHelper.send(async (req
|
|
597
|
-
const nodeTypeAndVersion = JSON.parse(
|
|
598
|
-
const path = req.query
|
|
733
|
+
this.app.get(`/${this.restEndpoint}/node-parameter-options`, _1.ResponseHelper.send(async (req) => {
|
|
734
|
+
const nodeTypeAndVersion = JSON.parse(req.query.nodeTypeAndVersion);
|
|
735
|
+
const { path, methodName } = req.query;
|
|
736
|
+
const currentNodeParameters = JSON.parse(req.query.currentNodeParameters);
|
|
599
737
|
let credentials;
|
|
600
|
-
|
|
601
|
-
if (req.query.credentials !== undefined) {
|
|
738
|
+
if (req.query.credentials) {
|
|
602
739
|
credentials = JSON.parse(req.query.credentials);
|
|
603
740
|
}
|
|
604
|
-
const
|
|
605
|
-
const
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
return loadDataInstance.getOptionsViaMethodName(req.query.methodName, additionalData);
|
|
741
|
+
const loadDataInstance = new n8n_core_1.LoadNodeParameterOptions(nodeTypeAndVersion, _1.NodeTypes(), path, currentNodeParameters, credentials);
|
|
742
|
+
const additionalData = await _1.WorkflowExecuteAdditionalData.getBase(req.user.id, currentNodeParameters);
|
|
743
|
+
if (methodName) {
|
|
744
|
+
return loadDataInstance.getOptionsViaMethodName(methodName, additionalData);
|
|
609
745
|
}
|
|
610
746
|
if (req.query.loadOptions) {
|
|
611
747
|
return loadDataInstance.getOptionsViaRequestProperty(JSON.parse(req.query.loadOptions), additionalData);
|
|
@@ -723,144 +859,28 @@ class App {
|
|
|
723
859
|
return _1.ResponseHelper.sendErrorResponse(res, error);
|
|
724
860
|
}
|
|
725
861
|
});
|
|
726
|
-
this.app.get(`/${this.restEndpoint}/active`, _1.ResponseHelper.send(async (req
|
|
727
|
-
const activeWorkflows = await this.activeWorkflowRunner.getActiveWorkflows();
|
|
728
|
-
return activeWorkflows.map((
|
|
729
|
-
}));
|
|
730
|
-
this.app.get(`/${this.restEndpoint}/active/error/:id`, _1.ResponseHelper.send(async (req, res) => {
|
|
731
|
-
const { id } = req.params;
|
|
732
|
-
return this.activeWorkflowRunner.getActivationError(id);
|
|
733
|
-
}));
|
|
734
|
-
this.app.get(`/${this.restEndpoint}/credentials/new`, _1.ResponseHelper.send(async (req, res) => {
|
|
735
|
-
const requestedName = req.query.name && req.query.name !== '' ? req.query.name : this.defaultCredentialsName;
|
|
736
|
-
return await _1.GenericHelpers.generateUniqueName(requestedName, 'credentials');
|
|
737
|
-
}));
|
|
738
|
-
this.app.delete(`/${this.restEndpoint}/credentials/:id`, _1.ResponseHelper.send(async (req, res) => {
|
|
739
|
-
const { id } = req.params;
|
|
740
|
-
await this.externalHooks.run('credentials.delete', [id]);
|
|
741
|
-
await _1.Db.collections.Credentials.delete({ id });
|
|
742
|
-
return true;
|
|
743
|
-
}));
|
|
744
|
-
this.app.post(`/${this.restEndpoint}/credentials`, _1.ResponseHelper.send(async (req, res) => {
|
|
745
|
-
const incomingData = req.body;
|
|
746
|
-
if (!incomingData.name || incomingData.name.length < 3) {
|
|
747
|
-
throw new _1.ResponseHelper.ResponseError(`Credentials name must be at least 3 characters long.`, undefined, 400);
|
|
748
|
-
}
|
|
749
|
-
for (const nodeAccess of incomingData.nodesAccess) {
|
|
750
|
-
nodeAccess.date = this.getCurrentDate();
|
|
751
|
-
}
|
|
752
|
-
const encryptionKey = await n8n_core_1.UserSettings.getEncryptionKey();
|
|
753
|
-
if (encryptionKey === undefined) {
|
|
754
|
-
throw new Error('No encryption key got found to encrypt the credentials!');
|
|
755
|
-
}
|
|
756
|
-
if (incomingData.name === '') {
|
|
757
|
-
throw new Error('Credentials have to have a name set!');
|
|
758
|
-
}
|
|
759
|
-
const credentials = new n8n_core_1.Credentials({ id: null, name: incomingData.name }, incomingData.type, incomingData.nodesAccess);
|
|
760
|
-
credentials.setData(incomingData.data, encryptionKey);
|
|
761
|
-
const newCredentialsData = credentials.getDataToSave();
|
|
762
|
-
await this.externalHooks.run('credentials.create', [newCredentialsData]);
|
|
763
|
-
const result = await _1.Db.collections.Credentials.save(newCredentialsData);
|
|
764
|
-
result.data = incomingData.data;
|
|
765
|
-
result.id = result.id.toString();
|
|
766
|
-
return result;
|
|
767
|
-
}));
|
|
768
|
-
this.app.post(`/${this.restEndpoint}/credentials-test`, _1.ResponseHelper.send(async (req, res) => {
|
|
769
|
-
const incomingData = req.body;
|
|
770
|
-
const encryptionKey = await n8n_core_1.UserSettings.getEncryptionKey();
|
|
771
|
-
if (encryptionKey === undefined) {
|
|
772
|
-
return {
|
|
773
|
-
status: 'Error',
|
|
774
|
-
message: 'No encryption key got found to decrypt the credentials!',
|
|
775
|
-
};
|
|
776
|
-
}
|
|
777
|
-
const credentialsHelper = new _1.CredentialsHelper(encryptionKey);
|
|
778
|
-
const credentialType = incomingData.credentials.type;
|
|
779
|
-
return credentialsHelper.testCredentials(credentialType, incomingData.credentials, incomingData.nodeToTestWith);
|
|
780
|
-
}));
|
|
781
|
-
this.app.patch(`/${this.restEndpoint}/credentials/:id`, _1.ResponseHelper.send(async (req, res) => {
|
|
782
|
-
const incomingData = req.body;
|
|
783
|
-
const { id } = req.params;
|
|
784
|
-
if (incomingData.name === '') {
|
|
785
|
-
throw new Error('Credentials have to have a name set!');
|
|
786
|
-
}
|
|
787
|
-
for (const nodeAccess of incomingData.nodesAccess) {
|
|
788
|
-
if (!nodeAccess.date) {
|
|
789
|
-
nodeAccess.date = this.getCurrentDate();
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
const encryptionKey = await n8n_core_1.UserSettings.getEncryptionKey();
|
|
793
|
-
if (encryptionKey === undefined) {
|
|
794
|
-
throw new Error('No encryption key got found to encrypt the credentials!');
|
|
795
|
-
}
|
|
796
|
-
const result = await _1.Db.collections.Credentials.findOne(id);
|
|
797
|
-
if (result === undefined) {
|
|
798
|
-
throw new _1.ResponseHelper.ResponseError(`Credentials with the id "${id}" do not exist.`, undefined, 400);
|
|
799
|
-
}
|
|
800
|
-
const currentlySavedCredentials = new n8n_core_1.Credentials(result, result.type, result.nodesAccess, result.data);
|
|
801
|
-
const decryptedData = currentlySavedCredentials.getData(encryptionKey);
|
|
802
|
-
if (decryptedData.oauthTokenData) {
|
|
803
|
-
incomingData.data.oauthTokenData = decryptedData.oauthTokenData;
|
|
804
|
-
}
|
|
805
|
-
const credentials = new n8n_core_1.Credentials({ id, name: incomingData.name }, incomingData.type, incomingData.nodesAccess);
|
|
806
|
-
credentials.setData(incomingData.data, encryptionKey);
|
|
807
|
-
const newCredentialsData = credentials.getDataToSave();
|
|
808
|
-
newCredentialsData.updatedAt = this.getCurrentDate();
|
|
809
|
-
await this.externalHooks.run('credentials.update', [newCredentialsData]);
|
|
810
|
-
await _1.Db.collections.Credentials.update(id, newCredentialsData);
|
|
811
|
-
const responseData = await _1.Db.collections.Credentials.findOne(id);
|
|
812
|
-
if (responseData === undefined) {
|
|
813
|
-
throw new _1.ResponseHelper.ResponseError(`Credentials with id "${id}" could not be found to be updated.`, undefined, 400);
|
|
814
|
-
}
|
|
815
|
-
responseData.data = '';
|
|
816
|
-
responseData.id = responseData.id.toString();
|
|
817
|
-
return responseData;
|
|
818
|
-
}));
|
|
819
|
-
this.app.get(`/${this.restEndpoint}/credentials/:id`, _1.ResponseHelper.send(async (req, res) => {
|
|
820
|
-
const findQuery = {};
|
|
821
|
-
const includeData = ['true', true].includes(req.query.includeData);
|
|
822
|
-
if (!includeData) {
|
|
823
|
-
findQuery.select = ['id', 'name', 'type', 'nodesAccess', 'createdAt', 'updatedAt'];
|
|
824
|
-
}
|
|
825
|
-
const result = await _1.Db.collections.Credentials.findOne(req.params.id);
|
|
826
|
-
if (result === undefined) {
|
|
827
|
-
return result;
|
|
828
|
-
}
|
|
829
|
-
let encryptionKey;
|
|
830
|
-
if (includeData) {
|
|
831
|
-
encryptionKey = await n8n_core_1.UserSettings.getEncryptionKey();
|
|
832
|
-
if (encryptionKey === undefined) {
|
|
833
|
-
throw new Error('No encryption key got found to decrypt the credentials!');
|
|
834
|
-
}
|
|
835
|
-
const credentials = new n8n_core_1.Credentials(result, result.type, result.nodesAccess, result.data);
|
|
836
|
-
result.data = credentials.getData(encryptionKey);
|
|
837
|
-
}
|
|
838
|
-
result.id = result.id.toString();
|
|
839
|
-
return result;
|
|
862
|
+
this.app.get(`/${this.restEndpoint}/active`, _1.ResponseHelper.send(async (req) => {
|
|
863
|
+
const activeWorkflows = await this.activeWorkflowRunner.getActiveWorkflows(req.user);
|
|
864
|
+
return activeWorkflows.map(({ id }) => id.toString());
|
|
840
865
|
}));
|
|
841
|
-
this.app.get(`/${this.restEndpoint}/
|
|
842
|
-
const
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
let result;
|
|
860
|
-
for (result of results) {
|
|
861
|
-
result.id = result.id.toString();
|
|
866
|
+
this.app.get(`/${this.restEndpoint}/active/error/:id`, _1.ResponseHelper.send(async (req) => {
|
|
867
|
+
const { id: workflowId } = req.params;
|
|
868
|
+
const shared = await _1.Db.collections.SharedWorkflow.findOne({
|
|
869
|
+
relations: ['workflow'],
|
|
870
|
+
where: WorkflowHelpers_1.whereClause({
|
|
871
|
+
user: req.user,
|
|
872
|
+
entityType: 'workflow',
|
|
873
|
+
entityId: workflowId,
|
|
874
|
+
}),
|
|
875
|
+
});
|
|
876
|
+
if (!shared) {
|
|
877
|
+
n8n_workflow_1.LoggerProxy.info('User attempted to access workflow errors without permissions', {
|
|
878
|
+
workflowId,
|
|
879
|
+
userId: req.user.id,
|
|
880
|
+
});
|
|
881
|
+
throw new _1.ResponseHelper.ResponseError(`Workflow with ID "${workflowId}" could not be found.`, undefined, 400);
|
|
862
882
|
}
|
|
863
|
-
return
|
|
883
|
+
return this.activeWorkflowRunner.getActivationError(workflowId);
|
|
864
884
|
}));
|
|
865
885
|
this.app.get(`/${this.restEndpoint}/credential-types`, _1.ResponseHelper.send(async (req, res) => {
|
|
866
886
|
const returnData = [];
|
|
@@ -895,26 +915,25 @@ class App {
|
|
|
895
915
|
return _1.ResponseHelper.sendErrorResponse(res, error);
|
|
896
916
|
}
|
|
897
917
|
});
|
|
898
|
-
this.app.get(`/${this.restEndpoint}/oauth1-credential/auth`, _1.ResponseHelper.send(async (req
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
918
|
+
this.app.get(`/${this.restEndpoint}/oauth1-credential/auth`, _1.ResponseHelper.send(async (req) => {
|
|
919
|
+
const { id: credentialId } = req.query;
|
|
920
|
+
if (!credentialId) {
|
|
921
|
+
n8n_workflow_1.LoggerProxy.error('OAuth1 credential authorization failed due to missing credential ID');
|
|
922
|
+
throw new _1.ResponseHelper.ResponseError('Required credential ID is missing', undefined, 400);
|
|
902
923
|
}
|
|
903
|
-
const
|
|
904
|
-
if (
|
|
905
|
-
|
|
906
|
-
|
|
924
|
+
const credential = await _1.getCredentialForUser(credentialId, req.user);
|
|
925
|
+
if (!credential) {
|
|
926
|
+
n8n_workflow_1.LoggerProxy.error('OAuth1 credential authorization failed because the current user does not have the correct permissions', { userId: req.user.id });
|
|
927
|
+
throw new _1.ResponseHelper.ResponseError(constants_1.RESPONSE_ERROR_MESSAGES.NO_CREDENTIAL, undefined, 404);
|
|
907
928
|
}
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
res.status(500).send('No encryption key got found to decrypt the credentials!');
|
|
912
|
-
return '';
|
|
929
|
+
const encryptionKey = await n8n_core_1.UserSettings.getEncryptionKey();
|
|
930
|
+
if (!encryptionKey) {
|
|
931
|
+
throw new _1.ResponseHelper.ResponseError(constants_1.RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY, undefined, 500);
|
|
913
932
|
}
|
|
914
933
|
const mode = 'internal';
|
|
915
934
|
const credentialsHelper = new _1.CredentialsHelper(encryptionKey);
|
|
916
|
-
const decryptedDataOriginal = await credentialsHelper.getDecrypted(
|
|
917
|
-
const oauthCredentials = credentialsHelper.applyDefaultsAndOverwrites(decryptedDataOriginal,
|
|
935
|
+
const decryptedDataOriginal = await credentialsHelper.getDecrypted(credential, credential.type, mode, true);
|
|
936
|
+
const oauthCredentials = credentialsHelper.applyDefaultsAndOverwrites(decryptedDataOriginal, credential.type, mode);
|
|
918
937
|
const signatureMethod = _.get(oauthCredentials, 'signatureMethod');
|
|
919
938
|
const oAuthOptions = {
|
|
920
939
|
consumer: {
|
|
@@ -928,7 +947,7 @@ class App {
|
|
|
928
947
|
},
|
|
929
948
|
};
|
|
930
949
|
const oauthRequestData = {
|
|
931
|
-
oauth_callback: `${_1.WebhookHelpers.getWebhookBaseUrl()}${this.restEndpoint}/oauth1-credential/callback?cid=${
|
|
950
|
+
oauth_callback: `${_1.WebhookHelpers.getWebhookBaseUrl()}${this.restEndpoint}/oauth1-credential/callback?cid=${credentialId}`,
|
|
932
951
|
};
|
|
933
952
|
await this.externalHooks.run('oauth1.authenticate', [oAuthOptions, oauthRequestData]);
|
|
934
953
|
const oauth = new clientOAuth1(oAuthOptions);
|
|
@@ -942,35 +961,46 @@ class App {
|
|
|
942
961
|
const response = await requestPromise(options);
|
|
943
962
|
const responseJson = querystring.parse(response);
|
|
944
963
|
const returnUri = `${_.get(oauthCredentials, 'authUrl')}?oauth_token=${responseJson.oauth_token}`;
|
|
945
|
-
const credentials = new n8n_core_1.Credentials(
|
|
964
|
+
const credentials = new n8n_core_1.Credentials(credential, credential.type, credential.nodesAccess);
|
|
946
965
|
credentials.setData(decryptedDataOriginal, encryptionKey);
|
|
947
966
|
const newCredentialsData = credentials.getDataToSave();
|
|
948
967
|
newCredentialsData.updatedAt = this.getCurrentDate();
|
|
949
|
-
await _1.Db.collections.Credentials.update(
|
|
968
|
+
await _1.Db.collections.Credentials.update(credentialId, newCredentialsData);
|
|
969
|
+
n8n_workflow_1.LoggerProxy.verbose('OAuth1 authorization successful for new credential', {
|
|
970
|
+
userId: req.user.id,
|
|
971
|
+
credentialId,
|
|
972
|
+
});
|
|
950
973
|
return returnUri;
|
|
951
974
|
}));
|
|
952
975
|
this.app.get(`/${this.restEndpoint}/oauth1-credential/callback`, async (req, res) => {
|
|
953
976
|
try {
|
|
954
|
-
const { oauth_verifier, oauth_token, cid } = req.query;
|
|
955
|
-
if (oauth_verifier
|
|
977
|
+
const { oauth_verifier, oauth_token, cid: credentialId } = req.query;
|
|
978
|
+
if (!oauth_verifier || !oauth_token) {
|
|
956
979
|
const errorResponse = new _1.ResponseHelper.ResponseError(`Insufficient parameters for OAuth1 callback. Received following query parameters: ${JSON.stringify(req.query)}`, undefined, 503);
|
|
980
|
+
n8n_workflow_1.LoggerProxy.error('OAuth1 callback failed because of insufficient parameters received', {
|
|
981
|
+
userId: req.user.id,
|
|
982
|
+
credentialId,
|
|
983
|
+
});
|
|
957
984
|
return _1.ResponseHelper.sendErrorResponse(res, errorResponse);
|
|
958
985
|
}
|
|
959
|
-
const
|
|
960
|
-
if (
|
|
961
|
-
|
|
986
|
+
const credential = await _1.getCredentialForUser(credentialId, req.user);
|
|
987
|
+
if (!credential) {
|
|
988
|
+
n8n_workflow_1.LoggerProxy.error('OAuth1 callback failed because of insufficient user permissions', {
|
|
989
|
+
userId: req.user.id,
|
|
990
|
+
credentialId,
|
|
991
|
+
});
|
|
992
|
+
const errorResponse = new _1.ResponseHelper.ResponseError(constants_1.RESPONSE_ERROR_MESSAGES.NO_CREDENTIAL, undefined, 404);
|
|
962
993
|
return _1.ResponseHelper.sendErrorResponse(res, errorResponse);
|
|
963
994
|
}
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
const errorResponse = new _1.ResponseHelper.ResponseError('No encryption key got found to decrypt the credentials!', undefined, 503);
|
|
995
|
+
const encryptionKey = await n8n_core_1.UserSettings.getEncryptionKey();
|
|
996
|
+
if (!encryptionKey) {
|
|
997
|
+
const errorResponse = new _1.ResponseHelper.ResponseError(constants_1.RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY, undefined, 503);
|
|
968
998
|
return _1.ResponseHelper.sendErrorResponse(res, errorResponse);
|
|
969
999
|
}
|
|
970
1000
|
const mode = 'internal';
|
|
971
1001
|
const credentialsHelper = new _1.CredentialsHelper(encryptionKey);
|
|
972
|
-
const decryptedDataOriginal = await credentialsHelper.getDecrypted(
|
|
973
|
-
const oauthCredentials = credentialsHelper.applyDefaultsAndOverwrites(decryptedDataOriginal,
|
|
1002
|
+
const decryptedDataOriginal = await credentialsHelper.getDecrypted(credential, credential.type, mode, true);
|
|
1003
|
+
const oauthCredentials = credentialsHelper.applyDefaultsAndOverwrites(decryptedDataOriginal, credential.type, mode);
|
|
974
1004
|
const options = {
|
|
975
1005
|
method: 'POST',
|
|
976
1006
|
url: _.get(oauthCredentials, 'accessTokenUrl'),
|
|
@@ -984,42 +1014,55 @@ class App {
|
|
|
984
1014
|
oauthToken = await requestPromise(options);
|
|
985
1015
|
}
|
|
986
1016
|
catch (error) {
|
|
1017
|
+
n8n_workflow_1.LoggerProxy.error('Unable to fetch tokens for OAuth1 callback', {
|
|
1018
|
+
userId: req.user.id,
|
|
1019
|
+
credentialId,
|
|
1020
|
+
});
|
|
987
1021
|
const errorResponse = new _1.ResponseHelper.ResponseError('Unable to get access tokens!', undefined, 404);
|
|
988
1022
|
return _1.ResponseHelper.sendErrorResponse(res, errorResponse);
|
|
989
1023
|
}
|
|
990
1024
|
const oauthTokenJson = querystring.parse(oauthToken);
|
|
991
1025
|
decryptedDataOriginal.oauthTokenData = oauthTokenJson;
|
|
992
|
-
const credentials = new n8n_core_1.Credentials(
|
|
1026
|
+
const credentials = new n8n_core_1.Credentials(credential, credential.type, credential.nodesAccess);
|
|
993
1027
|
credentials.setData(decryptedDataOriginal, encryptionKey);
|
|
994
1028
|
const newCredentialsData = credentials.getDataToSave();
|
|
995
1029
|
newCredentialsData.updatedAt = this.getCurrentDate();
|
|
996
|
-
await _1.Db.collections.Credentials.update(
|
|
1030
|
+
await _1.Db.collections.Credentials.update(credentialId, newCredentialsData);
|
|
1031
|
+
n8n_workflow_1.LoggerProxy.verbose('OAuth1 callback successful for new credential', {
|
|
1032
|
+
userId: req.user.id,
|
|
1033
|
+
credentialId,
|
|
1034
|
+
});
|
|
997
1035
|
res.sendFile(path_1.resolve(__dirname, '../../templates/oauth-callback.html'));
|
|
998
1036
|
}
|
|
999
1037
|
catch (error) {
|
|
1038
|
+
n8n_workflow_1.LoggerProxy.error('OAuth1 callback failed because of insufficient user permissions', {
|
|
1039
|
+
userId: req.user.id,
|
|
1040
|
+
credentialId: req.query.cid,
|
|
1041
|
+
});
|
|
1000
1042
|
return _1.ResponseHelper.sendErrorResponse(res, error);
|
|
1001
1043
|
}
|
|
1002
1044
|
});
|
|
1003
|
-
this.app.get(`/${this.restEndpoint}/oauth2-credential/auth`, _1.ResponseHelper.send(async (req
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
}
|
|
1008
|
-
const
|
|
1009
|
-
if (
|
|
1010
|
-
|
|
1011
|
-
|
|
1045
|
+
this.app.get(`/${this.restEndpoint}/oauth2-credential/auth`, _1.ResponseHelper.send(async (req) => {
|
|
1046
|
+
const { id: credentialId } = req.query;
|
|
1047
|
+
if (!credentialId) {
|
|
1048
|
+
throw new _1.ResponseHelper.ResponseError('Required credential ID is missing', undefined, 400);
|
|
1049
|
+
}
|
|
1050
|
+
const credential = await _1.getCredentialForUser(credentialId, req.user);
|
|
1051
|
+
if (!credential) {
|
|
1052
|
+
n8n_workflow_1.LoggerProxy.error('Failed to authorize OAuth2 due to lack of permissions', {
|
|
1053
|
+
userId: req.user.id,
|
|
1054
|
+
credentialId,
|
|
1055
|
+
});
|
|
1056
|
+
throw new _1.ResponseHelper.ResponseError(constants_1.RESPONSE_ERROR_MESSAGES.NO_CREDENTIAL, undefined, 404);
|
|
1012
1057
|
}
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
res.status(500).send('No encryption key got found to decrypt the credentials!');
|
|
1017
|
-
return '';
|
|
1058
|
+
const encryptionKey = await n8n_core_1.UserSettings.getEncryptionKey();
|
|
1059
|
+
if (!encryptionKey) {
|
|
1060
|
+
throw new _1.ResponseHelper.ResponseError(constants_1.RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY, undefined, 500);
|
|
1018
1061
|
}
|
|
1019
1062
|
const mode = 'internal';
|
|
1020
1063
|
const credentialsHelper = new _1.CredentialsHelper(encryptionKey);
|
|
1021
|
-
const decryptedDataOriginal = await credentialsHelper.getDecrypted(
|
|
1022
|
-
const oauthCredentials = credentialsHelper.applyDefaultsAndOverwrites(decryptedDataOriginal,
|
|
1064
|
+
const decryptedDataOriginal = await credentialsHelper.getDecrypted(credential, credential.type, mode, true);
|
|
1065
|
+
const oauthCredentials = credentialsHelper.applyDefaultsAndOverwrites(decryptedDataOriginal, credential.type, mode);
|
|
1023
1066
|
const token = new csrf();
|
|
1024
1067
|
const csrfSecret = token.secretSync();
|
|
1025
1068
|
const state = {
|
|
@@ -1038,7 +1081,7 @@ class App {
|
|
|
1038
1081
|
};
|
|
1039
1082
|
await this.externalHooks.run('oauth2.authenticate', [oAuthOptions]);
|
|
1040
1083
|
const oAuthObj = new clientOAuth2(oAuthOptions);
|
|
1041
|
-
const credentials = new n8n_core_1.Credentials(
|
|
1084
|
+
const credentials = new n8n_core_1.Credentials(credential, credential.type, credential.nodesAccess);
|
|
1042
1085
|
decryptedDataOriginal.csrfSecret = csrfSecret;
|
|
1043
1086
|
credentials.setData(decryptedDataOriginal, encryptionKey);
|
|
1044
1087
|
const newCredentialsData = credentials.getDataToSave();
|
|
@@ -1054,12 +1097,16 @@ class App {
|
|
|
1054
1097
|
if (authQueryParameters) {
|
|
1055
1098
|
returnUri += `&${authQueryParameters}`;
|
|
1056
1099
|
}
|
|
1100
|
+
n8n_workflow_1.LoggerProxy.verbose('OAuth2 authentication successful for new credential', {
|
|
1101
|
+
userId: req.user.id,
|
|
1102
|
+
credentialId,
|
|
1103
|
+
});
|
|
1057
1104
|
return returnUri;
|
|
1058
1105
|
}));
|
|
1059
1106
|
this.app.get(`/${this.restEndpoint}/oauth2-credential/callback`, async (req, res) => {
|
|
1060
1107
|
try {
|
|
1061
1108
|
const { code, state: stateEncoded } = req.query;
|
|
1062
|
-
if (code
|
|
1109
|
+
if (!code || !stateEncoded) {
|
|
1063
1110
|
const errorResponse = new _1.ResponseHelper.ResponseError(`Insufficient parameters for OAuth2 callback. Received following query parameters: ${JSON.stringify(req.query)}`, undefined, 503);
|
|
1064
1111
|
return _1.ResponseHelper.sendErrorResponse(res, errorResponse);
|
|
1065
1112
|
}
|
|
@@ -1071,24 +1118,31 @@ class App {
|
|
|
1071
1118
|
const errorResponse = new _1.ResponseHelper.ResponseError('Invalid state format returned', undefined, 503);
|
|
1072
1119
|
return _1.ResponseHelper.sendErrorResponse(res, errorResponse);
|
|
1073
1120
|
}
|
|
1074
|
-
const
|
|
1075
|
-
if (
|
|
1076
|
-
|
|
1121
|
+
const credential = await _1.getCredentialForUser(state.cid, req.user);
|
|
1122
|
+
if (!credential) {
|
|
1123
|
+
n8n_workflow_1.LoggerProxy.error('OAuth2 callback failed because of insufficient permissions', {
|
|
1124
|
+
userId: req.user.id,
|
|
1125
|
+
credentialId: state.cid,
|
|
1126
|
+
});
|
|
1127
|
+
const errorResponse = new _1.ResponseHelper.ResponseError(constants_1.RESPONSE_ERROR_MESSAGES.NO_CREDENTIAL, undefined, 404);
|
|
1077
1128
|
return _1.ResponseHelper.sendErrorResponse(res, errorResponse);
|
|
1078
1129
|
}
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
const errorResponse = new _1.ResponseHelper.ResponseError('No encryption key got found to decrypt the credentials!', undefined, 503);
|
|
1130
|
+
const encryptionKey = await n8n_core_1.UserSettings.getEncryptionKey();
|
|
1131
|
+
if (!encryptionKey) {
|
|
1132
|
+
const errorResponse = new _1.ResponseHelper.ResponseError(constants_1.RESPONSE_ERROR_MESSAGES.NO_ENCRYPTION_KEY, undefined, 503);
|
|
1083
1133
|
return _1.ResponseHelper.sendErrorResponse(res, errorResponse);
|
|
1084
1134
|
}
|
|
1085
1135
|
const mode = 'internal';
|
|
1086
1136
|
const credentialsHelper = new _1.CredentialsHelper(encryptionKey);
|
|
1087
|
-
const decryptedDataOriginal = await credentialsHelper.getDecrypted(
|
|
1088
|
-
const oauthCredentials = credentialsHelper.applyDefaultsAndOverwrites(decryptedDataOriginal,
|
|
1137
|
+
const decryptedDataOriginal = await credentialsHelper.getDecrypted(credential, credential.type, mode, true);
|
|
1138
|
+
const oauthCredentials = credentialsHelper.applyDefaultsAndOverwrites(decryptedDataOriginal, credential.type, mode);
|
|
1089
1139
|
const token = new csrf();
|
|
1090
1140
|
if (decryptedDataOriginal.csrfSecret === undefined ||
|
|
1091
1141
|
!token.verify(decryptedDataOriginal.csrfSecret, state.token)) {
|
|
1142
|
+
n8n_workflow_1.LoggerProxy.debug('OAuth2 callback state is invalid', {
|
|
1143
|
+
userId: req.user.id,
|
|
1144
|
+
credentialId: state.cid,
|
|
1145
|
+
});
|
|
1092
1146
|
const errorResponse = new _1.ResponseHelper.ResponseError('The OAuth2 callback state is invalid!', undefined, 404);
|
|
1093
1147
|
return _1.ResponseHelper.sendErrorResponse(res, errorResponse);
|
|
1094
1148
|
}
|
|
@@ -1118,6 +1172,10 @@ class App {
|
|
|
1118
1172
|
_.set(oauthToken.data, 'callbackQueryString', _.omit(req.query, 'state', 'code'));
|
|
1119
1173
|
}
|
|
1120
1174
|
if (oauthToken === undefined) {
|
|
1175
|
+
n8n_workflow_1.LoggerProxy.error('OAuth2 callback failed: unable to get access tokens', {
|
|
1176
|
+
userId: req.user.id,
|
|
1177
|
+
credentialId: state.cid,
|
|
1178
|
+
});
|
|
1121
1179
|
const errorResponse = new _1.ResponseHelper.ResponseError('Unable to get access tokens!', undefined, 404);
|
|
1122
1180
|
return _1.ResponseHelper.sendErrorResponse(res, errorResponse);
|
|
1123
1181
|
}
|
|
@@ -1128,124 +1186,152 @@ class App {
|
|
|
1128
1186
|
decryptedDataOriginal.oauthTokenData = oauthToken.data;
|
|
1129
1187
|
}
|
|
1130
1188
|
_.unset(decryptedDataOriginal, 'csrfSecret');
|
|
1131
|
-
const credentials = new n8n_core_1.Credentials(
|
|
1189
|
+
const credentials = new n8n_core_1.Credentials(credential, credential.type, credential.nodesAccess);
|
|
1132
1190
|
credentials.setData(decryptedDataOriginal, encryptionKey);
|
|
1133
1191
|
const newCredentialsData = credentials.getDataToSave();
|
|
1134
1192
|
newCredentialsData.updatedAt = this.getCurrentDate();
|
|
1135
1193
|
await _1.Db.collections.Credentials.update(state.cid, newCredentialsData);
|
|
1194
|
+
n8n_workflow_1.LoggerProxy.verbose('OAuth2 callback successful for new credential', {
|
|
1195
|
+
userId: req.user.id,
|
|
1196
|
+
credentialId: state.cid,
|
|
1197
|
+
});
|
|
1136
1198
|
res.sendFile(path_1.resolve(__dirname, '../../templates/oauth-callback.html'));
|
|
1137
1199
|
}
|
|
1138
1200
|
catch (error) {
|
|
1139
1201
|
return _1.ResponseHelper.sendErrorResponse(res, error);
|
|
1140
1202
|
}
|
|
1141
1203
|
});
|
|
1142
|
-
this.app.get(`/${this.restEndpoint}/executions`, _1.ResponseHelper.send(async (req
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
let limit = 20;
|
|
1148
|
-
if (req.query.limit) {
|
|
1149
|
-
limit = parseInt(req.query.limit, 10);
|
|
1150
|
-
}
|
|
1204
|
+
this.app.get(`/${this.restEndpoint}/executions`, _1.ResponseHelper.send(async (req) => {
|
|
1205
|
+
const filter = req.query.filter ? JSON.parse(req.query.filter) : {};
|
|
1206
|
+
const limit = req.query.limit
|
|
1207
|
+
? parseInt(req.query.limit, 10)
|
|
1208
|
+
: GenericHelpers_1.DEFAULT_EXECUTIONS_GET_ALL_LIMIT;
|
|
1151
1209
|
const executingWorkflowIds = [];
|
|
1152
1210
|
if (config.get('executions.mode') === 'queue') {
|
|
1153
1211
|
const currentJobs = await Queue.getInstance().getJobs(['active', 'waiting']);
|
|
1154
|
-
executingWorkflowIds.push(...currentJobs.map((
|
|
1155
|
-
}
|
|
1156
|
-
executingWorkflowIds.push(...this.activeExecutionsInstance
|
|
1157
|
-
.getActiveExecutions()
|
|
1158
|
-
.map((execution) => execution.id.toString()));
|
|
1159
|
-
const countFilter = JSON.parse(JSON.stringify(filter));
|
|
1160
|
-
if (countFilter.waitTill !== undefined) {
|
|
1161
|
-
countFilter.waitTill = typeorm_1.Not(typeorm_1.IsNull());
|
|
1212
|
+
executingWorkflowIds.push(...currentJobs.map(({ data }) => data.executionId));
|
|
1162
1213
|
}
|
|
1214
|
+
executingWorkflowIds.push(...this.activeExecutionsInstance.getActiveExecutions().map(({ id }) => id));
|
|
1215
|
+
const countFilter = lodash_1.cloneDeep(filter);
|
|
1216
|
+
countFilter.waitTill && (countFilter.waitTill = typeorm_1.Not(typeorm_1.IsNull()));
|
|
1163
1217
|
countFilter.id = typeorm_1.Not(typeorm_1.In(executingWorkflowIds));
|
|
1164
|
-
const
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
.
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1218
|
+
const sharedWorkflowIds = await WorkflowHelpers_1.getSharedWorkflowIds(req.user);
|
|
1219
|
+
const findOptions = {
|
|
1220
|
+
select: [
|
|
1221
|
+
'id',
|
|
1222
|
+
'finished',
|
|
1223
|
+
'mode',
|
|
1224
|
+
'retryOf',
|
|
1225
|
+
'retrySuccessId',
|
|
1226
|
+
'waitTill',
|
|
1227
|
+
'startedAt',
|
|
1228
|
+
'stoppedAt',
|
|
1229
|
+
'workflowData',
|
|
1230
|
+
],
|
|
1231
|
+
where: { workflowId: typeorm_1.In(sharedWorkflowIds) },
|
|
1232
|
+
order: { id: 'DESC' },
|
|
1233
|
+
take: limit,
|
|
1234
|
+
};
|
|
1235
|
+
Object.entries(filter).forEach(([key, value]) => {
|
|
1236
|
+
let filterToAdd = {};
|
|
1237
|
+
if (key === 'waitTill') {
|
|
1238
|
+
filterToAdd = { waitTill: !typeorm_1.IsNull() };
|
|
1239
|
+
}
|
|
1240
|
+
else if (key === 'finished' && value === false) {
|
|
1241
|
+
filterToAdd = { finished: false, waitTill: typeorm_1.IsNull() };
|
|
1188
1242
|
}
|
|
1189
1243
|
else {
|
|
1190
|
-
|
|
1191
|
-
[filterField]: filter[filterField],
|
|
1192
|
-
});
|
|
1244
|
+
filterToAdd = { [key]: value };
|
|
1193
1245
|
}
|
|
1246
|
+
Object.assign(findOptions.where, filterToAdd);
|
|
1194
1247
|
});
|
|
1248
|
+
const rangeQuery = [];
|
|
1249
|
+
const rangeQueryParams = {};
|
|
1195
1250
|
if (req.query.lastId) {
|
|
1196
|
-
|
|
1251
|
+
rangeQuery.push('id < :lastId');
|
|
1252
|
+
rangeQueryParams.lastId = req.query.lastId;
|
|
1197
1253
|
}
|
|
1198
1254
|
if (req.query.firstId) {
|
|
1199
|
-
|
|
1255
|
+
rangeQuery.push('id > :firstId');
|
|
1256
|
+
rangeQueryParams.firstId = req.query.firstId;
|
|
1200
1257
|
}
|
|
1201
1258
|
if (executingWorkflowIds.length > 0) {
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
const returnResults = [];
|
|
1209
|
-
for (const result of results) {
|
|
1210
|
-
returnResults.push({
|
|
1211
|
-
id: result.id.toString(),
|
|
1212
|
-
finished: result.finished,
|
|
1213
|
-
mode: result.mode,
|
|
1214
|
-
retryOf: result.retryOf ? result.retryOf.toString() : undefined,
|
|
1215
|
-
retrySuccessId: result.retrySuccessId ? result.retrySuccessId.toString() : undefined,
|
|
1216
|
-
waitTill: result.waitTill,
|
|
1217
|
-
startedAt: result.startedAt,
|
|
1218
|
-
stoppedAt: result.stoppedAt,
|
|
1219
|
-
workflowId: result.workflowData.id ? result.workflowData.id.toString() : '',
|
|
1220
|
-
workflowName: result.workflowData.name,
|
|
1259
|
+
rangeQuery.push(`id NOT IN (:...executingWorkflowIds)`);
|
|
1260
|
+
rangeQueryParams.executingWorkflowIds = executingWorkflowIds;
|
|
1261
|
+
}
|
|
1262
|
+
if (rangeQuery.length) {
|
|
1263
|
+
Object.assign(findOptions.where, {
|
|
1264
|
+
id: typeorm_1.Raw(() => rangeQuery.join(' and '), rangeQueryParams),
|
|
1221
1265
|
});
|
|
1222
1266
|
}
|
|
1267
|
+
const executions = await _1.Db.collections.Execution.find(findOptions);
|
|
1268
|
+
const { count, estimated } = await getExecutionsCount(countFilter, req.user);
|
|
1269
|
+
const formattedExecutions = executions.map((execution) => {
|
|
1270
|
+
var _a, _b, _c, _d, _e;
|
|
1271
|
+
return {
|
|
1272
|
+
id: execution.id.toString(),
|
|
1273
|
+
finished: execution.finished,
|
|
1274
|
+
mode: execution.mode,
|
|
1275
|
+
retryOf: (_a = execution.retryOf) === null || _a === void 0 ? void 0 : _a.toString(),
|
|
1276
|
+
retrySuccessId: (_b = execution === null || execution === void 0 ? void 0 : execution.retrySuccessId) === null || _b === void 0 ? void 0 : _b.toString(),
|
|
1277
|
+
waitTill: execution.waitTill,
|
|
1278
|
+
startedAt: execution.startedAt,
|
|
1279
|
+
stoppedAt: execution.stoppedAt,
|
|
1280
|
+
workflowId: (_e = (_d = (_c = execution.workflowData) === null || _c === void 0 ? void 0 : _c.id) === null || _d === void 0 ? void 0 : _d.toString()) !== null && _e !== void 0 ? _e : '',
|
|
1281
|
+
workflowName: execution.workflowData.name,
|
|
1282
|
+
};
|
|
1283
|
+
});
|
|
1223
1284
|
return {
|
|
1224
|
-
count
|
|
1225
|
-
results:
|
|
1226
|
-
estimated
|
|
1285
|
+
count,
|
|
1286
|
+
results: formattedExecutions,
|
|
1287
|
+
estimated,
|
|
1227
1288
|
};
|
|
1228
1289
|
}));
|
|
1229
|
-
this.app.get(`/${this.restEndpoint}/executions/:id`, _1.ResponseHelper.send(async (req
|
|
1230
|
-
const
|
|
1231
|
-
|
|
1290
|
+
this.app.get(`/${this.restEndpoint}/executions/:id`, _1.ResponseHelper.send(async (req) => {
|
|
1291
|
+
const { id: executionId } = req.params;
|
|
1292
|
+
const sharedWorkflowIds = await WorkflowHelpers_1.getSharedWorkflowIds(req.user);
|
|
1293
|
+
if (!sharedWorkflowIds.length)
|
|
1294
|
+
return undefined;
|
|
1295
|
+
const execution = await _1.Db.collections.Execution.findOne({
|
|
1296
|
+
where: {
|
|
1297
|
+
id: executionId,
|
|
1298
|
+
workflowId: typeorm_1.In(sharedWorkflowIds),
|
|
1299
|
+
},
|
|
1300
|
+
});
|
|
1301
|
+
if (!execution) {
|
|
1302
|
+
n8n_workflow_1.LoggerProxy.info('Attempt to read execution was blocked due to insufficient permissions', {
|
|
1303
|
+
userId: req.user.id,
|
|
1304
|
+
executionId,
|
|
1305
|
+
});
|
|
1232
1306
|
return undefined;
|
|
1233
1307
|
}
|
|
1234
1308
|
if (req.query.unflattedResponse === 'true') {
|
|
1235
|
-
|
|
1236
|
-
return fullExecutionData;
|
|
1309
|
+
return _1.ResponseHelper.unflattenExecutionData(execution);
|
|
1237
1310
|
}
|
|
1238
|
-
|
|
1239
|
-
return
|
|
1311
|
+
const { id } = execution, rest = __rest(execution, ["id"]);
|
|
1312
|
+
return Object.assign({ id: id.toString() }, rest);
|
|
1240
1313
|
}));
|
|
1241
|
-
this.app.post(`/${this.restEndpoint}/executions/:id/retry`, _1.ResponseHelper.send(async (req
|
|
1242
|
-
const
|
|
1243
|
-
|
|
1244
|
-
|
|
1314
|
+
this.app.post(`/${this.restEndpoint}/executions/:id/retry`, _1.ResponseHelper.send(async (req) => {
|
|
1315
|
+
const { id: executionId } = req.params;
|
|
1316
|
+
const sharedWorkflowIds = await WorkflowHelpers_1.getSharedWorkflowIds(req.user);
|
|
1317
|
+
if (!sharedWorkflowIds.length)
|
|
1318
|
+
return false;
|
|
1319
|
+
const execution = await _1.Db.collections.Execution.findOne({
|
|
1320
|
+
where: {
|
|
1321
|
+
id: executionId,
|
|
1322
|
+
workflowId: typeorm_1.In(sharedWorkflowIds),
|
|
1323
|
+
},
|
|
1324
|
+
});
|
|
1325
|
+
if (!execution) {
|
|
1326
|
+
n8n_workflow_1.LoggerProxy.info('Attempt to retry an execution was blocked due to insufficient permissions', {
|
|
1327
|
+
userId: req.user.id,
|
|
1328
|
+
executionId,
|
|
1329
|
+
});
|
|
1330
|
+
throw new _1.ResponseHelper.ResponseError(`The execution with the ID "${executionId}" does not exist.`, 404, 404);
|
|
1245
1331
|
}
|
|
1246
|
-
const fullExecutionData = _1.ResponseHelper.unflattenExecutionData(
|
|
1332
|
+
const fullExecutionData = _1.ResponseHelper.unflattenExecutionData(execution);
|
|
1247
1333
|
if (fullExecutionData.finished) {
|
|
1248
|
-
throw new Error('The execution
|
|
1334
|
+
throw new Error('The execution succeeded, so it cannot be retried.');
|
|
1249
1335
|
}
|
|
1250
1336
|
const executionMode = 'retry';
|
|
1251
1337
|
fullExecutionData.workflowData.active = false;
|
|
@@ -1254,6 +1340,7 @@ class App {
|
|
|
1254
1340
|
executionData: fullExecutionData.data,
|
|
1255
1341
|
retryOf: req.params.id,
|
|
1256
1342
|
workflowData: fullExecutionData.workflowData,
|
|
1343
|
+
userId: req.user.id,
|
|
1257
1344
|
};
|
|
1258
1345
|
const { lastNodeExecuted } = data.executionData.resultData;
|
|
1259
1346
|
if (lastNodeExecuted) {
|
|
@@ -1264,7 +1351,7 @@ class App {
|
|
|
1264
1351
|
data.executionData.resultData.runData[lastNodeExecuted].pop();
|
|
1265
1352
|
}
|
|
1266
1353
|
}
|
|
1267
|
-
if (req.body.loadWorkflow
|
|
1354
|
+
if (req.body.loadWorkflow) {
|
|
1268
1355
|
const workflowId = fullExecutionData.workflowData.id;
|
|
1269
1356
|
const workflowData = (await _1.Db.collections.Workflow.findOne(workflowId));
|
|
1270
1357
|
if (workflowData === undefined) {
|
|
@@ -1285,88 +1372,115 @@ class App {
|
|
|
1285
1372
|
for (const stack of data.executionData.executionData.nodeExecutionStack) {
|
|
1286
1373
|
const node = workflowInstance.getNode(stack.node.name);
|
|
1287
1374
|
if (node === null) {
|
|
1375
|
+
n8n_workflow_1.LoggerProxy.error('Failed to retry an execution because a node could not be found', {
|
|
1376
|
+
userId: req.user.id,
|
|
1377
|
+
executionId,
|
|
1378
|
+
nodeName: stack.node.name,
|
|
1379
|
+
});
|
|
1288
1380
|
throw new Error(`Could not find the node "${stack.node.name}" in workflow. It probably got deleted or renamed. Without it the workflow can sadly not be retried.`);
|
|
1289
1381
|
}
|
|
1290
1382
|
stack.node = node;
|
|
1291
1383
|
}
|
|
1292
1384
|
}
|
|
1293
1385
|
const workflowRunner = new _1.WorkflowRunner();
|
|
1294
|
-
const
|
|
1295
|
-
const executionData = await this.activeExecutionsInstance.getPostExecutePromise(
|
|
1296
|
-
if (executionData
|
|
1386
|
+
const retriedExecutionId = await workflowRunner.run(data);
|
|
1387
|
+
const executionData = await this.activeExecutionsInstance.getPostExecutePromise(retriedExecutionId);
|
|
1388
|
+
if (!executionData) {
|
|
1297
1389
|
throw new Error('The retry did not start for an unknown reason.');
|
|
1298
1390
|
}
|
|
1299
1391
|
return !!executionData.finished;
|
|
1300
1392
|
}));
|
|
1301
|
-
this.app.post(`/${this.restEndpoint}/executions/delete`, _1.ResponseHelper.send(async (req
|
|
1302
|
-
const
|
|
1303
|
-
if (
|
|
1393
|
+
this.app.post(`/${this.restEndpoint}/executions/delete`, _1.ResponseHelper.send(async (req) => {
|
|
1394
|
+
const { deleteBefore, ids, filters: requestFilters } = req.body;
|
|
1395
|
+
if (!deleteBefore && !ids) {
|
|
1396
|
+
throw new Error('Either "deleteBefore" or "ids" must be present in the request body');
|
|
1397
|
+
}
|
|
1398
|
+
const sharedWorkflowIds = await WorkflowHelpers_1.getSharedWorkflowIds(req.user);
|
|
1399
|
+
const binaryDataManager = n8n_core_1.BinaryDataManager.getInstance();
|
|
1400
|
+
if (deleteBefore) {
|
|
1304
1401
|
const filters = {
|
|
1305
|
-
startedAt: typeorm_1.LessThanOrEqual(
|
|
1402
|
+
startedAt: typeorm_1.LessThanOrEqual(deleteBefore),
|
|
1306
1403
|
};
|
|
1307
|
-
if (
|
|
1308
|
-
Object.assign(filters,
|
|
1404
|
+
if (filters) {
|
|
1405
|
+
Object.assign(filters, requestFilters);
|
|
1309
1406
|
}
|
|
1310
|
-
const
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
await
|
|
1407
|
+
const executions = await _1.Db.collections.Execution.find({
|
|
1408
|
+
where: Object.assign({ workflowId: typeorm_1.In(sharedWorkflowIds) }, filters),
|
|
1409
|
+
});
|
|
1410
|
+
if (!executions.length)
|
|
1411
|
+
return;
|
|
1412
|
+
const idsToDelete = executions.map(({ id }) => id.toString());
|
|
1413
|
+
await Promise.all(idsToDelete.map(async (id) => binaryDataManager.deleteBinaryDataByExecutionId(id)));
|
|
1414
|
+
await _1.Db.collections.Execution.delete({ id: typeorm_1.In(idsToDelete) });
|
|
1415
|
+
return;
|
|
1317
1416
|
}
|
|
1318
|
-
|
|
1319
|
-
|
|
1417
|
+
if (ids) {
|
|
1418
|
+
const executions = await _1.Db.collections.Execution.find({
|
|
1419
|
+
where: {
|
|
1420
|
+
id: typeorm_1.In(ids),
|
|
1421
|
+
workflowId: typeorm_1.In(sharedWorkflowIds),
|
|
1422
|
+
},
|
|
1423
|
+
});
|
|
1424
|
+
if (!executions.length) {
|
|
1425
|
+
n8n_workflow_1.LoggerProxy.error('Failed to delete an execution due to insufficient permissions', {
|
|
1426
|
+
userId: req.user.id,
|
|
1427
|
+
executionIds: ids,
|
|
1428
|
+
});
|
|
1429
|
+
return;
|
|
1430
|
+
}
|
|
1431
|
+
const idsToDelete = executions.map(({ id }) => id.toString());
|
|
1432
|
+
await Promise.all(idsToDelete.map(async (id) => binaryDataManager.deleteBinaryDataByExecutionId(id)));
|
|
1433
|
+
await _1.Db.collections.Execution.delete(idsToDelete);
|
|
1320
1434
|
}
|
|
1321
1435
|
}));
|
|
1322
|
-
this.app.get(`/${this.restEndpoint}/executions-current`, _1.ResponseHelper.send(async (req
|
|
1436
|
+
this.app.get(`/${this.restEndpoint}/executions-current`, _1.ResponseHelper.send(async (req) => {
|
|
1323
1437
|
if (config.get('executions.mode') === 'queue') {
|
|
1324
1438
|
const currentJobs = await Queue.getInstance().getJobs(['active', 'waiting']);
|
|
1325
1439
|
const currentlyRunningQueueIds = currentJobs.map((job) => job.data.executionId);
|
|
1326
1440
|
const currentlyRunningManualExecutions = this.activeExecutionsInstance.getActiveExecutions();
|
|
1327
1441
|
const manualExecutionIds = currentlyRunningManualExecutions.map((execution) => execution.id);
|
|
1328
1442
|
const currentlyRunningExecutionIds = currentlyRunningQueueIds.concat(manualExecutionIds);
|
|
1329
|
-
if (currentlyRunningExecutionIds.length
|
|
1443
|
+
if (!currentlyRunningExecutionIds.length)
|
|
1444
|
+
return [];
|
|
1445
|
+
const findOptions = {
|
|
1446
|
+
select: ['id', 'workflowId', 'mode', 'retryOf', 'startedAt'],
|
|
1447
|
+
order: { id: 'DESC' },
|
|
1448
|
+
where: {
|
|
1449
|
+
id: typeorm_1.In(currentlyRunningExecutionIds),
|
|
1450
|
+
},
|
|
1451
|
+
};
|
|
1452
|
+
const sharedWorkflowIds = await WorkflowHelpers_1.getSharedWorkflowIds(req.user);
|
|
1453
|
+
if (!sharedWorkflowIds.length)
|
|
1330
1454
|
return [];
|
|
1331
|
-
}
|
|
1332
|
-
const resultsQuery = await _1.Db.collections
|
|
1333
|
-
.Execution.createQueryBuilder('execution')
|
|
1334
|
-
.select([
|
|
1335
|
-
'execution.id',
|
|
1336
|
-
'execution.workflowId',
|
|
1337
|
-
'execution.mode',
|
|
1338
|
-
'execution.retryOf',
|
|
1339
|
-
'execution.startedAt',
|
|
1340
|
-
])
|
|
1341
|
-
.orderBy('execution.id', 'DESC')
|
|
1342
|
-
.andWhere(`execution.id IN (:...ids)`, { ids: currentlyRunningExecutionIds });
|
|
1343
1455
|
if (req.query.filter) {
|
|
1344
|
-
const
|
|
1345
|
-
if (
|
|
1346
|
-
|
|
1347
|
-
workflowId: filter.workflowId,
|
|
1348
|
-
});
|
|
1456
|
+
const { workflowId } = JSON.parse(req.query.filter);
|
|
1457
|
+
if (workflowId && sharedWorkflowIds.includes(workflowId)) {
|
|
1458
|
+
Object.assign(findOptions.where, { workflowId });
|
|
1349
1459
|
}
|
|
1350
1460
|
}
|
|
1351
|
-
|
|
1352
|
-
|
|
1461
|
+
else {
|
|
1462
|
+
Object.assign(findOptions.where, { workflowId: typeorm_1.In(sharedWorkflowIds) });
|
|
1463
|
+
}
|
|
1464
|
+
const executions = await _1.Db.collections.Execution.find(findOptions);
|
|
1465
|
+
if (!executions.length)
|
|
1466
|
+
return [];
|
|
1467
|
+
return executions.map((execution) => {
|
|
1353
1468
|
return {
|
|
1354
|
-
id:
|
|
1355
|
-
workflowId:
|
|
1356
|
-
mode:
|
|
1357
|
-
retryOf:
|
|
1358
|
-
startedAt: new Date(
|
|
1469
|
+
id: execution.id,
|
|
1470
|
+
workflowId: execution.workflowId,
|
|
1471
|
+
mode: execution.mode,
|
|
1472
|
+
retryOf: execution.retryOf !== null ? execution.retryOf : undefined,
|
|
1473
|
+
startedAt: new Date(execution.startedAt),
|
|
1359
1474
|
};
|
|
1360
1475
|
});
|
|
1361
1476
|
}
|
|
1362
1477
|
const executingWorkflows = this.activeExecutionsInstance.getActiveExecutions();
|
|
1363
1478
|
const returnData = [];
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
filter = JSON.parse(req.query.filter);
|
|
1367
|
-
}
|
|
1479
|
+
const filter = req.query.filter ? JSON.parse(req.query.filter) : {};
|
|
1480
|
+
const sharedWorkflowIds = await WorkflowHelpers_1.getSharedWorkflowIds(req.user).then((ids) => ids.map((id) => id.toString()));
|
|
1368
1481
|
for (const data of executingWorkflows) {
|
|
1369
|
-
if (filter.workflowId !== undefined && filter.workflowId !== data.workflowId)
|
|
1482
|
+
if ((filter.workflowId !== undefined && filter.workflowId !== data.workflowId) ||
|
|
1483
|
+
!sharedWorkflowIds.includes(data.workflowId)) {
|
|
1370
1484
|
continue;
|
|
1371
1485
|
}
|
|
1372
1486
|
returnData.push({
|
|
@@ -1380,8 +1494,22 @@ class App {
|
|
|
1380
1494
|
returnData.sort((a, b) => parseInt(b.id, 10) - parseInt(a.id, 10));
|
|
1381
1495
|
return returnData;
|
|
1382
1496
|
}));
|
|
1383
|
-
this.app.post(`/${this.restEndpoint}/executions-current/:id/stop`, _1.ResponseHelper.send(async (req
|
|
1497
|
+
this.app.post(`/${this.restEndpoint}/executions-current/:id/stop`, _1.ResponseHelper.send(async (req) => {
|
|
1384
1498
|
var _a;
|
|
1499
|
+
const { id: executionId } = req.params;
|
|
1500
|
+
const sharedWorkflowIds = await WorkflowHelpers_1.getSharedWorkflowIds(req.user);
|
|
1501
|
+
if (!sharedWorkflowIds.length) {
|
|
1502
|
+
throw new _1.ResponseHelper.ResponseError('Execution not found', undefined, 404);
|
|
1503
|
+
}
|
|
1504
|
+
const execution = await _1.Db.collections.Execution.findOne({
|
|
1505
|
+
where: {
|
|
1506
|
+
id: executionId,
|
|
1507
|
+
workflowId: typeorm_1.In(sharedWorkflowIds),
|
|
1508
|
+
},
|
|
1509
|
+
});
|
|
1510
|
+
if (!execution) {
|
|
1511
|
+
throw new _1.ResponseHelper.ResponseError('Execution not found', undefined, 404);
|
|
1512
|
+
}
|
|
1385
1513
|
if (config.get('executions.mode') === 'queue') {
|
|
1386
1514
|
const result = await this.activeExecutionsInstance.stopExecution(req.params.id);
|
|
1387
1515
|
if (result === undefined) {
|
|
@@ -1419,7 +1547,6 @@ class App {
|
|
|
1419
1547
|
};
|
|
1420
1548
|
return returnData;
|
|
1421
1549
|
}
|
|
1422
|
-
const executionId = req.params.id;
|
|
1423
1550
|
const result = await this.activeExecutionsInstance.stopExecution(executionId);
|
|
1424
1551
|
let returnData;
|
|
1425
1552
|
if (result === undefined) {
|
|
@@ -1451,19 +1578,8 @@ class App {
|
|
|
1451
1578
|
});
|
|
1452
1579
|
}));
|
|
1453
1580
|
this.app.get(`/${this.restEndpoint}/settings`, _1.ResponseHelper.send(async (req, res) => {
|
|
1454
|
-
return this.
|
|
1581
|
+
return this.getSettingsForFrontend();
|
|
1455
1582
|
}));
|
|
1456
|
-
this.app.post(`/${this.restEndpoint}/user-survey`, async (req, res) => {
|
|
1457
|
-
if (!this.frontendSettings.personalizationSurvey.shouldShow) {
|
|
1458
|
-
_1.ResponseHelper.sendErrorResponse(res, new _1.ResponseHelper.ResponseError('User survey already submitted', undefined, 400), false);
|
|
1459
|
-
}
|
|
1460
|
-
const answers = req.body;
|
|
1461
|
-
await PersonalizationSurvey.writeSurveyToDisk(answers);
|
|
1462
|
-
this.frontendSettings.personalizationSurvey.shouldShow = false;
|
|
1463
|
-
this.frontendSettings.personalizationSurvey.answers = answers;
|
|
1464
|
-
_1.ResponseHelper.sendSuccessResponse(res, undefined, true, 200);
|
|
1465
|
-
void InternalHooksManager_1.InternalHooksManager.getInstance().onPersonalizationSurveySubmitted(answers);
|
|
1466
|
-
});
|
|
1467
1583
|
if (config.get('endpoints.disableProductionWebhooksOnMainProcess') !== true) {
|
|
1468
1584
|
_1.WebhookServer.registerProductionWebhooks.apply(this);
|
|
1469
1585
|
}
|
|
@@ -1602,6 +1718,9 @@ async function start() {
|
|
|
1602
1718
|
},
|
|
1603
1719
|
deploymentType: config.get('deployment.type'),
|
|
1604
1720
|
binaryDataMode: binarDataConfig.mode,
|
|
1721
|
+
n8n_multi_user_allowed: config.get('userManagement.disabled') === false ||
|
|
1722
|
+
config.get('userManagement.isInstanceOwnerSetUp') === true,
|
|
1723
|
+
smtp_set_up: config.get('userManagement.emails.mode') === 'smtp',
|
|
1605
1724
|
};
|
|
1606
1725
|
void _1.Db.collections
|
|
1607
1726
|
.Workflow.findOne({
|
|
@@ -1618,25 +1737,33 @@ async function start() {
|
|
|
1618
1737
|
});
|
|
1619
1738
|
}
|
|
1620
1739
|
exports.start = start;
|
|
1621
|
-
async function getExecutionsCount(countFilter) {
|
|
1740
|
+
async function getExecutionsCount(countFilter, user) {
|
|
1622
1741
|
const dbType = (await _1.GenericHelpers.getConfigValue('database.type'));
|
|
1623
1742
|
const filteredFields = Object.keys(countFilter).filter((field) => field !== 'id');
|
|
1624
|
-
if (dbType !== 'postgresdb' || filteredFields.length > 0) {
|
|
1625
|
-
const
|
|
1626
|
-
|
|
1743
|
+
if (dbType !== 'postgresdb' || filteredFields.length > 0 || user.globalRole.name !== 'owner') {
|
|
1744
|
+
const sharedWorkflowIds = await WorkflowHelpers_1.getSharedWorkflowIds(user);
|
|
1745
|
+
const count = await _1.Db.collections.Execution.count({
|
|
1746
|
+
where: Object.assign({ workflowId: typeorm_1.In(sharedWorkflowIds) }, countFilter),
|
|
1747
|
+
});
|
|
1748
|
+
return { count, estimated: false };
|
|
1627
1749
|
}
|
|
1628
1750
|
try {
|
|
1629
1751
|
const estimateRowsNumberSql = "SELECT n_live_tup FROM pg_stat_all_tables WHERE relname = 'execution_entity';";
|
|
1630
1752
|
const rows = await _1.Db.collections.Execution.query(estimateRowsNumberSql);
|
|
1631
1753
|
const estimate = parseInt(rows[0].n_live_tup, 10);
|
|
1632
1754
|
if (estimate > 100000) {
|
|
1633
|
-
return { count: estimate,
|
|
1755
|
+
return { count: estimate, estimated: true };
|
|
1634
1756
|
}
|
|
1635
1757
|
}
|
|
1636
|
-
catch (
|
|
1637
|
-
n8n_workflow_1.LoggerProxy.warn(`
|
|
1758
|
+
catch (error) {
|
|
1759
|
+
n8n_workflow_1.LoggerProxy.warn(`Failed to get executions count from Postgres: ${error}`);
|
|
1638
1760
|
}
|
|
1639
|
-
const
|
|
1640
|
-
|
|
1761
|
+
const sharedWorkflowIds = await WorkflowHelpers_1.getSharedWorkflowIds(user);
|
|
1762
|
+
const count = await _1.Db.collections.Execution.count({
|
|
1763
|
+
where: {
|
|
1764
|
+
workflowId: typeorm_1.In(sharedWorkflowIds),
|
|
1765
|
+
},
|
|
1766
|
+
});
|
|
1767
|
+
return { count, estimated: false };
|
|
1641
1768
|
}
|
|
1642
1769
|
//# sourceMappingURL=Server.js.map
|