This commit is contained in:
Rupenieks 2020-06-23 17:22:22 +02:00
commit b61808c1df

View file

@ -113,6 +113,7 @@ class App {
activeExecutionsInstance: ActiveExecutions.ActiveExecutions; activeExecutionsInstance: ActiveExecutions.ActiveExecutions;
push: Push.Push; push: Push.Push;
versions: IPackageVersions | undefined; versions: IPackageVersions | undefined;
restEndpoint: string;
protocol: string; protocol: string;
sslKey: string; sslKey: string;
@ -127,6 +128,7 @@ class App {
this.saveDataSuccessExecution = config.get('executions.saveDataOnSuccess') as string; this.saveDataSuccessExecution = config.get('executions.saveDataOnSuccess') as string;
this.saveManualExecutions = config.get('executions.saveDataManualExecutions') as boolean; this.saveManualExecutions = config.get('executions.saveDataManualExecutions') as boolean;
this.timezone = config.get('generic.timezone') as string; this.timezone = config.get('generic.timezone') as string;
this.restEndpoint = config.get('endpoints.rest') as string;
this.activeWorkflowRunner = ActiveWorkflowRunner.getInstance(); this.activeWorkflowRunner = ActiveWorkflowRunner.getInstance();
this.testWebhooks = TestWebhooks.getInstance(); this.testWebhooks = TestWebhooks.getInstance();
@ -235,7 +237,7 @@ class App {
// Get push connections // Get push connections
this.app.use((req: express.Request, res: express.Response, next: express.NextFunction) => { this.app.use((req: express.Request, res: express.Response, next: express.NextFunction) => {
if (req.url.indexOf('/rest/push') === 0) { if (req.url.indexOf(`/${this.restEndpoint}/push`) === 0) {
// TODO: Later also has to add some kind of authentication token // TODO: Later also has to add some kind of authentication token
if (req.query.sessionId === undefined) { if (req.query.sessionId === undefined) {
next(new Error('The query parameter "sessionId" is missing!')); next(new Error('The query parameter "sessionId" is missing!'));
@ -284,7 +286,7 @@ class App {
this.app.use(history({ this.app.use(history({
rewrites: [ rewrites: [
{ {
from: new RegExp(`^\/(rest|healthz|css|js|${this.endpointWebhook}|${this.endpointWebhookTest})\/?.*$`), from: new RegExp(`^\/(${this.restEndpoint}|healthz|css|js|${this.endpointWebhook}|${this.endpointWebhookTest})\/?.*$`),
to: (context) => { to: (context) => {
return context.parsedUrl!.pathname!.toString(); return context.parsedUrl!.pathname!.toString();
} }
@ -354,7 +356,7 @@ class App {
// Creates a new workflow // Creates a new workflow
this.app.post('/rest/workflows', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IWorkflowResponse> => { this.app.post(`/${this.restEndpoint}/workflows`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IWorkflowResponse> => {
const newWorkflowData = req.body as IWorkflowBase; const newWorkflowData = req.body as IWorkflowBase;
@ -377,7 +379,7 @@ class App {
// Reads and returns workflow data from an URL // Reads and returns workflow data from an URL
this.app.get('/rest/workflows/from-url', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IWorkflowResponse> => { this.app.get(`/${this.restEndpoint}/workflows/from-url`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IWorkflowResponse> => {
if (req.query.url === undefined) { if (req.query.url === undefined) {
throw new ResponseHelper.ResponseError(`The parameter "url" is missing!`, undefined, 400); throw new ResponseHelper.ResponseError(`The parameter "url" is missing!`, undefined, 400);
} }
@ -405,7 +407,7 @@ class App {
// Returns workflows // Returns workflows
this.app.get('/rest/workflows', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IWorkflowShortResponse[]> => { this.app.get(`/${this.restEndpoint}/workflows`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IWorkflowShortResponse[]> => {
const findQuery = {} as FindManyOptions; const findQuery = {} as FindManyOptions;
if (req.query.filter) { if (req.query.filter) {
findQuery.where = JSON.parse(req.query.filter as string); findQuery.where = JSON.parse(req.query.filter as string);
@ -425,7 +427,7 @@ class App {
// Returns a specific workflow // Returns a specific workflow
this.app.get('/rest/workflows/:id', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IWorkflowResponse | undefined> => { this.app.get(`/${this.restEndpoint}/workflows/:id`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IWorkflowResponse | undefined> => {
const result = await Db.collections.Workflow!.findOne(req.params.id); const result = await Db.collections.Workflow!.findOne(req.params.id);
if (result === undefined) { if (result === undefined) {
@ -439,7 +441,7 @@ class App {
// Updates an existing workflow // Updates an existing workflow
this.app.patch('/rest/workflows/:id', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IWorkflowResponse> => { this.app.patch(`/${this.restEndpoint}/workflows/:id`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IWorkflowResponse> => {
const newWorkflowData = req.body as IWorkflowBase; const newWorkflowData = req.body as IWorkflowBase;
const id = req.params.id; const id = req.params.id;
@ -510,7 +512,7 @@ class App {
// Deletes a specific workflow // Deletes a specific workflow
this.app.delete('/rest/workflows/:id', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<boolean> => { this.app.delete(`/${this.restEndpoint}/workflows/:id`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<boolean> => {
const id = req.params.id; const id = req.params.id;
await this.externalHooks.run('workflow.delete', [id]); await this.externalHooks.run('workflow.delete', [id]);
@ -526,7 +528,7 @@ class App {
})); }));
this.app.post('/rest/workflows/run', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IExecutionPushResponse> => { this.app.post(`/${this.restEndpoint}/workflows/run`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IExecutionPushResponse> => {
const workflowData = req.body.workflowData; const workflowData = req.body.workflowData;
const runData: IRunData | undefined = req.body.runData; const runData: IRunData | undefined = req.body.runData;
const startNodes: string[] | undefined = req.body.startNodes; const startNodes: string[] | undefined = req.body.startNodes;
@ -575,7 +577,7 @@ class App {
// Returns parameter values which normally get loaded from an external API or // Returns parameter values which normally get loaded from an external API or
// get generated dynamically // get generated dynamically
this.app.get('/rest/node-parameter-options', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<INodePropertyOptions[]> => { this.app.get(`/${this.restEndpoint}/node-parameter-options`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<INodePropertyOptions[]> => {
const nodeType = req.query.nodeType as string; const nodeType = req.query.nodeType as string;
let credentials: INodeCredentials | undefined = undefined; let credentials: INodeCredentials | undefined = undefined;
const currentNodeParameters = JSON.parse('' + req.query.currentNodeParameters) as INodeParameters; const currentNodeParameters = JSON.parse('' + req.query.currentNodeParameters) as INodeParameters;
@ -597,7 +599,7 @@ class App {
// Returns all the node-types // Returns all the node-types
this.app.get('/rest/node-types', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<INodeTypeDescription[]> => { this.app.get(`/${this.restEndpoint}/node-types`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<INodeTypeDescription[]> => {
const returnData: INodeTypeDescription[] = []; const returnData: INodeTypeDescription[] = [];
@ -620,7 +622,7 @@ class App {
// Returns the node icon // Returns the node icon
this.app.get(['/rest/node-icon/:nodeType', '/rest/node-icon/:scope/:nodeType'], async (req: express.Request, res: express.Response): Promise<void> => { this.app.get([`/${this.restEndpoint}/node-icon/:nodeType`, `/${this.restEndpoint}/node-icon/:scope/:nodeType`], async (req: express.Request, res: express.Response): Promise<void> => {
const nodeTypeName = `${req.params.scope ? `${req.params.scope}/` : ''}${req.params.nodeType}`; const nodeTypeName = `${req.params.scope ? `${req.params.scope}/` : ''}${req.params.nodeType}`;
const nodeTypes = NodeTypes(); const nodeTypes = NodeTypes();
@ -654,13 +656,13 @@ class App {
// Returns the active workflow ids // Returns the active workflow ids
this.app.get('/rest/active', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<string[]> => { this.app.get(`/${this.restEndpoint}/active`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<string[]> => {
return this.activeWorkflowRunner.getActiveWorkflows(); return this.activeWorkflowRunner.getActiveWorkflows();
})); }));
// Returns if the workflow with the given id had any activation errors // Returns if the workflow with the given id had any activation errors
this.app.get('/rest/active/error/:id', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IActivationError | undefined> => { this.app.get(`/${this.restEndpoint}/active/error/:id`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IActivationError | undefined> => {
const id = req.params.id; const id = req.params.id;
return this.activeWorkflowRunner.getActivationError(id); return this.activeWorkflowRunner.getActivationError(id);
})); }));
@ -673,7 +675,7 @@ class App {
// Deletes a specific credential // Deletes a specific credential
this.app.delete('/rest/credentials/:id', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<boolean> => { this.app.delete(`/${this.restEndpoint}/credentials/:id`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<boolean> => {
const id = req.params.id; const id = req.params.id;
await this.externalHooks.run('credentials.delete', [id]); await this.externalHooks.run('credentials.delete', [id]);
@ -684,7 +686,7 @@ class App {
})); }));
// Creates new credentials // Creates new credentials
this.app.post('/rest/credentials', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<ICredentialsResponse> => { this.app.post(`/${this.restEndpoint}/credentials`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<ICredentialsResponse> => {
const incomingData = req.body; const incomingData = req.body;
if (!incomingData.name || incomingData.name.length < 3) { if (!incomingData.name || incomingData.name.length < 3) {
@ -742,7 +744,7 @@ class App {
// Updates existing credentials // Updates existing credentials
this.app.patch('/rest/credentials/:id', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<ICredentialsResponse> => { this.app.patch(`/${this.restEndpoint}/credentials/:id`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<ICredentialsResponse> => {
const incomingData = req.body; const incomingData = req.body;
const id = req.params.id; const id = req.params.id;
@ -823,7 +825,7 @@ class App {
// Returns specific credentials // Returns specific credentials
this.app.get('/rest/credentials/:id', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<ICredentialsDecryptedResponse | ICredentialsResponse | undefined> => { this.app.get(`/${this.restEndpoint}/credentials/:id`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<ICredentialsDecryptedResponse | ICredentialsResponse | undefined> => {
const findQuery = {} as FindManyOptions; const findQuery = {} as FindManyOptions;
// Make sure the variable has an expected value // Make sure the variable has an expected value
@ -858,7 +860,7 @@ class App {
// Returns all the saved credentials // Returns all the saved credentials
this.app.get('/rest/credentials', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<ICredentialsResponse[]> => { this.app.get(`/${this.restEndpoint}/credentials`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<ICredentialsResponse[]> => {
const findQuery = {} as FindManyOptions; const findQuery = {} as FindManyOptions;
if (req.query.filter) { if (req.query.filter) {
findQuery.where = JSON.parse(req.query.filter as string); findQuery.where = JSON.parse(req.query.filter as string);
@ -900,7 +902,7 @@ class App {
// Returns all the credential types which are defined in the loaded n8n-modules // Returns all the credential types which are defined in the loaded n8n-modules
this.app.get('/rest/credential-types', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<ICredentialType[]> => { this.app.get(`/${this.restEndpoint}/credential-types`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<ICredentialType[]> => {
const returnData: ICredentialType[] = []; const returnData: ICredentialType[] = [];
@ -918,7 +920,7 @@ class App {
// ---------------------------------------- // ----------------------------------------
// Authorize OAuth Data // Authorize OAuth Data
this.app.get('/rest/oauth1-credential/auth', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<string> => { this.app.get(`/${this.restEndpoint}/oauth1-credential/auth`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<string> => {
if (req.query.id === undefined) { if (req.query.id === undefined) {
throw new Error('Required credential id is missing!'); throw new Error('Required credential id is missing!');
} }
@ -961,7 +963,7 @@ class App {
}, },
}); });
const callback = `${WebhookHelpers.getWebhookBaseUrl()}rest/oauth1-credential/callback?cid=${req.query.id}`; const callback = `${WebhookHelpers.getWebhookBaseUrl()}${this.restEndpoint}/oauth1-credential/callback?cid=${req.query.id}`;
const options: RequestOptions = { const options: RequestOptions = {
method: 'POST', method: 'POST',
@ -1000,7 +1002,7 @@ class App {
})); }));
// Verify and store app code. Generate access tokens and store for respective credential. // Verify and store app code. Generate access tokens and store for respective credential.
this.app.get('/rest/oauth1-credential/callback', async (req: express.Request, res: express.Response) => { this.app.get(`/${this.restEndpoint}/oauth1-credential/callback`, async (req: express.Request, res: express.Response) => {
const { oauth_verifier, oauth_token, cid } = req.query; const { oauth_verifier, oauth_token, cid } = req.query;
if (oauth_verifier === undefined || oauth_token === undefined) { if (oauth_verifier === undefined || oauth_token === undefined) {
@ -1072,7 +1074,7 @@ class App {
// Authorize OAuth Data // Authorize OAuth Data
this.app.get('/rest/oauth2-credential/auth', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<string> => { this.app.get(`/${this.restEndpoint}/oauth2-credential/auth`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<string> => {
if (req.query.id === undefined) { if (req.query.id === undefined) {
throw new Error('Required credential id is missing!'); throw new Error('Required credential id is missing!');
} }
@ -1113,7 +1115,7 @@ class App {
clientSecret: _.get(oauthCredentials, 'clientSecret', '') as string, clientSecret: _.get(oauthCredentials, 'clientSecret', '') as string,
accessTokenUri: _.get(oauthCredentials, 'accessTokenUrl', '') as string, accessTokenUri: _.get(oauthCredentials, 'accessTokenUrl', '') as string,
authorizationUri: _.get(oauthCredentials, 'authUrl', '') as string, authorizationUri: _.get(oauthCredentials, 'authUrl', '') as string,
redirectUri: `${WebhookHelpers.getWebhookBaseUrl()}rest/oauth2-credential/callback`, redirectUri: `${WebhookHelpers.getWebhookBaseUrl()}${this.restEndpoint}/oauth2-credential/callback`,
scopes: _.split(_.get(oauthCredentials, 'scope', 'openid,') as string, ','), scopes: _.split(_.get(oauthCredentials, 'scope', 'openid,') as string, ','),
state: stateEncodedStr, state: stateEncodedStr,
}); });
@ -1146,7 +1148,7 @@ class App {
// ---------------------------------------- // ----------------------------------------
// Verify and store app code. Generate access tokens and store for respective credential. // Verify and store app code. Generate access tokens and store for respective credential.
this.app.get('/rest/oauth2-credential/callback', async (req: express.Request, res: express.Response) => { this.app.get(`/${this.restEndpoint}/oauth2-credential/callback`, async (req: express.Request, res: express.Response) => {
const {code, state: stateEncoded } = req.query; const {code, state: stateEncoded } = req.query;
if (code === undefined || stateEncoded === undefined) { if (code === undefined || stateEncoded === undefined) {
@ -1206,7 +1208,7 @@ class App {
clientSecret: _.get(oauthCredentials, 'clientSecret', '') as string, clientSecret: _.get(oauthCredentials, 'clientSecret', '') as string,
accessTokenUri: _.get(oauthCredentials, 'accessTokenUrl', '') as string, accessTokenUri: _.get(oauthCredentials, 'accessTokenUrl', '') as string,
authorizationUri: _.get(oauthCredentials, 'authUrl', '') as string, authorizationUri: _.get(oauthCredentials, 'authUrl', '') as string,
redirectUri: `${WebhookHelpers.getWebhookBaseUrl()}rest/oauth2-credential/callback`, redirectUri: `${WebhookHelpers.getWebhookBaseUrl()}${this.restEndpoint}/oauth2-credential/callback`,
scopes: _.split(_.get(oauthCredentials, 'scope', 'openid,') as string, ',') scopes: _.split(_.get(oauthCredentials, 'scope', 'openid,') as string, ',')
}); });
@ -1246,7 +1248,7 @@ class App {
// Returns all finished executions // Returns all finished executions
this.app.get('/rest/executions', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IExecutionsListResponse> => { this.app.get(`/${this.restEndpoint}/executions`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IExecutionsListResponse> => {
let filter: any = {}; // tslint:disable-line:no-any let filter: any = {}; // tslint:disable-line:no-any
if (req.query.filter) { if (req.query.filter) {
@ -1311,7 +1313,7 @@ class App {
// Returns a specific execution // Returns a specific execution
this.app.get('/rest/executions/:id', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IExecutionFlattedResponse | undefined> => { this.app.get(`/${this.restEndpoint}/executions/:id`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IExecutionFlattedResponse | undefined> => {
const result = await Db.collections.Execution!.findOne(req.params.id); const result = await Db.collections.Execution!.findOne(req.params.id);
if (result === undefined) { if (result === undefined) {
@ -1325,7 +1327,7 @@ class App {
// Retries a failed execution // Retries a failed execution
this.app.post('/rest/executions/:id/retry', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<boolean> => { this.app.post(`/${this.restEndpoint}/executions/:id/retry`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<boolean> => {
// Get the data to execute // Get the data to execute
const fullExecutionDataFlatted = await Db.collections.Execution!.findOne(req.params.id); const fullExecutionDataFlatted = await Db.collections.Execution!.findOne(req.params.id);
@ -1399,7 +1401,7 @@ class App {
// Delete Executions // Delete Executions
// INFORMATION: We use POST instead of DELETE to not run into any issues // INFORMATION: We use POST instead of DELETE to not run into any issues
// with the query data getting to long // with the query data getting to long
this.app.post('/rest/executions/delete', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<void> => { this.app.post(`/${this.restEndpoint}/executions/delete`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<void> => {
const deleteData = req.body as IExecutionDeleteFilter; const deleteData = req.body as IExecutionDeleteFilter;
if (deleteData.deleteBefore !== undefined) { if (deleteData.deleteBefore !== undefined) {
@ -1426,7 +1428,7 @@ class App {
// Returns all the currently working executions // Returns all the currently working executions
this.app.get('/rest/executions-current', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IExecutionsSummary[]> => { this.app.get(`/${this.restEndpoint}/executions-current`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IExecutionsSummary[]> => {
const executingWorkflows = this.activeExecutionsInstance.getActiveExecutions(); const executingWorkflows = this.activeExecutionsInstance.getActiveExecutions();
const returnData: IExecutionsSummary[] = []; const returnData: IExecutionsSummary[] = [];
@ -1455,7 +1457,7 @@ class App {
})); }));
// Forces the execution to stop // Forces the execution to stop
this.app.post('/rest/executions-current/:id/stop', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IExecutionsStopData> => { this.app.post(`/${this.restEndpoint}/executions-current/:id/stop`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IExecutionsStopData> => {
const executionId = req.params.id; const executionId = req.params.id;
// Stopt he execution and wait till it is done and we got the data // Stopt he execution and wait till it is done and we got the data
@ -1477,7 +1479,7 @@ class App {
// Removes a test webhook // Removes a test webhook
this.app.delete('/rest/test-webhook/:id', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<boolean> => { this.app.delete(`/${this.restEndpoint}/test-webhook/:id`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<boolean> => {
const workflowId = req.params.id; const workflowId = req.params.id;
return this.testWebhooks.cancelTestWebhook(workflowId); return this.testWebhooks.cancelTestWebhook(workflowId);
})); }));
@ -1489,7 +1491,7 @@ class App {
// ---------------------------------------- // ----------------------------------------
// Returns all the available timezones // Returns all the available timezones
this.app.get('/rest/options/timezones', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<object> => { this.app.get(`/${this.restEndpoint}/options/timezones`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<object> => {
return timezones; return timezones;
})); }));
@ -1502,7 +1504,7 @@ class App {
// Returns the settings which are needed in the UI // Returns the settings which are needed in the UI
this.app.get('/rest/settings', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IN8nUISettings> => { this.app.get(`/${this.restEndpoint}/settings`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IN8nUISettings> => {
return { return {
endpointWebhook: this.endpointWebhook, endpointWebhook: this.endpointWebhook,
endpointWebhookTest: this.endpointWebhookTest, endpointWebhookTest: this.endpointWebhookTest,