Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Runtime checks for credentials load and execute workflows #2697

Merged
merged 12 commits into from
Feb 26, 2022
3 changes: 3 additions & 0 deletions packages/cli/commands/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {

import { getLogger } from '../src/Logger';
import config = require('../config');
import { getInstanceOwner } from '../src/UserManagement/UserManagementHelper';

export class Execute extends Command {
static description = '\nExecutes a given workflow';
Expand Down Expand Up @@ -169,11 +170,13 @@ export class Execute extends Command {
}

try {
const user = await getInstanceOwner();
const runData: IWorkflowExecutionDataProcess = {
executionMode: 'cli',
startNodes: [startNode.name],
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
workflowData: workflowData!,
userId: user.id,
};

const workflowRunner = new WorkflowRunner();
Expand Down
7 changes: 7 additions & 0 deletions packages/cli/commands/executeBatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import {
WorkflowRunner,
} from '../src';
import config = require('../config');
import { User } from '../src/databases/entities/User';
import { getInstanceOwner } from '../src/UserManagement/UserManagementHelper';

export class ExecuteBatch extends Command {
static description = '\nExecutes multiple workflows once';
Expand All @@ -57,6 +59,8 @@ export class ExecuteBatch extends Command {

static executionTimeout = 3 * 60 * 1000;

static instanceOwner: User;

static examples = [
`$ n8n executeBatch`,
`$ n8n executeBatch --concurrency=10 --skipList=/data/skipList.txt`,
Expand Down Expand Up @@ -279,6 +283,8 @@ export class ExecuteBatch extends Command {
// Wait till the database is ready
await startDbInitPromise;

ExecuteBatch.instanceOwner = await getInstanceOwner();

let allWorkflows;

const query = Db.collections.Workflow!.createQueryBuilder('workflows');
Expand Down Expand Up @@ -666,6 +672,7 @@ export class ExecuteBatch extends Command {
executionMode: 'cli',
startNodes: [startNode!.name],
workflowData,
userId: ExecuteBatch.instanceOwner.id,
};

const workflowRunner = new WorkflowRunner();
Expand Down
9 changes: 9 additions & 0 deletions packages/cli/commands/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ import { getLogger } from '../src/Logger';

import * as config from '../config';
import * as Queue from '../src/Queue';
import {
checkPermissionsForExecution,
getWorkflowOwner,
} from '../src/UserManagement/UserManagementHelper';

export class Worker extends Command {
static description = '\nStarts a n8n worker';
Expand Down Expand Up @@ -121,6 +125,8 @@ export class Worker extends Command {
`Start job: ${job.id} (Workflow ID: ${currentExecutionDb.workflowData.id} | Execution: ${jobData.executionId})`,
);

const workflowOwner = await getWorkflowOwner(currentExecutionDb.workflowData.id!.toString());

let { staticData } = currentExecutionDb.workflowData;
if (jobData.loadStaticData) {
const findOptions = {
Expand Down Expand Up @@ -164,7 +170,10 @@ export class Worker extends Command {
settings: currentExecutionDb.workflowData.settings,
});

await checkPermissionsForExecution(workflow, workflowOwner.id);

const additionalData = await WorkflowExecuteAdditionalData.getBase(
workflowOwner.id,
undefined,
executionTimeoutTimestamp,
);
Expand Down
28 changes: 21 additions & 7 deletions packages/cli/src/ActiveWorkflowRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ export class ActiveWorkflowRunner {
// Here I guess we can have a flag on the workflow table like hasTrigger
// so intead of pulling all the active wehhooks just pull the actives that have a trigger
const workflowsData: IWorkflowDb[] = (await Db.collections.Workflow!.find({
active: true,
where: { active: true },
relations: ['shared', 'shared.user', 'shared.user.globalRole'],
})) as IWorkflowDb[];
krynble marked this conversation as resolved.
Show resolved Hide resolved

if (!config.get('endpoints.skipWebhoooksDeregistrationOnShutdown')) {
Expand Down Expand Up @@ -255,7 +256,9 @@ export class ActiveWorkflowRunner {
});
}

const workflowData = await Db.collections.Workflow!.findOne(webhook.workflowId);
const workflowData = await Db.collections.Workflow!.findOne(webhook.workflowId, {
relations: ['shared', 'shared.user', 'shared.user.globalRole'],
});
if (workflowData === undefined) {
throw new ResponseHelper.ResponseError(
`Could not find workflow with id "${webhook.workflowId}"`,
Expand All @@ -276,7 +279,9 @@ export class ActiveWorkflowRunner {
settings: workflowData.settings,
});

const additionalData = await WorkflowExecuteAdditionalData.getBase();
const additionalData = await WorkflowExecuteAdditionalData.getBase(
workflowData.shared[0].user.id,
);

const webhookData = NodeHelpers.getNodeWebhooks(
workflow,
Expand Down Expand Up @@ -520,7 +525,9 @@ export class ActiveWorkflowRunner {
* @memberof ActiveWorkflowRunner
*/
async removeWorkflowWebhooks(workflowId: string): Promise<void> {
const workflowData = await Db.collections.Workflow!.findOne(workflowId);
const workflowData = await Db.collections.Workflow!.findOne(workflowId, {
relations: ['shared', 'shared.user', 'shared.user.globalRole'],
});
if (workflowData === undefined) {
throw new Error(`Could not find workflow with id "${workflowId}"`);
}
Expand All @@ -539,7 +546,9 @@ export class ActiveWorkflowRunner {

const mode = 'internal';

const additionalData = await WorkflowExecuteAdditionalData.getBase();
const additionalData = await WorkflowExecuteAdditionalData.getBase(
workflowData.shared[0].user.id,
);

const webhooks = WebhookHelpers.getWorkflowWebhooks(workflow, additionalData, undefined, true);

Expand Down Expand Up @@ -606,6 +615,7 @@ export class ActiveWorkflowRunner {

// Start the workflow
const runData: IWorkflowExecutionDataProcess = {
userId: additionalData.userId,
executionMode: mode,
executionData,
workflowData,
Expand Down Expand Up @@ -709,7 +719,9 @@ export class ActiveWorkflowRunner {
let workflowInstance: Workflow;
try {
if (workflowData === undefined) {
workflowData = (await Db.collections.Workflow!.findOne(workflowId)) as IWorkflowDb;
workflowData = (await Db.collections.Workflow!.findOne(workflowId, {
relations: ['shared', 'shared.user', 'shared.user.globalRole'],
})) as IWorkflowDb;
}

if (!workflowData) {
Expand Down Expand Up @@ -738,7 +750,9 @@ export class ActiveWorkflowRunner {
}

const mode = 'trigger';
const additionalData = await WorkflowExecuteAdditionalData.getBase();
const additionalData = await WorkflowExecuteAdditionalData.getBase(
(workflowData as WorkflowEntity).shared[0].user.id,
);
const getTriggerFunctions = this.getExecuteTriggerFunctions(
workflowData,
additionalData,
Expand Down
17 changes: 5 additions & 12 deletions packages/cli/src/CredentialsHelper.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
/* eslint-disable no-restricted-syntax */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
Expand Down Expand Up @@ -226,20 +227,12 @@ export class CredentialsHelper extends ICredentialsHelper {
async getCredentials(
nodeCredentials: INodeCredentialsDetails,
type: string,
userId?: string,
): Promise<Credentials> {
if (!nodeCredentials.id) {
throw new Error(`Credentials "${nodeCredentials.name}" for type "${type}" don't have an ID.`);
}

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const qb = Db.collections.Credentials!.createQueryBuilder('c');
qb.where('c.id = :id and c.type = :type', { id: nodeCredentials.id, type });
if (userId) {
// TODO UM: implement this.
// qb.
}
const credentials = await qb.getOne();
const credentials = await Db.collections.Credentials!.findOne(nodeCredentials.id);

if (!credentials) {
throw new Error(
Expand Down Expand Up @@ -300,9 +293,8 @@ export class CredentialsHelper extends ICredentialsHelper {
mode: WorkflowExecuteMode,
raw?: boolean,
expressionResolveValues?: ICredentialsExpressionResolveValues,
userId?: string,
): Promise<ICredentialDataDecryptedObject> {
const credentials = await this.getCredentials(nodeCredentials, type, userId);
const credentials = await this.getCredentials(nodeCredentials, type);
const decryptedDataOriginal = credentials.getData(this.encryptionKey);

if (raw === true) {
Expand Down Expand Up @@ -506,6 +498,7 @@ export class CredentialsHelper extends ICredentialsHelper {
}

async testCredentials(
user: User,
credentialType: string,
credentialsDecrypted: ICredentialsDecrypted,
nodeToTestWith?: string,
Expand Down Expand Up @@ -604,7 +597,7 @@ export class CredentialsHelper extends ICredentialsHelper {
},
};

const additionalData = await WorkflowExecuteAdditionalData.getBase(node.parameters);
const additionalData = await WorkflowExecuteAdditionalData.getBase(user.id, node.parameters);

const routingNode = new RoutingNode(
workflow,
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/src/Interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -579,14 +579,15 @@ export interface IWorkflowExecutionDataProcess {
sessionId?: string;
startNodes?: string[];
workflowData: IWorkflowBase;
userId?: string;
userId: string;
}

export interface IWorkflowExecutionDataProcessWithExecution extends IWorkflowExecutionDataProcess {
credentialsOverwrite: ICredentialsOverwrite;
credentialsTypeData: ICredentialsTypeData;
executionId: string;
nodeTypeData: ITransferNodeTypes;
userId: string;
}

export interface IWorkflowExecuteProcess {
Expand Down
Loading