@unchainedshop/core-users 3.0.0-alpha7 → 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 +57 -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 +77 -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
|
|
|
@@ -410,7 +414,7 @@ export const configureUsersModule = async ({
|
|
|
410
414
|
plainPassword: string,
|
|
411
415
|
): Promise<boolean> {
|
|
412
416
|
if (bcryptHash) {
|
|
413
|
-
const password = await sha256
|
|
417
|
+
const password = await sha256(plainPassword);
|
|
414
418
|
return bcrypt.compare(password, bcryptHash);
|
|
415
419
|
}
|
|
416
420
|
if (pbkdf2SaltAndHash) {
|
|
@@ -451,9 +455,9 @@ export const configureUsersModule = async ({
|
|
|
451
455
|
async sendResetPasswordEmail(userId: string, email: string, isEnrollment?: boolean): Promise<void> {
|
|
452
456
|
const plainToken = crypto.randomUUID();
|
|
453
457
|
const resetToken = {
|
|
454
|
-
token: await sha256
|
|
458
|
+
token: await sha256(plainToken),
|
|
455
459
|
address: email,
|
|
456
|
-
when: new Date()
|
|
460
|
+
when: new Date(),
|
|
457
461
|
};
|
|
458
462
|
|
|
459
463
|
await Users.updateOne(
|
|
@@ -476,9 +480,9 @@ export const configureUsersModule = async ({
|
|
|
476
480
|
async sendVerificationEmail(userId: string, email: string): Promise<void> {
|
|
477
481
|
const plainToken = crypto.randomUUID();
|
|
478
482
|
const verificationToken = {
|
|
479
|
-
token: await sha256
|
|
483
|
+
token: await sha256(plainToken),
|
|
480
484
|
address: email,
|
|
481
|
-
when: new Date()
|
|
485
|
+
when: new Date(),
|
|
482
486
|
};
|
|
483
487
|
|
|
484
488
|
await Users.updateOne(
|
|
@@ -602,42 +606,38 @@ export const configureUsersModule = async ({
|
|
|
602
606
|
return user;
|
|
603
607
|
},
|
|
604
608
|
|
|
605
|
-
|
|
606
|
-
const
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
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,
|
|
620
626
|
},
|
|
621
|
-
];
|
|
622
|
-
});
|
|
623
|
-
|
|
624
|
-
const obfuscatedUsername = existingUser.username ? `${existingUser.username}-${uuid}` : null;
|
|
625
|
-
|
|
626
|
-
Users.updateOne(userFilter, {
|
|
627
|
-
$set: {
|
|
628
|
-
emails: obfuscatedEmails,
|
|
629
|
-
username: obfuscatedUsername,
|
|
630
|
-
services: {},
|
|
631
627
|
},
|
|
632
|
-
|
|
628
|
+
{ returnDocument: 'after' },
|
|
629
|
+
);
|
|
633
630
|
|
|
634
|
-
const user = await Users.findOneAndDelete(userFilter);
|
|
635
631
|
await emit('USER_REMOVE', {
|
|
636
|
-
user
|
|
632
|
+
user,
|
|
637
633
|
});
|
|
638
634
|
return user;
|
|
639
635
|
},
|
|
640
636
|
|
|
637
|
+
deletePermanently: async ({ userId }: { userId: string }): Promise<User> => {
|
|
638
|
+
return Users.findOneAndDelete({ _id: userId });
|
|
639
|
+
},
|
|
640
|
+
|
|
641
641
|
updateProfile: async (
|
|
642
642
|
userId: string,
|
|
643
643
|
updatedData: { profile?: UserProfile; meta?: any },
|
|
@@ -680,6 +680,8 @@ export const configureUsersModule = async ({
|
|
|
680
680
|
const userFilter = generateDbFilterById(_id);
|
|
681
681
|
const user = await Users.findOne(userFilter, {});
|
|
682
682
|
|
|
683
|
+
if (!lastBillingAddress) return user;
|
|
684
|
+
|
|
683
685
|
const modifier = {
|
|
684
686
|
$set: {
|
|
685
687
|
lastBillingAddress,
|
|
@@ -702,9 +704,12 @@ export const configureUsersModule = async ({
|
|
|
702
704
|
returnDocument: 'after',
|
|
703
705
|
});
|
|
704
706
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
707
|
+
if (updatedUser) {
|
|
708
|
+
await emit('USER_UPDATE_BILLING_ADDRESS', {
|
|
709
|
+
user: removeConfidentialServiceHashes(updatedUser),
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
|
|
708
713
|
return updatedUser;
|
|
709
714
|
},
|
|
710
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
|
-
};
|