@unchainedshop/core-users 3.0.0-alpha6 → 3.0.0-rc1
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/lib/module/configureUsersModule.d.ts +10 -68
- package/lib/module/configureUsersModule.d.ts.map +1 -1
- package/lib/module/configureUsersModule.js +58 -52
- package/lib/module/configureUsersModule.js.map +1 -1
- package/lib/module/configureUsersModule_BACKUP_57123.d.ts +73 -0
- package/lib/module/configureUsersModule_BACKUP_57123.d.ts.map +1 -0
- package/lib/module/configureUsersModule_BACKUP_57123.js +567 -0
- package/lib/module/configureUsersModule_BACKUP_57123.js.map +1 -0
- package/lib/module/configureUsersModule_BASE_57123.d.ts +131 -0
- package/lib/module/configureUsersModule_BASE_57123.d.ts.map +1 -0
- package/lib/module/configureUsersModule_BASE_57123.js +563 -0
- package/lib/module/configureUsersModule_BASE_57123.js.map +1 -0
- package/lib/module/configureUsersModule_LOCAL_57123.d.ts +131 -0
- package/lib/module/configureUsersModule_LOCAL_57123.d.ts.map +1 -0
- package/lib/module/configureUsersModule_LOCAL_57123.js +564 -0
- package/lib/module/configureUsersModule_LOCAL_57123.js.map +1 -0
- package/lib/module/configureUsersModule_REMOTE_57123.d.ts +74 -0
- package/lib/module/configureUsersModule_REMOTE_57123.d.ts.map +1 -0
- package/lib/module/configureUsersModule_REMOTE_57123.js +567 -0
- package/lib/module/configureUsersModule_REMOTE_57123.js.map +1 -0
- package/lib/module/configureUsersWebAuthnModule.d.ts.map +1 -1
- package/lib/module/configureUsersWebAuthnModule.js.map +1 -1
- package/lib/types.d.ts +5 -2
- package/lib/types.d.ts.map +1 -1
- package/lib/users-index.d.ts +0 -1
- package/lib/users-index.d.ts.map +1 -1
- package/lib/users-index.js +0 -1
- package/lib/users-index.js.map +1 -1
- package/package.json +14 -17
- package/src/module/configureUsersModule.ts +78 -72
- package/src/module/configureUsersWebAuthnModule.ts +0 -1
- package/src/types.ts +5 -2
- package/src/users-index.ts +0 -1
- package/tests/mock/user-mock.ts +2 -3
- package/tsconfig.json +5 -7
- package/lib/services/migrateUserDataService.d.ts +0 -4
- package/lib/services/migrateUserDataService.d.ts.map +0 -1
- package/lib/services/migrateUserDataService.js +0 -18
- package/lib/services/migrateUserDataService.js.map +0 -1
- package/lib/services/updateUserAvatarAfterUploadService.d.ts +0 -15
- package/lib/services/updateUserAvatarAfterUploadService.d.ts.map +0 -1
- package/lib/services/updateUserAvatarAfterUploadService.js +0 -24
- package/lib/services/updateUserAvatarAfterUploadService.js.map +0 -1
- package/lib/services/userServices.d.ts +0 -8
- package/lib/services/userServices.d.ts.map +0 -1
- package/lib/services/userServices.js +0 -7
- package/lib/services/userServices.js.map +0 -1
- package/src/module/sha256.ts +0 -5
- package/src/services/migrateUserDataService.ts +0 -37
- package/src/services/updateUserAvatarAfterUploadService.ts +0 -42
- package/src/services/userServices.ts +0 -15
package/lib/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { TimestampFields, Address, Contact, mongodb } from '@unchainedshop/mongodb';
|
|
2
|
+
import { DateFilterInput } from '@unchainedshop/utils';
|
|
2
3
|
export interface PushSubscription {
|
|
3
4
|
_id: string;
|
|
4
5
|
userAgent: string;
|
|
@@ -47,7 +48,7 @@ export interface PushSubscriptionObject {
|
|
|
47
48
|
};
|
|
48
49
|
}
|
|
49
50
|
export type User = {
|
|
50
|
-
_id
|
|
51
|
+
_id: string;
|
|
51
52
|
deleted?: Date;
|
|
52
53
|
avatarId?: string;
|
|
53
54
|
emails: Array<Email>;
|
|
@@ -67,6 +68,8 @@ export type User = {
|
|
|
67
68
|
export type UserQuery = mongodb.Filter<User> & {
|
|
68
69
|
includeGuests?: boolean;
|
|
69
70
|
queryString?: string;
|
|
71
|
+
emailVerified?: boolean;
|
|
72
|
+
lastLogin?: DateFilterInput;
|
|
70
73
|
};
|
|
71
74
|
export interface WebAuthnCredentialsCreationRequest {
|
|
72
75
|
challenge: string;
|
package/lib/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/lib/users-index.d.ts
CHANGED
package/lib/users-index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"users-index.d.ts","sourceRoot":"","sources":["../src/users-index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,kCAAkC,CAAC;AACjD,cAAc,
|
|
1
|
+
{"version":3,"file":"users-index.d.ts","sourceRoot":"","sources":["../src/users-index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,kCAAkC,CAAC;AACjD,cAAc,qBAAqB,CAAC"}
|
package/lib/users-index.js
CHANGED
package/lib/users-index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"users-index.js","sourceRoot":"","sources":["../src/users-index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,kCAAkC,CAAC;AACjD,cAAc,
|
|
1
|
+
{"version":3,"file":"users-index.js","sourceRoot":"","sources":["../src/users-index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,kCAAkC,CAAC;AACjD,cAAc,qBAAqB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unchainedshop/core-users",
|
|
3
|
-
"version": "3.0.0-
|
|
3
|
+
"version": "3.0.0-rc1",
|
|
4
4
|
"main": "lib/users-index.js",
|
|
5
|
-
"exports": {
|
|
6
|
-
".": "./lib/users-index.js",
|
|
7
|
-
"./*": "./lib/*"
|
|
8
|
-
},
|
|
9
5
|
"types": "lib/users-index.d.ts",
|
|
10
6
|
"type": "module",
|
|
11
7
|
"scripts": {
|
|
12
|
-
"clean": "
|
|
13
|
-
"
|
|
8
|
+
"clean": "tsc -b --clean",
|
|
9
|
+
"build": "tsc -b",
|
|
10
|
+
"prepublishOnly": "npm run clean && npm run build",
|
|
14
11
|
"watch": "tsc -w",
|
|
15
12
|
"test": "NODE_OPTIONS=--experimental-vm-modules jest --detectOpenHandles --forceExit",
|
|
16
13
|
"test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch --detectOpenHandles --forceExit"
|
|
@@ -31,19 +28,19 @@
|
|
|
31
28
|
},
|
|
32
29
|
"homepage": "https://github.com/unchainedshop/unchained#readme",
|
|
33
30
|
"dependencies": {
|
|
34
|
-
"@
|
|
35
|
-
"@unchainedshop/
|
|
36
|
-
"@unchainedshop/
|
|
37
|
-
"@unchainedshop/
|
|
38
|
-
"@unchainedshop/
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
31
|
+
"@node-rs/bcrypt": "^1.10.7",
|
|
32
|
+
"@unchainedshop/events": "^3.0.0-rc1",
|
|
33
|
+
"@unchainedshop/file-upload": "^3.0.0-rc1",
|
|
34
|
+
"@unchainedshop/logger": "^3.0.0-rc1",
|
|
35
|
+
"@unchainedshop/mongodb": "^3.0.0-rc1",
|
|
36
|
+
"@unchainedshop/roles": "^3.0.0-rc1",
|
|
37
|
+
"@unchainedshop/utils": "^3.0.0-rc1",
|
|
38
|
+
"fido2-lib": "^3.5.3"
|
|
42
39
|
},
|
|
43
40
|
"devDependencies": {
|
|
44
|
-
"@types/node": "^22.
|
|
41
|
+
"@types/node": "^22.10.2",
|
|
45
42
|
"jest": "^29.7.0",
|
|
46
43
|
"ts-jest": "^29.2.5",
|
|
47
|
-
"typescript": "^5.
|
|
44
|
+
"typescript": "^5.7.2"
|
|
48
45
|
}
|
|
49
46
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import bcrypt from '
|
|
2
|
-
import { ModuleInput } from '@unchainedshop/mongodb';
|
|
1
|
+
import bcrypt from '@node-rs/bcrypt';
|
|
2
|
+
import { ModuleInput, Address, Contact } from '@unchainedshop/mongodb';
|
|
3
3
|
import { User, UserQuery, Email, UserLastLogin, UserProfile, UserData } from '../types.js';
|
|
4
4
|
import { emit, registerEvents } from '@unchainedshop/events';
|
|
5
5
|
import {
|
|
@@ -8,18 +8,12 @@ import {
|
|
|
8
8
|
mongodb,
|
|
9
9
|
generateDbObjectId,
|
|
10
10
|
} from '@unchainedshop/mongodb';
|
|
11
|
-
import { systemLocale } from '@unchainedshop/utils';
|
|
12
|
-
import { FileDirector } from '@unchainedshop/file-upload';
|
|
13
|
-
import { SortDirection, SortOption } from '@unchainedshop/utils';
|
|
11
|
+
import { systemLocale, SortDirection, SortOption, sha256 } from '@unchainedshop/utils';
|
|
14
12
|
import { UsersCollection } from '../db/UsersCollection.js';
|
|
15
13
|
import addMigrations from './addMigrations.js';
|
|
16
14
|
import { userSettings, UserSettingsOptions } from '../users-settings.js';
|
|
17
15
|
import { configureUsersWebAuthnModule, UsersWebAuthnModule } from './configureUsersWebAuthnModule.js';
|
|
18
16
|
import * as pbkdf2 from './pbkdf2.js';
|
|
19
|
-
import * as sha256 from './sha256.js';
|
|
20
|
-
import type { Address, Contact } from '@unchainedshop/mongodb';
|
|
21
|
-
import { UserServices } from '../services/userServices.js';
|
|
22
|
-
import { FileServices, FilesModule } from '@unchainedshop/core-files';
|
|
23
17
|
|
|
24
18
|
export type UsersModule = {
|
|
25
19
|
// Submodules
|
|
@@ -76,7 +70,8 @@ export type UsersModule = {
|
|
|
76
70
|
_id: string,
|
|
77
71
|
{ profile, meta }: { profile?: UserProfile; meta?: any },
|
|
78
72
|
) => Promise<User>;
|
|
79
|
-
|
|
73
|
+
markDeleted: (userId: string) => Promise<User>;
|
|
74
|
+
deletePermanently: (params: { userId: string }) => Promise<User>;
|
|
80
75
|
updateRoles: (_id: string, roles: Array<string>) => Promise<User>;
|
|
81
76
|
updateTags: (_id: string, tags: Array<string>) => Promise<User>;
|
|
82
77
|
updateUser: (
|
|
@@ -93,6 +88,9 @@ export type UsersModule = {
|
|
|
93
88
|
},
|
|
94
89
|
) => Promise<void>;
|
|
95
90
|
removePushSubscription: (userId: string, p256dh: string) => Promise<void>;
|
|
91
|
+
hashPassword(password: string): Promise<{
|
|
92
|
+
pbkdf2: string;
|
|
93
|
+
}>;
|
|
96
94
|
};
|
|
97
95
|
|
|
98
96
|
const USER_EVENTS = [
|
|
@@ -118,36 +116,44 @@ export const removeConfidentialServiceHashes = (rawUser: User): User => {
|
|
|
118
116
|
return user;
|
|
119
117
|
};
|
|
120
118
|
|
|
121
|
-
export const buildFindSelector = ({
|
|
119
|
+
export const buildFindSelector = ({
|
|
120
|
+
includeGuests,
|
|
121
|
+
queryString,
|
|
122
|
+
emailVerified,
|
|
123
|
+
lastLogin,
|
|
124
|
+
...rest
|
|
125
|
+
}: UserQuery) => {
|
|
122
126
|
const selector: mongodb.Filter<User> = { ...rest, deleted: null };
|
|
123
127
|
if (!includeGuests) selector.guest = { $in: [false, null] };
|
|
128
|
+
if (emailVerified === true) {
|
|
129
|
+
selector['emails.verified'] = true;
|
|
130
|
+
}
|
|
131
|
+
if (emailVerified === false) {
|
|
132
|
+
// We need to use $ne here else we'd also find users with many emails where one is
|
|
133
|
+
// unverified
|
|
134
|
+
selector['emails.verified'] = { $ne: true };
|
|
135
|
+
}
|
|
136
|
+
if (lastLogin?.start) {
|
|
137
|
+
selector['lastLogin.timestamp'] = { $exists: true };
|
|
138
|
+
}
|
|
139
|
+
if (lastLogin?.end) {
|
|
140
|
+
selector['lastLogin.timestamp'].$lte = new Date(lastLogin.end);
|
|
141
|
+
}
|
|
142
|
+
if (lastLogin?.start) {
|
|
143
|
+
selector['lastLogin.timestamp'].$gte = new Date(lastLogin.start);
|
|
144
|
+
}
|
|
124
145
|
if (queryString) {
|
|
125
146
|
(selector as any).$text = { $search: queryString };
|
|
126
147
|
}
|
|
127
148
|
return selector;
|
|
128
149
|
};
|
|
129
150
|
|
|
130
|
-
FileDirector.registerFileUploadCallback<{
|
|
131
|
-
services: {
|
|
132
|
-
users: UserServices;
|
|
133
|
-
files: FileServices;
|
|
134
|
-
};
|
|
135
|
-
modules: {
|
|
136
|
-
users: UsersModule;
|
|
137
|
-
files: FilesModule;
|
|
138
|
-
};
|
|
139
|
-
}>('user-avatars', async (file, context) => {
|
|
140
|
-
const { services } = context;
|
|
141
|
-
return services.users.updateUserAvatarAfterUpload({ file }, context);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
151
|
export const configureUsersModule = async ({
|
|
145
152
|
db,
|
|
146
153
|
options,
|
|
147
154
|
migrationRepository,
|
|
148
|
-
}: ModuleInput<UserSettingsOptions>) => {
|
|
155
|
+
}: ModuleInput<UserSettingsOptions>): Promise<UsersModule> => {
|
|
149
156
|
userSettings.configureSettings(options || {}, db);
|
|
150
|
-
|
|
151
157
|
registerEvents(USER_EVENTS);
|
|
152
158
|
const Users = await UsersCollection(db);
|
|
153
159
|
|
|
@@ -185,13 +191,13 @@ export const configureUsersModule = async ({
|
|
|
185
191
|
when: Date;
|
|
186
192
|
}> {
|
|
187
193
|
if (!plainToken) return null;
|
|
188
|
-
const token = await sha256
|
|
194
|
+
const token = await sha256(plainToken);
|
|
189
195
|
const user = await Users.findOne(
|
|
190
196
|
{
|
|
191
197
|
'services.email.verificationTokens': {
|
|
192
198
|
$elemMatch: {
|
|
193
199
|
token,
|
|
194
|
-
when: { $gt: new Date().getTime() },
|
|
200
|
+
when: { $gt: new Date(new Date().getTime() - 1000 * 60 * 60) },
|
|
195
201
|
},
|
|
196
202
|
},
|
|
197
203
|
},
|
|
@@ -231,13 +237,13 @@ export const configureUsersModule = async ({
|
|
|
231
237
|
},
|
|
232
238
|
|
|
233
239
|
async findUserByResetToken(plainToken: string): Promise<User> {
|
|
234
|
-
const token = await sha256
|
|
240
|
+
const token = await sha256(plainToken);
|
|
235
241
|
const user = await Users.findOne(
|
|
236
242
|
{
|
|
237
243
|
'services.password.reset': {
|
|
238
244
|
$elemMatch: {
|
|
239
245
|
token,
|
|
240
|
-
when: { $gt: new Date().getTime() },
|
|
246
|
+
when: { $gt: new Date(new Date().getTime() - 1000 * 60 * 60) },
|
|
241
247
|
},
|
|
242
248
|
},
|
|
243
249
|
},
|
|
@@ -247,7 +253,7 @@ export const configureUsersModule = async ({
|
|
|
247
253
|
},
|
|
248
254
|
|
|
249
255
|
async findUserByToken(plainToken?: string): Promise<User> {
|
|
250
|
-
const token = await sha256
|
|
256
|
+
const token = await sha256(plainToken);
|
|
251
257
|
|
|
252
258
|
if (token) {
|
|
253
259
|
return Users.findOne({
|
|
@@ -276,7 +282,7 @@ export const configureUsersModule = async ({
|
|
|
276
282
|
offset?: number;
|
|
277
283
|
}): Promise<Array<User>> {
|
|
278
284
|
const defaultSort = [{ key: 'created', value: SortDirection.ASC }] as SortOption[];
|
|
279
|
-
const selector = buildFindSelector(query);
|
|
285
|
+
const selector = buildFindSelector({ ...query });
|
|
280
286
|
|
|
281
287
|
if (query.queryString) {
|
|
282
288
|
return Users.find(selector, {
|
|
@@ -295,9 +301,7 @@ export const configureUsersModule = async ({
|
|
|
295
301
|
},
|
|
296
302
|
|
|
297
303
|
async userExists({ userId }: { userId: string }): Promise<boolean> {
|
|
298
|
-
const
|
|
299
|
-
selector.deleted = null; // skip deleted users when checked for existance!
|
|
300
|
-
const userCount = await Users.countDocuments(selector, { limit: 1 });
|
|
304
|
+
const userCount = await Users.countDocuments({ _id: userId, deleted: null }, { limit: 1 });
|
|
301
305
|
return userCount === 1;
|
|
302
306
|
},
|
|
303
307
|
|
|
@@ -359,6 +363,7 @@ export const configureUsersModule = async ({
|
|
|
359
363
|
_id: normalizedUserData._id || generateDbObjectId(),
|
|
360
364
|
roles: roles || [],
|
|
361
365
|
initialPassword: Boolean(initialPassword),
|
|
366
|
+
services,
|
|
362
367
|
emails: email ? [{ address: email, verified: false }] : [],
|
|
363
368
|
created: new Date(),
|
|
364
369
|
};
|
|
@@ -409,7 +414,7 @@ export const configureUsersModule = async ({
|
|
|
409
414
|
plainPassword: string,
|
|
410
415
|
): Promise<boolean> {
|
|
411
416
|
if (bcryptHash) {
|
|
412
|
-
const password = await sha256
|
|
417
|
+
const password = await sha256(plainPassword);
|
|
413
418
|
return bcrypt.compare(password, bcryptHash);
|
|
414
419
|
}
|
|
415
420
|
if (pbkdf2SaltAndHash) {
|
|
@@ -450,9 +455,9 @@ export const configureUsersModule = async ({
|
|
|
450
455
|
async sendResetPasswordEmail(userId: string, email: string, isEnrollment?: boolean): Promise<void> {
|
|
451
456
|
const plainToken = crypto.randomUUID();
|
|
452
457
|
const resetToken = {
|
|
453
|
-
token: await sha256
|
|
458
|
+
token: await sha256(plainToken),
|
|
454
459
|
address: email,
|
|
455
|
-
when: new Date()
|
|
460
|
+
when: new Date(),
|
|
456
461
|
};
|
|
457
462
|
|
|
458
463
|
await Users.updateOne(
|
|
@@ -475,9 +480,9 @@ export const configureUsersModule = async ({
|
|
|
475
480
|
async sendVerificationEmail(userId: string, email: string): Promise<void> {
|
|
476
481
|
const plainToken = crypto.randomUUID();
|
|
477
482
|
const verificationToken = {
|
|
478
|
-
token: await sha256
|
|
483
|
+
token: await sha256(plainToken),
|
|
479
484
|
address: email,
|
|
480
|
-
when: new Date()
|
|
485
|
+
when: new Date(),
|
|
481
486
|
};
|
|
482
487
|
|
|
483
488
|
await Users.updateOne(
|
|
@@ -601,42 +606,38 @@ export const configureUsersModule = async ({
|
|
|
601
606
|
return user;
|
|
602
607
|
},
|
|
603
608
|
|
|
604
|
-
|
|
605
|
-
const
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
609
|
+
markDeleted: async (userId: string): Promise<User> => {
|
|
610
|
+
const user = await Users.findOneAndUpdate(
|
|
611
|
+
{ _id: userId },
|
|
612
|
+
{
|
|
613
|
+
$set: {
|
|
614
|
+
username: `deleted-${Date.now()}`,
|
|
615
|
+
deleted: new Date(),
|
|
616
|
+
emails: [],
|
|
617
|
+
roles: [],
|
|
618
|
+
profile: null,
|
|
619
|
+
lastBillingAddress: null,
|
|
620
|
+
services: {},
|
|
621
|
+
pushSubscriptions: [],
|
|
622
|
+
avatarId: null,
|
|
623
|
+
initialPassword: false,
|
|
624
|
+
lastContact: null,
|
|
625
|
+
lastLogin: null,
|
|
619
626
|
},
|
|
620
|
-
];
|
|
621
|
-
});
|
|
622
|
-
|
|
623
|
-
const obfuscatedUsername = existingUser.username ? `${existingUser.username}-${uuid}` : null;
|
|
624
|
-
|
|
625
|
-
Users.updateOne(userFilter, {
|
|
626
|
-
$set: {
|
|
627
|
-
emails: obfuscatedEmails,
|
|
628
|
-
username: obfuscatedUsername,
|
|
629
|
-
services: {},
|
|
630
627
|
},
|
|
631
|
-
|
|
628
|
+
{ returnDocument: 'after' },
|
|
629
|
+
);
|
|
632
630
|
|
|
633
|
-
const user = await Users.findOneAndDelete(userFilter);
|
|
634
631
|
await emit('USER_REMOVE', {
|
|
635
|
-
user
|
|
632
|
+
user,
|
|
636
633
|
});
|
|
637
634
|
return user;
|
|
638
635
|
},
|
|
639
636
|
|
|
637
|
+
deletePermanently: async ({ userId }: { userId: string }): Promise<User> => {
|
|
638
|
+
return Users.findOneAndDelete({ _id: userId });
|
|
639
|
+
},
|
|
640
|
+
|
|
640
641
|
updateProfile: async (
|
|
641
642
|
userId: string,
|
|
642
643
|
updatedData: { profile?: UserProfile; meta?: any },
|
|
@@ -679,6 +680,8 @@ export const configureUsersModule = async ({
|
|
|
679
680
|
const userFilter = generateDbFilterById(_id);
|
|
680
681
|
const user = await Users.findOne(userFilter, {});
|
|
681
682
|
|
|
683
|
+
if (!lastBillingAddress) return user;
|
|
684
|
+
|
|
682
685
|
const modifier = {
|
|
683
686
|
$set: {
|
|
684
687
|
lastBillingAddress,
|
|
@@ -701,9 +704,12 @@ export const configureUsersModule = async ({
|
|
|
701
704
|
returnDocument: 'after',
|
|
702
705
|
});
|
|
703
706
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
+
if (updatedUser) {
|
|
708
|
+
await emit('USER_UPDATE_BILLING_ADDRESS', {
|
|
709
|
+
user: removeConfidentialServiceHashes(updatedUser),
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
|
|
707
713
|
return updatedUser;
|
|
708
714
|
},
|
|
709
715
|
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { TimestampFields, Address, Contact, mongodb } from '@unchainedshop/mongodb';
|
|
2
|
+
import { DateFilterInput } from '@unchainedshop/utils';
|
|
2
3
|
|
|
3
4
|
export interface PushSubscription {
|
|
4
5
|
_id: string;
|
|
@@ -55,7 +56,7 @@ export interface PushSubscriptionObject {
|
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
export type User = {
|
|
58
|
-
_id
|
|
59
|
+
_id: string;
|
|
59
60
|
deleted?: Date;
|
|
60
61
|
avatarId?: string;
|
|
61
62
|
emails: Array<Email>;
|
|
@@ -76,6 +77,8 @@ export type User = {
|
|
|
76
77
|
export type UserQuery = mongodb.Filter<User> & {
|
|
77
78
|
includeGuests?: boolean;
|
|
78
79
|
queryString?: string;
|
|
80
|
+
emailVerified?: boolean;
|
|
81
|
+
lastLogin?: DateFilterInput;
|
|
79
82
|
};
|
|
80
83
|
|
|
81
84
|
export interface WebAuthnCredentialsCreationRequest {
|
package/src/users-index.ts
CHANGED
package/tests/mock/user-mock.ts
CHANGED
|
@@ -2,7 +2,7 @@ export default {
|
|
|
2
2
|
_id: 'PKve0k9fLCUzn2EUi',
|
|
3
3
|
guest: false,
|
|
4
4
|
initialPassword: false,
|
|
5
|
-
lastBillingAddress:
|
|
5
|
+
lastBillingAddress: null,
|
|
6
6
|
profile: {
|
|
7
7
|
address: {
|
|
8
8
|
firstName: null,
|
|
@@ -65,9 +65,8 @@ export default {
|
|
|
65
65
|
remotePort: '42978',
|
|
66
66
|
userAgent:
|
|
67
67
|
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36',
|
|
68
|
-
locale: '
|
|
68
|
+
locale: 'de-CH',
|
|
69
69
|
countryCode: 'CH',
|
|
70
70
|
},
|
|
71
71
|
updated: new Date('2022-11-30T11:02:19.624Z'),
|
|
72
|
-
updatedBy: 'PKve0k9fLCUzn2EUi',
|
|
73
72
|
};
|
package/tsconfig.json
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"extends": "../shared/base.tsconfig.json",
|
|
3
3
|
"compilerOptions": {
|
|
4
|
-
"
|
|
5
|
-
"
|
|
4
|
+
"declarationDir": "./lib",
|
|
5
|
+
"rootDir": "./src",
|
|
6
|
+
"outDir": "./lib"
|
|
6
7
|
},
|
|
7
|
-
"exclude": ["**/*.test.ts", "**/*.test.js", "tests"]
|
|
8
|
-
|
|
9
|
-
"./src"
|
|
10
|
-
]
|
|
11
|
-
}
|
|
8
|
+
"exclude": ["**/*.test.ts", "**/*.test.js", "tests", "lib"]
|
|
9
|
+
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { UnchainedCore } from '@unchainedshop/core';
|
|
2
|
-
export type MigrateUserDataService = (userIdBeforeLogin: any, userId: any, unchainedAPI: UnchainedCore) => Promise<void>;
|
|
3
|
-
export declare const migrateUserDataService: MigrateUserDataService;
|
|
4
|
-
//# sourceMappingURL=migrateUserDataService.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"migrateUserDataService.d.ts","sourceRoot":"","sources":["../../src/services/migrateUserDataService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,MAAM,MAAM,sBAAsB,GAAG,CACnC,iBAAiB,KAAA,EACjB,MAAM,KAAA,EACN,YAAY,EAAE,aAAa,KACxB,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,eAAO,MAAM,sBAAsB,EAAE,sBA2BpC,CAAC"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { userSettings } from '../users-settings.js';
|
|
2
|
-
export const migrateUserDataService = async (userIdBeforeLogin, userId, unchainedAPI) => {
|
|
3
|
-
const user = await unchainedAPI.modules.users.findUserById(userId);
|
|
4
|
-
const userBeforeLogin = await unchainedAPI.modules.users.findUserById(userIdBeforeLogin);
|
|
5
|
-
await unchainedAPI.services.orders.migrateOrderCarts({
|
|
6
|
-
fromUserId: userIdBeforeLogin,
|
|
7
|
-
toUserId: userId,
|
|
8
|
-
shouldMerge: userSettings.mergeUserCartsOnLogin,
|
|
9
|
-
countryContext: userBeforeLogin.lastLogin?.countryCode || user.lastLogin?.countryCode,
|
|
10
|
-
}, unchainedAPI);
|
|
11
|
-
await unchainedAPI.services.bookmarks.migrateBookmarks({
|
|
12
|
-
fromUserId: userIdBeforeLogin,
|
|
13
|
-
toUserId: userId,
|
|
14
|
-
shouldMerge: userSettings.mergeUserCartsOnLogin,
|
|
15
|
-
countryContext: userBeforeLogin.lastLogin?.countryCode || user.lastLogin?.countryCode,
|
|
16
|
-
}, unchainedAPI);
|
|
17
|
-
};
|
|
18
|
-
//# sourceMappingURL=migrateUserDataService.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"migrateUserDataService.js","sourceRoot":"","sources":["../../src/services/migrateUserDataService.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAQpD,MAAM,CAAC,MAAM,sBAAsB,GAA2B,KAAK,EACjE,iBAAiB,EACjB,MAAM,EACN,YAAY,EACZ,EAAE;IACF,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IACnE,MAAM,eAAe,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;IAEzF,MAAM,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,iBAAiB,CAClD;QACE,UAAU,EAAE,iBAAiB;QAC7B,QAAQ,EAAE,MAAM;QAChB,WAAW,EAAE,YAAY,CAAC,qBAAqB;QAC/C,cAAc,EAAE,eAAe,CAAC,SAAS,EAAE,WAAW,IAAI,IAAI,CAAC,SAAS,EAAE,WAAW;KACtF,EACD,YAAY,CACb,CAAC;IAEF,MAAM,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,gBAAgB,CACpD;QACE,UAAU,EAAE,iBAAiB;QAC7B,QAAQ,EAAE,MAAM;QAChB,WAAW,EAAE,YAAY,CAAC,qBAAqB;QAC/C,cAAc,EAAE,eAAe,CAAC,SAAS,EAAE,WAAW,IAAI,IAAI,CAAC,SAAS,EAAE,WAAW;KACtF,EACD,YAAY,CACb,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { File, FileServices, FilesModule } from '@unchainedshop/core-files';
|
|
2
|
-
import { UsersModule } from '../users-index.js';
|
|
3
|
-
export type UpdateUserAvatarAfterUploadService = (params: {
|
|
4
|
-
file: File;
|
|
5
|
-
}, context: {
|
|
6
|
-
modules: {
|
|
7
|
-
files: FilesModule;
|
|
8
|
-
users: UsersModule;
|
|
9
|
-
};
|
|
10
|
-
services: {
|
|
11
|
-
files: FileServices;
|
|
12
|
-
};
|
|
13
|
-
}) => Promise<void>;
|
|
14
|
-
export declare const updateUserAvatarAfterUploadService: UpdateUserAvatarAfterUploadService;
|
|
15
|
-
//# sourceMappingURL=updateUserAvatarAfterUploadService.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"updateUserAvatarAfterUploadService.d.ts","sourceRoot":"","sources":["../../src/services/updateUserAvatarAfterUploadService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE5E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,MAAM,kCAAkC,GAAG,CAC/C,MAAM,EAAE;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,EACtB,OAAO,EAAE;IACP,OAAO,EAAE;QAAE,KAAK,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,WAAW,CAAA;KAAE,CAAC;IACpD,QAAQ,EAAE;QAAE,KAAK,EAAE,YAAY,CAAA;KAAE,CAAC;CACnC,KACE,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,eAAO,MAAM,kCAAkC,EAAE,kCA6BhD,CAAC"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { log, LogLevel } from '@unchainedshop/logger';
|
|
2
|
-
export const updateUserAvatarAfterUploadService = async ({ file }, context) => {
|
|
3
|
-
const { modules, services } = context;
|
|
4
|
-
const { userId } = file.meta;
|
|
5
|
-
const files = await modules.files.findFiles({
|
|
6
|
-
_id: { $ne: file._id },
|
|
7
|
-
path: file.path,
|
|
8
|
-
'meta.userId': userId,
|
|
9
|
-
});
|
|
10
|
-
const fileIds = files.map((f) => f._id);
|
|
11
|
-
try {
|
|
12
|
-
if (fileIds?.length) {
|
|
13
|
-
await services.files.removeFiles({
|
|
14
|
-
fileIds,
|
|
15
|
-
}, context);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
catch (e) {
|
|
19
|
-
// cleanup error, not critical
|
|
20
|
-
log(`could not clean up all old avatars: ${e.message}`, { level: LogLevel.Warning });
|
|
21
|
-
}
|
|
22
|
-
await modules.users.updateAvatar(userId, file._id);
|
|
23
|
-
};
|
|
24
|
-
//# sourceMappingURL=updateUserAvatarAfterUploadService.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"updateUserAvatarAfterUploadService.js","sourceRoot":"","sources":["../../src/services/updateUserAvatarAfterUploadService.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAWtD,MAAM,CAAC,MAAM,kCAAkC,GAAuC,KAAK,EACzF,EAAE,IAAI,EAAE,EACR,OAAO,EACP,EAAE;IACF,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IACtC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,IAA0B,CAAC;IAEnD,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC;QAC1C,GAAG,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE;QACtB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,aAAa,EAAE,MAAM;KACtB,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAExC,IAAI,CAAC;QACH,IAAI,OAAO,EAAE,MAAM,EAAE,CAAC;YACpB,MAAM,QAAQ,CAAC,KAAK,CAAC,WAAW,CAC9B;gBACE,OAAO;aACR,EACD,OAAO,CACR,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,OAAO,CAAU,EAAE,CAAC;QACpB,8BAA8B;QAC9B,GAAG,CAAC,uCAAwC,CAAW,CAAC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IAClG,CAAC;IAED,MAAM,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;AACrD,CAAC,CAAC"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { UpdateUserAvatarAfterUploadService } from './updateUserAvatarAfterUploadService.js';
|
|
2
|
-
import { MigrateUserDataService } from './migrateUserDataService.js';
|
|
3
|
-
export interface UserServices {
|
|
4
|
-
updateUserAvatarAfterUpload: UpdateUserAvatarAfterUploadService;
|
|
5
|
-
migrateUserData: MigrateUserDataService;
|
|
6
|
-
}
|
|
7
|
-
export declare const userServices: UserServices;
|
|
8
|
-
//# sourceMappingURL=userServices.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"userServices.d.ts","sourceRoot":"","sources":["../../src/services/userServices.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,kCAAkC,EACnC,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAA0B,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAE7F,MAAM,WAAW,YAAY;IAC3B,2BAA2B,EAAE,kCAAkC,CAAC;IAChE,eAAe,EAAE,sBAAsB,CAAC;CACzC;AAED,eAAO,MAAM,YAAY,EAAE,YAG1B,CAAC"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { updateUserAvatarAfterUploadService, } from './updateUserAvatarAfterUploadService.js';
|
|
2
|
-
import { migrateUserDataService } from './migrateUserDataService.js';
|
|
3
|
-
export const userServices = {
|
|
4
|
-
updateUserAvatarAfterUpload: updateUserAvatarAfterUploadService,
|
|
5
|
-
migrateUserData: migrateUserDataService,
|
|
6
|
-
};
|
|
7
|
-
//# sourceMappingURL=userServices.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"userServices.js","sourceRoot":"","sources":["../../src/services/userServices.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kCAAkC,GAEnC,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAA0B,MAAM,6BAA6B,CAAC;AAO7F,MAAM,CAAC,MAAM,YAAY,GAAiB;IACxC,2BAA2B,EAAE,kCAAkC;IAC/D,eAAe,EAAE,sBAAsB;CACxC,CAAC"}
|
package/src/module/sha256.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { UnchainedCore } from '@unchainedshop/core';
|
|
2
|
-
import { userSettings } from '../users-settings.js';
|
|
3
|
-
|
|
4
|
-
export type MigrateUserDataService = (
|
|
5
|
-
userIdBeforeLogin,
|
|
6
|
-
userId,
|
|
7
|
-
unchainedAPI: UnchainedCore,
|
|
8
|
-
) => Promise<void>;
|
|
9
|
-
|
|
10
|
-
export const migrateUserDataService: MigrateUserDataService = async (
|
|
11
|
-
userIdBeforeLogin,
|
|
12
|
-
userId,
|
|
13
|
-
unchainedAPI,
|
|
14
|
-
) => {
|
|
15
|
-
const user = await unchainedAPI.modules.users.findUserById(userId);
|
|
16
|
-
const userBeforeLogin = await unchainedAPI.modules.users.findUserById(userIdBeforeLogin);
|
|
17
|
-
|
|
18
|
-
await unchainedAPI.services.orders.migrateOrderCarts(
|
|
19
|
-
{
|
|
20
|
-
fromUserId: userIdBeforeLogin,
|
|
21
|
-
toUserId: userId,
|
|
22
|
-
shouldMerge: userSettings.mergeUserCartsOnLogin,
|
|
23
|
-
countryContext: userBeforeLogin.lastLogin?.countryCode || user.lastLogin?.countryCode,
|
|
24
|
-
},
|
|
25
|
-
unchainedAPI,
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
await unchainedAPI.services.bookmarks.migrateBookmarks(
|
|
29
|
-
{
|
|
30
|
-
fromUserId: userIdBeforeLogin,
|
|
31
|
-
toUserId: userId,
|
|
32
|
-
shouldMerge: userSettings.mergeUserCartsOnLogin,
|
|
33
|
-
countryContext: userBeforeLogin.lastLogin?.countryCode || user.lastLogin?.countryCode,
|
|
34
|
-
},
|
|
35
|
-
unchainedAPI,
|
|
36
|
-
);
|
|
37
|
-
};
|