cabloy 5.1.195 → 5.1.196
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/.cabloy-version +1 -1
- package/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/repo-e2e/specs/home-user-account.spec.ts +311 -207
- package/vona/pnpm-lock.yaml +6 -6
- package/vona/src/suite/a-home/modules/home-user/src/.metadata/index.ts +379 -376
- package/vona/src/suite/a-home/modules/home-user/src/controller/passportTest.ts +60 -0
- package/vona/src/suite/a-home/modules/home-user/test/passportTest.test.ts +164 -1
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import type { TableIdentity } from 'table-identity';
|
|
1
2
|
import type { IDecoratorControllerOptions } from 'vona-module-a-web';
|
|
2
3
|
|
|
3
4
|
import { BeanBase } from 'vona';
|
|
5
|
+
import { Core } from 'vona-module-a-core';
|
|
4
6
|
import { Api } from 'vona-module-a-openapiutils';
|
|
5
7
|
import { Passport } from 'vona-module-a-user';
|
|
6
8
|
import { Controller, Web } from 'vona-module-a-web';
|
|
7
9
|
|
|
10
|
+
const fixtureUserNamePrefix = 'e2e-fixture-';
|
|
11
|
+
|
|
8
12
|
export interface IControllerOptionsPassportTest extends IDecoratorControllerOptions {}
|
|
9
13
|
|
|
10
14
|
@Controller<IControllerOptionsPassportTest>({
|
|
@@ -18,4 +22,60 @@ export class ControllerPassportTest extends BeanBase {
|
|
|
18
22
|
async activateCurrent() {
|
|
19
23
|
await this.bean.user.activate(this.bean.passport.currentUser!);
|
|
20
24
|
}
|
|
25
|
+
|
|
26
|
+
@Web.delete('removeCurrentFixture')
|
|
27
|
+
@Passport.activated('noCheck')
|
|
28
|
+
@Core.transaction()
|
|
29
|
+
async removeCurrentFixture() {
|
|
30
|
+
const user = this.bean.passport.currentUser!;
|
|
31
|
+
if (!user.name.startsWith(fixtureUserNamePrefix)) this.app.throw(403);
|
|
32
|
+
|
|
33
|
+
const auths = await this.$scope.auth.model.auth.select({ where: { userId: user.id } });
|
|
34
|
+
const authProvider = await this.bean.authProvider.get({
|
|
35
|
+
providerName: 'auth-simple:simple',
|
|
36
|
+
clientName: 'default',
|
|
37
|
+
});
|
|
38
|
+
const authSimpleIds = authProvider
|
|
39
|
+
? auths.filter(auth => auth.authProviderId === authProvider.id).map(auth => auth.profileId)
|
|
40
|
+
: [];
|
|
41
|
+
if (auths.length) await this.$scope.auth.model.auth.deleteBulk(auths.map(auth => auth.id));
|
|
42
|
+
if (authSimpleIds.length) {
|
|
43
|
+
await this.$scope.authSimple.model.authSimple.deleteBulk(authSimpleIds);
|
|
44
|
+
}
|
|
45
|
+
await this.scope.model.roleUser.delete({ userId: user.id });
|
|
46
|
+
await this.bean.user.removeById(user.id);
|
|
47
|
+
this.ctx.db.commit(async () => {
|
|
48
|
+
await Promise.all([
|
|
49
|
+
this._removeCurrentToken(
|
|
50
|
+
this.scope.cacheRedis.activation,
|
|
51
|
+
this.scope.cacheRedis.activationCurrent,
|
|
52
|
+
user.id,
|
|
53
|
+
),
|
|
54
|
+
this._removeCurrentToken(
|
|
55
|
+
this.scope.cacheRedis.passwordSet,
|
|
56
|
+
this.scope.cacheRedis.passwordSetCurrent,
|
|
57
|
+
user.id,
|
|
58
|
+
),
|
|
59
|
+
this._removeCurrentToken(
|
|
60
|
+
this.scope.cacheRedis.passwordReset,
|
|
61
|
+
this.scope.cacheRedis.passwordResetCurrent,
|
|
62
|
+
user.id,
|
|
63
|
+
),
|
|
64
|
+
this.bean.passport.kickOut(user),
|
|
65
|
+
]);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private async _removeCurrentToken(
|
|
70
|
+
tokenCache: { del(key: string): Promise<unknown> },
|
|
71
|
+
currentCache: {
|
|
72
|
+
get(key: TableIdentity): Promise<string | undefined>;
|
|
73
|
+
del(key: TableIdentity): Promise<unknown>;
|
|
74
|
+
},
|
|
75
|
+
userId: TableIdentity,
|
|
76
|
+
) {
|
|
77
|
+
const digest = await currentCache.get(userId);
|
|
78
|
+
if (digest) await tokenCache.del(digest);
|
|
79
|
+
await currentCache.del(userId);
|
|
80
|
+
}
|
|
21
81
|
}
|
|
@@ -4,8 +4,171 @@ import { describe, it } from 'node:test';
|
|
|
4
4
|
import { app } from 'vona-mock';
|
|
5
5
|
|
|
6
6
|
const activateCurrentPath = '/home/user/passportTest/activateCurrent';
|
|
7
|
+
const removeCurrentFixturePath = '/home/user/passportTest/removeCurrentFixture';
|
|
8
|
+
const fixtureUserNamePrefix = 'e2e-fixture-';
|
|
9
|
+
|
|
10
|
+
describe('passportTest.test.ts', { concurrency: false }, () => {
|
|
11
|
+
it('action:passportTest:removeCurrentFixture removes only the authenticated marked fixture', async () => {
|
|
12
|
+
let fixtureUserId: string | undefined;
|
|
13
|
+
let fixtureAuthId: string | undefined;
|
|
14
|
+
let fixtureAuthSimpleId: string | undefined;
|
|
15
|
+
let ordinaryUserId: string | undefined;
|
|
16
|
+
try {
|
|
17
|
+
await app.bean.executor.mockCtx(async () => {
|
|
18
|
+
const fixtureUser = await app.bean.user.register({
|
|
19
|
+
name: `${fixtureUserNamePrefix}${crypto.randomUUID()}`,
|
|
20
|
+
});
|
|
21
|
+
fixtureUserId = String(fixtureUser.id);
|
|
22
|
+
await app.bean.user.activate(fixtureUser);
|
|
23
|
+
await app
|
|
24
|
+
.scope('auth-simple')
|
|
25
|
+
.service.authSimple.createForUser(fixtureUser.id, 'fixture-password');
|
|
26
|
+
const authProvider = await app.bean.authProvider.get({
|
|
27
|
+
providerName: 'auth-simple:simple',
|
|
28
|
+
clientName: 'default',
|
|
29
|
+
});
|
|
30
|
+
const fixtureAuth = await app.scope('a-auth').model.auth.get({
|
|
31
|
+
userId: fixtureUser.id,
|
|
32
|
+
authProviderId: authProvider!.id,
|
|
33
|
+
});
|
|
34
|
+
fixtureAuthId = String(fixtureAuth!.id);
|
|
35
|
+
fixtureAuthSimpleId = fixtureAuth!.profileId;
|
|
36
|
+
const ordinaryUser = await app.bean.user.register({
|
|
37
|
+
name: `passport-test-${crypto.randomUUID()}`,
|
|
38
|
+
});
|
|
39
|
+
ordinaryUserId = String(ordinaryUser.id);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
await app.bean.executor.mockCtx(async () => {
|
|
43
|
+
const [_, error] = await catchError(() =>
|
|
44
|
+
app.bean.executor.performAction('delete', removeCurrentFixturePath, {
|
|
45
|
+
innerAccess: false,
|
|
46
|
+
}),
|
|
47
|
+
);
|
|
48
|
+
assert.equal(error?.code, 401);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
await app.bean.executor.mockCtx(async () => {
|
|
52
|
+
const ordinaryUser = await app.bean.user.findOneById(ordinaryUserId!);
|
|
53
|
+
await app.bean.passport.signinSystem('mock', -10001 as any, ordinaryUser!.name);
|
|
54
|
+
try {
|
|
55
|
+
const [_, error] = await catchError(() =>
|
|
56
|
+
app.bean.executor.performAction('delete', removeCurrentFixturePath, {
|
|
57
|
+
innerAccess: false,
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
60
|
+
assert.equal(error?.code, 403);
|
|
61
|
+
} finally {
|
|
62
|
+
await app.bean.passport.signout();
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
await app.bean.executor.mockCtx(async () => {
|
|
67
|
+
const fixtureUser = await app.bean.user.findOneById(fixtureUserId!);
|
|
68
|
+
await app.bean.passport.signinSystem('mock', -10002 as any, fixtureUser!.name);
|
|
69
|
+
try {
|
|
70
|
+
assert.equal(
|
|
71
|
+
await app.bean.executor.performAction('delete', removeCurrentFixturePath, {
|
|
72
|
+
innerAccess: false,
|
|
73
|
+
}),
|
|
74
|
+
null,
|
|
75
|
+
);
|
|
76
|
+
} finally {
|
|
77
|
+
await app.bean.passport.signout();
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
await app.bean.executor.mockCtx(async () => {
|
|
82
|
+
assert.equal(await app.bean.user.findOneById(fixtureUserId!), undefined);
|
|
83
|
+
assert.equal(await app.scope('a-auth').model.auth.getById(fixtureAuthId!), undefined);
|
|
84
|
+
assert.equal(
|
|
85
|
+
await app.scope('auth-simple').model.authSimple.getById(fixtureAuthSimpleId!),
|
|
86
|
+
undefined,
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
fixtureUserId = undefined;
|
|
90
|
+
fixtureAuthId = undefined;
|
|
91
|
+
fixtureAuthSimpleId = undefined;
|
|
92
|
+
} finally {
|
|
93
|
+
await app.bean.executor.mockCtx(async () => {
|
|
94
|
+
if (fixtureAuthId) await app.scope('a-auth').model.auth.deleteById(fixtureAuthId);
|
|
95
|
+
if (fixtureAuthSimpleId) {
|
|
96
|
+
await app.scope('auth-simple').model.authSimple.deleteById(fixtureAuthSimpleId);
|
|
97
|
+
}
|
|
98
|
+
if (fixtureUserId) {
|
|
99
|
+
await app.scope('home-user').model.roleUser.delete({ userId: fixtureUserId });
|
|
100
|
+
await app.bean.user.removeById(fixtureUserId);
|
|
101
|
+
}
|
|
102
|
+
if (ordinaryUserId) await app.bean.user.removeById(ordinaryUserId);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('removes a registered fixture before activation', async () => {
|
|
108
|
+
let userId: string | undefined;
|
|
109
|
+
let authId: string | undefined;
|
|
110
|
+
let authSimpleId: string | undefined;
|
|
111
|
+
try {
|
|
112
|
+
await app.bean.executor.mockCtx(async () => {
|
|
113
|
+
const user = await app.bean.user.register({
|
|
114
|
+
name: `${fixtureUserNamePrefix}${crypto.randomUUID()}`,
|
|
115
|
+
});
|
|
116
|
+
userId = String(user.id);
|
|
117
|
+
assert.equal(user.activated, false);
|
|
118
|
+
const authSimple = await app
|
|
119
|
+
.scope('auth-simple')
|
|
120
|
+
.service.authSimple.createForUser(user.id, 'fixture-password');
|
|
121
|
+
authSimpleId = String(authSimple!.id);
|
|
122
|
+
const provider = await app.bean.authProvider.get({
|
|
123
|
+
providerName: 'auth-simple:simple',
|
|
124
|
+
clientName: 'default',
|
|
125
|
+
});
|
|
126
|
+
const auth = await app.scope('a-auth').model.auth.get({
|
|
127
|
+
userId: user.id,
|
|
128
|
+
authProviderId: provider!.id,
|
|
129
|
+
});
|
|
130
|
+
authId = String(auth!.id);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
await app.bean.executor.mockCtx(async () => {
|
|
134
|
+
const user = await app.bean.user.findOneById(userId!);
|
|
135
|
+
assert.equal(user?.activated, false);
|
|
136
|
+
await app.bean.passport.signinSystem('mock', -10003 as any, user!.name);
|
|
137
|
+
try {
|
|
138
|
+
assert.equal(
|
|
139
|
+
await app.bean.executor.performAction('delete', removeCurrentFixturePath, {
|
|
140
|
+
innerAccess: false,
|
|
141
|
+
}),
|
|
142
|
+
null,
|
|
143
|
+
);
|
|
144
|
+
} finally {
|
|
145
|
+
await app.bean.passport.signout();
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
await app.bean.executor.mockCtx(async () => {
|
|
150
|
+
assert.equal(await app.bean.user.findOneById(userId!), undefined);
|
|
151
|
+
assert.equal(await app.scope('a-auth').model.auth.getById(authId!), undefined);
|
|
152
|
+
assert.equal(
|
|
153
|
+
await app.scope('auth-simple').model.authSimple.getById(authSimpleId!),
|
|
154
|
+
undefined,
|
|
155
|
+
);
|
|
156
|
+
});
|
|
157
|
+
userId = undefined;
|
|
158
|
+
authId = undefined;
|
|
159
|
+
authSimpleId = undefined;
|
|
160
|
+
} finally {
|
|
161
|
+
await app.bean.executor.mockCtx(async () => {
|
|
162
|
+
if (authId) await app.scope('a-auth').model.auth.deleteById(authId);
|
|
163
|
+
if (authSimpleId) await app.scope('auth-simple').model.authSimple.deleteById(authSimpleId);
|
|
164
|
+
if (userId) {
|
|
165
|
+
await app.scope('home-user').model.roleUser.delete({ userId });
|
|
166
|
+
await app.bean.user.removeById(userId);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
});
|
|
7
171
|
|
|
8
|
-
describe('passportTest.test.ts', () => {
|
|
9
172
|
it('action:passportTest:activateCurrent', async () => {
|
|
10
173
|
let userId: string | undefined;
|
|
11
174
|
try {
|