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

✨ User management backend #2636

Merged
merged 782 commits into from
Mar 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
782 commits
Select commit Hold shift + click to select a range
9ab9c10
✅ adjust tests
BHesseldieck Feb 10, 2022
9a970c9
🛠 refactor user invites to be indempotent (#2791)
BHesseldieck Feb 11, 2022
e57368f
🔐 Encrypt SMTP pass for user management backend (#2793)
ivov Feb 11, 2022
20a0885
👰 n8n 2826 um wedding FE<>BE (#2789)
mutdmour Feb 14, 2022
0592a0f
update telemetry
mutdmour Feb 14, 2022
d3b3777
🐛 preload role for users
BHesseldieck Feb 14, 2022
c4344cf
:bug: remove auth for password reset routes
BHesseldieck Feb 14, 2022
b798966
🐛 fix forgot-password flow
BHesseldieck Feb 14, 2022
41116a2
:zap: allow workflow tag disabling
BHesseldieck Feb 14, 2022
06a49b8
update telemetry init
mutdmour Feb 15, 2022
6e315e0
add reset
mutdmour Feb 15, 2022
1e168e9
clear error notifications on signin
mutdmour Feb 15, 2022
6dd114e
remove load settings from node view
mutdmour Feb 15, 2022
2ed15e1
remove user id from user state
mutdmour Feb 15, 2022
84dc274
inherit existing user props
mutdmour Feb 15, 2022
5e36cd0
go back in history on button click
mutdmour Feb 15, 2022
a394048
use replace to force redirect
mutdmour Feb 15, 2022
b3a7c17
update stories
mutdmour Feb 15, 2022
d13fbc2
Merge branch 'user-management-backend' of github.com:n8n-io/n8n into …
mutdmour Feb 15, 2022
b7b3324
:zap: add env check for tag create
BHesseldieck Feb 15, 2022
a205727
:test_tube: Add `/users` tests for user management backend (#2790)
ivov Feb 15, 2022
af52a75
:test_tube: Add password reset flow tests for user management backend…
ivov Feb 15, 2022
4545296
:bug: return 200 for non-existing user
BHesseldieck Feb 16, 2022
2669ccd
Merge branch 'user-management-backend' of https://github.com/n8n-io/n…
BHesseldieck Feb 16, 2022
d87d48a
✅ fix tests for forgot-password and user creation
BHesseldieck Feb 16, 2022
56f5519
Update packages/editor-ui/src/components/MainSidebar.vue
mutdmour Feb 16, 2022
3c24d91
Update packages/editor-ui/src/components/Telemetry.vue
mutdmour Feb 16, 2022
f4ad3c9
Update packages/editor-ui/src/plugins/telemetry/index.ts
mutdmour Feb 16, 2022
9645ce5
Update packages/editor-ui/src/plugins/telemetry/index.ts
mutdmour Feb 16, 2022
0e85fa2
Update packages/editor-ui/src/plugins/telemetry/index.ts
mutdmour Feb 16, 2022
b4be87b
Merge pull request #2820 from n8n-io/n8n-2824-telemetry-fe-um
mutdmour Feb 16, 2022
a691d24
:truck: Fix imports
ivov Feb 16, 2022
6f255a3
:zap: reset password just if password exists
BHesseldieck Feb 17, 2022
4c544c0
🔀 Merge branch 'master' into user-management-backend
BHesseldieck Feb 17, 2022
8c1ff6d
Fix validation at `PATCH /workfows/:id` (#2819)
ivov Feb 17, 2022
d2ebc41
Merge pull request #2824 from n8n-io/um-fe-issues
mutdmour Feb 18, 2022
f5a9185
🔨 refactor response from user creation
BHesseldieck Feb 18, 2022
8082827
🐛 um email invite fix (#2833)
mutdmour Feb 18, 2022
2c8ea63
🐘 database migrations UM + password reset expiration (#2710)
krynble Feb 20, 2022
6e95735
🔀 Merge branch 'master' into user-management-backend
BHesseldieck Feb 21, 2022
76c3ee3
:zap: treat skipped personalizationSurvey as not answered
BHesseldieck Feb 21, 2022
8b8e99b
:bug: removing active workflows when deleting user, :bug: fix reinvit…
BHesseldieck Feb 21, 2022
5ea87a3
✅ Add DB state check tests (#2841)
ivov Feb 21, 2022
533759d
Add logging to user management endpoints v2 (#2836)
ivov Feb 22, 2022
a5fc507
:bug: Fix ID overridden in range query
ivov Feb 22, 2022
b4b0904
:hammer: small refactoring
BHesseldieck Feb 22, 2022
bc88e7b
🔐 add auth to push-connection
BHesseldieck Feb 22, 2022
4f5b0c6
🛠 ✅ Create credentials namespace and add tests (#2831)
ivov Feb 23, 2022
e878adf
:bug: no auth for .svg
BHesseldieck Feb 23, 2022
e6a07a5
🛠 move auth cookie name to constant; 🐛 fix auth for push-connection
BHesseldieck Feb 24, 2022
f1a5523
✅ Add auth middleware tests (#2853)
ivov Feb 25, 2022
9705165
🔥 Remove test description wrappers (#2874)
ivov Feb 25, 2022
3748fa1
✨ Runtime checks for credentials load and execute workflows (#2697)
krynble Feb 26, 2022
2b84c3e
:zap: remove personalizationAnswers when fetching all users
BHesseldieck Feb 26, 2022
b895992
✅ fix failing get all users test
BHesseldieck Feb 26, 2022
0a1d030
✅ check authorization routes also for authentication
BHesseldieck Feb 27, 2022
a967aec
🔀 Merge branch 'master' into user-management-backend
BHesseldieck Feb 28, 2022
110f249
:bug: fix defaults in reset command
BHesseldieck Feb 28, 2022
2dbf7bb
🛠 refactorings from walkthrough (#2856)
ivov Feb 28, 2022
6c8f776
🛠 set up credentials router (#2882)
ivov Feb 28, 2022
10f6c1f
:bug: remove GET /login from auth
BHesseldieck Feb 28, 2022
dbd5e0e
🔀 merge master + FE update (#2905)
mutdmour Mar 1, 2022
b39af7e
fix conflict
mutdmour Mar 1, 2022
d11b179
:zap: n8n 2952 personalisation (#2911)
mutdmour Mar 1, 2022
a1e7bcc
✨ add current pw check for change password (#2912)
mutdmour Mar 1, 2022
7c017e8
merge in main branch
mutdmour Mar 2, 2022
518623f
update package.json
mutdmour Mar 2, 2022
75eac31
delete mock file
mutdmour Mar 2, 2022
e5265c2
delete mock file
mutdmour Mar 2, 2022
8fac07c
get settings func
mutdmour Mar 2, 2022
145b6ad
update router
mutdmour Mar 2, 2022
a4056ff
update package lock
mutdmour Mar 2, 2022
028d51b
update package lock
mutdmour Mar 2, 2022
43d108b
Fix invite text
mutdmour Mar 2, 2022
0169a1f
update error i18n
mutdmour Mar 2, 2022
cb81be3
open personalization on search if not set
mutdmour Mar 2, 2022
fd8f35e
update error view i18n
mutdmour Mar 2, 2022
a983bb0
update change password
mutdmour Mar 2, 2022
c72e796
update settings sidebar
mutdmour Mar 2, 2022
eb1def9
remove import
mutdmour Mar 2, 2022
3ab6b0b
fix sidebar
mutdmour Mar 2, 2022
8fc2325
:goal_net: fix error for credential/workflow not found
BHesseldieck Mar 2, 2022
b514a0a
update invite modal
mutdmour Mar 2, 2022
d8e453f
✨ persist skipping owner setup (#2894)
BHesseldieck Mar 2, 2022
5501fbf
update delete modal
mutdmour Mar 2, 2022
10ba3a6
change password modal
mutdmour Mar 2, 2022
08ea4eb
remove _label
mutdmour Mar 2, 2022
777b53e
sort keys
mutdmour Mar 2, 2022
3420287
remove key
mutdmour Mar 2, 2022
0e60143
update key names
mutdmour Mar 2, 2022
050edeb
fix test endpoint
mutdmour Mar 2, 2022
2021ba4
merge main branch
mutdmour Mar 2, 2022
e6d0374
🥅 Handle error workflows permissions (#2908)
krynble Mar 2, 2022
75e9933
fix ts issue
mutdmour Mar 2, 2022
386b9f1
fix list after ispending changes
mutdmour Mar 2, 2022
df848aa
fix error page bugs
mutdmour Mar 2, 2022
34b59c5
fix error redirect
mutdmour Mar 2, 2022
4f20383
fix notification
mutdmour Mar 2, 2022
f9a988e
:bug: fix survey import in migration
BHesseldieck Mar 2, 2022
a95961a
🔀 Merge branch 'master' into user-management-backend
BHesseldieck Mar 2, 2022
a64fd56
fix up spacing
mutdmour Mar 2, 2022
7b5cccc
update keys spacing
mutdmour Mar 2, 2022
a6a16da
update keys
mutdmour Mar 2, 2022
8a6c312
add space
mutdmour Mar 2, 2022
6e8f180
update key
mutdmour Mar 2, 2022
738d73d
fix up more spacing
mutdmour Mar 2, 2022
f14d4da
merge in main branch
mutdmour Mar 2, 2022
2498cba
Merge pull request #2914 from n8n-io/n8n-2823-um-i18n-1
mutdmour Mar 2, 2022
ef53bcc
🔐 add current password (#2919)
mutdmour Mar 2, 2022
8e27254
:bug: stringify tag ids
BHesseldieck Mar 2, 2022
c4611f1
🔐 check current password before update
BHesseldieck Mar 2, 2022
5b50548
add package lock
mutdmour Mar 3, 2022
1af50a0
fix dep version
mutdmour Mar 3, 2022
30abe3b
update version
mutdmour Mar 3, 2022
a62c2d4
🐛 fix access for instance owner to credentials (#2927)
krynble Mar 3, 2022
1181f2b
🛠 stringify tag id on entity
BHesseldieck Mar 3, 2022
422a567
🔐 Update password requirements (#2920)
ivov Mar 3, 2022
e2dbb4f
✅ fix tests for currentPassword check
BHesseldieck Mar 3, 2022
e074dee
change redirection, add homepage
mutdmour Mar 4, 2022
6589d19
fix error view redirection
mutdmour Mar 4, 2022
945e452
updated wording
mutdmour Mar 4, 2022
228dd5b
fix setup redirection
mutdmour Mar 4, 2022
4d72dbf
update validator
mutdmour Mar 4, 2022
65a4c3d
remove successfully
mutdmour Mar 4, 2022
6c2de07
update consumers
mutdmour Mar 4, 2022
f1142fe
update settings redirect
mutdmour Mar 4, 2022
3b4334f
on signup, redirect to homepage
mutdmour Mar 4, 2022
eea2777
update empty state
mutdmour Mar 4, 2022
891cb07
add space to emails
mutdmour Mar 4, 2022
68c2f01
remove brackets
mutdmour Mar 4, 2022
30164e4
add opacity
mutdmour Mar 4, 2022
42ed627
update spacing
mutdmour Mar 4, 2022
2700402
remove border from last user
mutdmour Mar 4, 2022
e70923e
personal details updated
mutdmour Mar 4, 2022
be7ddee
update redirect on sign up
mutdmour Mar 4, 2022
460ce98
prevent text wrap
mutdmour Mar 4, 2022
3a18c0d
fix notification title line height
mutdmour Mar 4, 2022
f3a6120
remove console log
mutdmour Mar 4, 2022
32abca6
Merge pull request #2936 from n8n-io/um/ui-changes
mutdmour Mar 4, 2022
1a2819d
🐘 Support testing with Postgres and MySQL (#2886)
ivov Mar 4, 2022
0641373
✏️ fix email template link expiry
BHesseldieck Mar 4, 2022
14b1ad7
🔥 remove unused import
BHesseldieck Mar 5, 2022
bdad888
✅ fix testing email not sent error
BHesseldieck Mar 6, 2022
77c8d12
merge in master and resolve conflicts
mutdmour Mar 7, 2022
56d1a8c
fix duplicate import
mutdmour Mar 7, 2022
ae72dfe
add package lock
mutdmour Mar 7, 2022
a595e04
fix export
mutdmour Mar 7, 2022
ba30698
change opacity
mutdmour Mar 7, 2022
31f1e3d
fix text issue
mutdmour Mar 7, 2022
67eb85a
update action box
mutdmour Mar 7, 2022
e4cdd37
update error title
mutdmour Mar 7, 2022
c61c189
update forgot password
mutdmour Mar 7, 2022
b04e24c
update survey
mutdmour Mar 7, 2022
b6fbf3d
update product text
mutdmour Mar 7, 2022
83ed616
remove unset fields
mutdmour Mar 7, 2022
5852d81
add category to page events
mutdmour Mar 7, 2022
a02aca7
remove duplicate import
mutdmour Mar 7, 2022
438ffac
update key
mutdmour Mar 7, 2022
2bb1daa
update key
mutdmour Mar 7, 2022
dac3a3e
update label type
mutdmour Mar 7, 2022
ea40412
🎨 um/fe review (#2946)
mutdmour Mar 7, 2022
32bf761
Move owner skip from settings
mutdmour Mar 7, 2022
49f82dc
🐛 SMTP fixes (#2937)
ivov Mar 7, 2022
cfd1484
🔊 create logger helper for migrations (#2944)
BHesseldieck Mar 7, 2022
cb1379f
🐛 Fix issue with workflow process to initialize db connection correct…
krynble Mar 7, 2022
b3a1cd8
✏️ update error messages for webhhook run/activation
BHesseldieck Mar 7, 2022
1f2a39b
📈 Implement telemetry events (#2868)
krynble Mar 7, 2022
8c84df8
🔊 Added logs to credentials, executions and workflows (#2915)
krynble Mar 7, 2022
e55c2f7
:bug: fix telemetry error
BHesseldieck Mar 7, 2022
f3d499f
fix conflicts with master
mutdmour Mar 9, 2022
0d371b1
fix duplicate
mutdmour Mar 9, 2022
7e050d2
add package-lock
mutdmour Mar 9, 2022
074a018
Merge pull request #2950 from n8n-io/um/master
mutdmour Mar 9, 2022
0ebac1b
Merge branch 'master' of github.com:n8n-io/n8n into user-management-b…
mutdmour Mar 9, 2022
81b93e9
:bug: Um/fixes (#2952)
mutdmour Mar 9, 2022
198ca5a
✏️ fix environment name
BHesseldieck Mar 9, 2022
5a55250
🐛 fix disabling UM
BHesseldieck Mar 9, 2022
9e76692
🐛 fix email setup flag
BHesseldieck Mar 9, 2022
b35d573
🐛 FE fixes 1 (#2953)
mutdmour Mar 9, 2022
0691f1b
Fixed the issue with telemetry data missing for personalization survey
krynble Mar 9, 2022
863b1b4
Merge pull request #2955 from n8n-io/um-bug-bash-bh
mutdmour Mar 9, 2022
3d08ba1
Merge pull request #2956 from n8n-io/user-management-personalization-…
mutdmour Mar 9, 2022
ada6bb7
Changed invite email text
krynble Mar 9, 2022
ead254e
Merge pull request #2959 from n8n-io/user-management-email-fix
mutdmour Mar 9, 2022
bbd1643
🐛 Fix quotes issue with postgres migration (#2958)
krynble Mar 9, 2022
7238f60
Changed text for invite link
krynble Mar 9, 2022
17746e7
Merge pull request #2960 from n8n-io/invite-email-link-message
mutdmour Mar 9, 2022
ea11323
🐛 fix reset command for mysql
BHesseldieck Mar 9, 2022
712bbbc
✅ fix race condition in test DB creation
BHesseldieck Mar 9, 2022
e92d0ef
🔐 block user creation if UM is disabled
BHesseldieck Mar 9, 2022
5c3b6a3
🥅 improve smtp setup issue error
BHesseldieck Mar 9, 2022
53ac2ac
:zap: update error message
BHesseldieck Mar 9, 2022
cedf924
fix conflicts
mutdmour Mar 10, 2022
3fd6bad
refactor route rules
mutdmour Mar 10, 2022
40c9894
set package lock
mutdmour Mar 10, 2022
4988688
fix access
mutdmour Mar 10, 2022
87d9ea9
remove capitalize
mutdmour Mar 10, 2022
725526f
update input labels
mutdmour Mar 10, 2022
692cc43
refactor heading
mutdmour Mar 10, 2022
3adc0b9
change span to fragment
mutdmour Mar 10, 2022
6795fac
add route types
mutdmour Mar 10, 2022
0c04be2
refactor views
mutdmour Mar 10, 2022
e12b869
✅ fix increase timeout for mysql
BHesseldieck Mar 10, 2022
1aa387f
:zap: correct logic of error message
BHesseldieck Mar 10, 2022
8976fe7
refactor view names
mutdmour Mar 10, 2022
285e7cf
Merge branch 'user-management-backend' of github.com:n8n-io/n8n into …
mutdmour Mar 10, 2022
1469414
:zap: update randomString
BHesseldieck Mar 10, 2022
3bef43a
📈 Added missing event regarding failed emails (#2964)
krynble Mar 10, 2022
2bdc38f
replace label with info
mutdmour Mar 10, 2022
869a69f
🛠 refactor JWT-secret creation
BHesseldieck Mar 10, 2022
bccf45f
remove duplicate key
mutdmour Mar 10, 2022
41f8e32
remove unused part
mutdmour Mar 10, 2022
de95708
remove semicolon
mutdmour Mar 10, 2022
2521e3a
Merge pull request #2965 from n8n-io/um/fe-fixes
mutdmour Mar 10, 2022
b0431e7
fix up i18n pattern
mutdmour Mar 10, 2022
a9c1458
update translation keys
mutdmour Mar 10, 2022
4fcb86d
update urls
mutdmour Mar 10, 2022
52913bf
support i18n in nds
mutdmour Mar 11, 2022
b0f989c
fix how external keys are handled
mutdmour Mar 11, 2022
d628f81
add source
mutdmour Mar 11, 2022
5bc8f90
Merge pull request #2972 from n8n-io/um/i18n-nds
mutdmour Mar 11, 2022
36bfe34
💥 update timestamp of UM migration
BHesseldieck Mar 11, 2022
78956ed
✏️ small message updates
BHesseldieck Mar 11, 2022
731596e
fix tracking
mutdmour Mar 11, 2022
e27c35b
update notification line-height
mutdmour Mar 11, 2022
e2ee069
fix avatar opacity
mutdmour Mar 11, 2022
962c4b7
fix up empty state
mutdmour Mar 11, 2022
4658dec
shift focus to input
mutdmour Mar 11, 2022
eebed1a
🔐 Disable basic auth after owner has been set up (#2973)
krynble Mar 11, 2022
c4ff484
rename modal title
mutdmour Mar 11, 2022
55255be
🐛 use pgcrypto extension for uuid creation (#2977)
BHesseldieck Mar 11, 2022
94edba2
📧 Added public url variable for emails (#2967)
krynble Mar 11, 2022
b9840c7
🌐 fix i18n pattern (#2970)
mutdmour Mar 11, 2022
0b7a06a
resolve conflicts
mutdmour Mar 11, 2022
ea0ae27
Merge pull request #2974 from n8n-io/um/ui-fixes
mutdmour Mar 11, 2022
2f4c3c9
Um/fixes 1000 (#2980)
mutdmour Mar 11, 2022
cd264f4
fix select issue
mutdmour Mar 11, 2022
496ef8e
😫 hacky solution to circumvent pgcrypto (#2979)
BHesseldieck Mar 11, 2022
b751ba9
fix owner bug after transfer. always fetch latest credentials
mutdmour Mar 12, 2022
f4b4170
Merging updates from base branch
krynble Mar 14, 2022
d99d559
add confirmation modal to setup
mutdmour Mar 14, 2022
186e987
Use webhook url as fallback when editor url is not defined
krynble Mar 14, 2022
24525f9
fix enter bug
mutdmour Mar 14, 2022
e0fa225
update modal
mutdmour Mar 14, 2022
8cd9217
update modal
mutdmour Mar 14, 2022
406713a
update modal text, fix bug in settings view
mutdmour Mar 14, 2022
450508d
Updating editor url to not append path
krynble Mar 14, 2022
c1b0cb3
Merge pull request #2986 from n8n-io/user-management-editor-uri
mutdmour Mar 14, 2022
914d1f5
rename keys
mutdmour Mar 14, 2022
68eaebe
Merge pull request #2985 from n8n-io/um/owner-modal
mutdmour Mar 14, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,11 @@ module.exports = {
*/
'@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }],

/**
* https://github.com/typescript-eslint/typescript-eslint/blob/v4.33.0/packages/eslint-plugin/docs/rules/no-namespace.md
*/
'@typescript-eslint/no-namespace': 'off',

/**
* https://eslint.org/docs/1.0.0/rules/no-throw-literal
*/
Expand Down
2,508 changes: 1,743 additions & 765 deletions package-lock.json

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions packages/cli/commands/Interfaces.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,14 @@ declare module 'json-diff' {
}
export function diff(obj1: unknown, obj2: unknown, diffOptions: IDiffOptions): string;
}

type SmtpConfig = {
host: string;
port: number;
secure: boolean;
auth: {
user: string;
pass: string;
};
sender: string;
};
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
170 changes: 130 additions & 40 deletions packages/cli/commands/import/credentials.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/* eslint-disable no-restricted-syntax */
/* eslint-disable @typescript-eslint/no-shadow */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable no-await-in-loop */
/* eslint-disable @typescript-eslint/no-non-null-assertion */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable no-console */
import { Command, flags } from '@oclif/command';
Expand All @@ -9,15 +15,25 @@ import { LoggerProxy } from 'n8n-workflow';
import * as fs from 'fs';
import * as glob from 'fast-glob';
import * as path from 'path';
import { EntityManager, getConnection } from 'typeorm';
import { getLogger } from '../../src/Logger';
import { Db } from '../../src';
import { User } from '../../src/databases/entities/User';
import { SharedCredentials } from '../../src/databases/entities/SharedCredentials';
import { Role } from '../../src/databases/entities/Role';
import { CredentialsEntity } from '../../src/databases/entities/CredentialsEntity';

const FIX_INSTRUCTION =
'Please fix the database by running ./packages/cli/bin/n8n user-management:reset';

export class ImportCredentialsCommand extends Command {
static description = 'Import credentials';

static examples = [
`$ n8n import:credentials --input=file.json`,
`$ n8n import:credentials --separate --input=backups/latest/`,
'$ n8n import:credentials --input=file.json',
'$ n8n import:credentials --separate --input=backups/latest/',
'$ n8n import:credentials --input=file.json --userId=1d64c3d2-85fe-4a83-a649-e446b07b3aae',
'$ n8n import:credentials --separate --input=backups/latest/ --userId=1d64c3d2-85fe-4a83-a649-e446b07b3aae',
];

static flags = {
Expand All @@ -29,87 +45,161 @@ export class ImportCredentialsCommand extends Command {
separate: flags.boolean({
description: 'Imports *.json files from directory provided by --input',
}),
userId: flags.string({
description: 'The ID of the user to assign the imported credentials to',
}),
};

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
async run() {
ownerCredentialRole: Role;

transactionManager: EntityManager;

async run(): Promise<void> {
const logger = getLogger();
LoggerProxy.init(logger);

// eslint-disable-next-line @typescript-eslint/no-shadow
const { flags } = this.parse(ImportCredentialsCommand);

if (!flags.input) {
console.info(`An input file or directory with --input must be provided`);
console.info('An input file or directory with --input must be provided');
return;
}

if (flags.separate) {
if (fs.existsSync(flags.input)) {
if (!fs.lstatSync(flags.input).isDirectory()) {
console.info(`The paramenter --input must be a directory`);
console.info('The argument to --input must be a directory');
return;
}
}
}

let totalImported = 0;

try {
await Db.init();

await this.initOwnerCredentialRole();
const user = flags.userId ? await this.getAssignee(flags.userId) : await this.getOwner();

// Make sure the settings exist
await UserSettings.prepareUserSettings();
let i;

const encryptionKey = await UserSettings.getEncryptionKey();
if (encryptionKey === undefined) {
throw new Error('No encryption key got found to encrypt the credentials!');
throw new Error('No encryption key found to encrypt the credentials!');
}

if (flags.separate) {
const files = await glob(
`${flags.input.endsWith(path.sep) ? flags.input : flags.input + path.sep}*.json`,
);
for (i = 0; i < files.length; i++) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const credential = JSON.parse(fs.readFileSync(files[i], { encoding: 'utf8' }));

// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (typeof credential.data === 'object') {
// plain data / decrypted input. Should be encrypted first.
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
Credentials.prototype.setData.call(credential, credential.data, encryptionKey);
totalImported = files.length;

await getConnection().transaction(async (transactionManager) => {
this.transactionManager = transactionManager;
for (const file of files) {
const credential = JSON.parse(fs.readFileSync(file, { encoding: 'utf8' }));

if (typeof credential.data === 'object') {
// plain data / decrypted input. Should be encrypted first.
Credentials.prototype.setData.call(credential, credential.data, encryptionKey);
}

await this.storeCredential(credential, user);
}
});

// eslint-disable-next-line no-await-in-loop, @typescript-eslint/no-non-null-assertion
await Db.collections.Credentials!.save(credential);
}
} else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const fileContents = JSON.parse(fs.readFileSync(flags.input, { encoding: 'utf8' }));
this.reportSuccess(totalImported);
process.exit();
}

if (!Array.isArray(fileContents)) {
throw new Error(`File does not seem to contain credentials.`);
}
const credentials = JSON.parse(fs.readFileSync(flags.input, { encoding: 'utf8' }));

totalImported = credentials.length;

if (!Array.isArray(credentials)) {
throw new Error(
'File does not seem to contain credentials. Make sure the credentials are contained in an array.',
);
}

for (i = 0; i < fileContents.length; i++) {
if (typeof fileContents[i].data === 'object') {
await getConnection().transaction(async (transactionManager) => {
this.transactionManager = transactionManager;
for (const credential of credentials) {
if (typeof credential.data === 'object') {
// plain data / decrypted input. Should be encrypted first.
Credentials.prototype.setData.call(
fileContents[i],
fileContents[i].data,
encryptionKey,
);
Credentials.prototype.setData.call(credential, credential.data, encryptionKey);
}
// eslint-disable-next-line no-await-in-loop, @typescript-eslint/no-non-null-assertion
await Db.collections.Credentials!.save(fileContents[i]);
await this.storeCredential(credential, user);
}
}
console.info(`Successfully imported ${i} ${i === 1 ? 'credential.' : 'credentials.'}`);
process.exit(0);
});

this.reportSuccess(totalImported);
process.exit();
} catch (error) {
console.error('An error occurred while exporting credentials. See log messages for details.');
logger.error(error.message);
console.error('An error occurred while importing credentials. See log messages for details.');
if (error instanceof Error) logger.error(error.message);
this.exit(1);
}
}

private reportSuccess(total: number) {
console.info(`Successfully imported ${total} ${total === 1 ? 'workflow.' : 'workflows.'}`);
}

private async initOwnerCredentialRole() {
const ownerCredentialRole = await Db.collections.Role!.findOne({
where: { name: 'owner', scope: 'credential' },
});

if (!ownerCredentialRole) {
throw new Error(`Failed to find owner credential role. ${FIX_INSTRUCTION}`);
}

this.ownerCredentialRole = ownerCredentialRole;
}

private async storeCredential(credential: object, user: User) {
const newCredential = new CredentialsEntity();

Object.assign(newCredential, credential);

const savedCredential = await this.transactionManager.save<CredentialsEntity>(newCredential);

const newSharedCredential = new SharedCredentials();

Object.assign(newSharedCredential, {
credentials: savedCredential,
user,
role: this.ownerCredentialRole,
});

await this.transactionManager.save<SharedCredentials>(newSharedCredential);
}

private async getOwner() {
const ownerGlobalRole = await Db.collections.Role!.findOne({
where: { name: 'owner', scope: 'global' },
});

const owner = await Db.collections.User!.findOne({ globalRole: ownerGlobalRole });

if (!owner) {
throw new Error(`Failed to find owner. ${FIX_INSTRUCTION}`);
}

return owner;
}

private async getAssignee(userId: string) {
const user = await Db.collections.User!.findOne(userId);

if (!user) {
throw new Error(`Failed to find user with ID ${userId}`);
}

return user;
}
}
Loading