@unchainedshop/core-users 2.13.0 → 3.0.0-alpha2
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/db/UsersCollection.d.ts.map +1 -1
- package/lib/db/UsersCollection.js +0 -8
- package/lib/db/UsersCollection.js.map +1 -1
- package/lib/db/WebAuthnCredentialsCreationRequestsCollection.d.ts +8 -0
- package/lib/db/WebAuthnCredentialsCreationRequestsCollection.d.ts.map +1 -0
- package/lib/db/WebAuthnCredentialsCreationRequestsCollection.js +13 -0
- package/lib/db/WebAuthnCredentialsCreationRequestsCollection.js.map +1 -0
- package/lib/module/configureUsersModule.d.ts +88 -2
- package/lib/module/configureUsersModule.d.ts.map +1 -1
- package/lib/module/configureUsersModule.js +277 -47
- package/lib/module/configureUsersModule.js.map +1 -1
- package/lib/module/configureUsersWebAuthnModule.d.ts +25 -0
- package/lib/module/configureUsersWebAuthnModule.d.ts.map +1 -0
- package/lib/module/configureUsersWebAuthnModule.js +148 -0
- package/lib/module/configureUsersWebAuthnModule.js.map +1 -0
- package/lib/module/pbkdf2.d.ts +4 -0
- package/lib/module/pbkdf2.d.ts.map +1 -0
- package/lib/module/pbkdf2.js +27 -0
- package/lib/module/pbkdf2.js.map +1 -0
- package/lib/module/sha256.d.ts +2 -0
- package/lib/module/sha256.d.ts.map +1 -0
- package/lib/module/sha256.js +6 -0
- package/lib/module/sha256.js.map +1 -0
- package/lib/services/migrateUserDataService.d.ts +3 -0
- package/lib/services/migrateUserDataService.d.ts.map +1 -0
- package/lib/services/migrateUserDataService.js +18 -0
- package/lib/services/migrateUserDataService.js.map +1 -0
- package/lib/services/userServices.d.ts +6 -2
- package/lib/services/userServices.d.ts.map +1 -1
- package/lib/services/userServices.js +2 -0
- package/lib/services/userServices.js.map +1 -1
- package/lib/users-index.d.ts +1 -0
- package/lib/users-index.d.ts.map +1 -1
- package/lib/users-index.js +1 -0
- package/lib/users-index.js.map +1 -1
- package/lib/users-settings.d.ts +3 -0
- package/lib/users-settings.d.ts.map +1 -0
- package/lib/users-settings.js +51 -0
- package/lib/users-settings.js.map +1 -0
- package/package.json +9 -7
- package/src/db/UsersCollection.ts +0 -9
- package/src/db/WebAuthnCredentialsCreationRequestsCollection.ts +20 -0
- package/src/module/configureUsersModule.ts +411 -62
- package/src/module/configureUsersWebAuthnModule.ts +201 -0
- package/src/module/pbkdf2.ts +39 -0
- package/src/module/sha256.ts +5 -0
- package/src/services/migrateUserDataService.ts +31 -0
- package/src/services/userServices.ts +3 -2
- package/src/users-index.ts +1 -0
- package/src/users-settings.ts +71 -0
- package/tests/mock/user-mock.ts +0 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UsersCollection.d.ts","sourceRoot":"","sources":["../../src/db/UsersCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAkB,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAEpD,eAAO,MAAM,eAAe,OAAc,OAAO,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"UsersCollection.d.ts","sourceRoot":"","sources":["../../src/db/UsersCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAkB,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAEpD,eAAO,MAAM,eAAe,OAAc,OAAO,CAAC,EAAE,sCA4FnD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UsersCollection.js","sourceRoot":"","sources":["../../src/db/UsersCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAGjE,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAAE,EAAc,EAAE,EAAE;IACtD,MAAM,KAAK,GAAG,EAAE,CAAC,UAAU,CAAO,OAAO,CAAC,CAAC;IAE3C,MAAM,cAAc,CAAO,KAAK,EAAE;QAChC;YACE,KAAK,EAAE;gBACL,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,CAAC;gBACV,KAAK,EAAE,CAAC;aACT;YACD,OAAO,EAAE,EAAE;SACZ;QACD;YACE,KAAK,EAAE;gBACL,KAAK,EAAE,CAAC;aACT;YACD,OAAO,EAAE;gBACP,MAAM,EAAE,IAAI;aACb;SACF;QACD;YACE,KAAK,EAAE;gBACL,OAAO,EAAE,CAAC;aACX;YACD,OAAO,EAAE,EAAE;SACZ;QACD;YACE,KAAK,EAAE;gBACL,QAAQ,EAAE,CAAC;aACZ;YACD,OAAO,EAAE;gBACP,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,IAAI;aACb;SACF;QACD;YACE,KAAK,EAAE;gBACL,gBAAgB,EAAE,CAAC;aACb;YACR,OAAO,EAAE;gBACP,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,IAAI;aACb;SACF;QAED;YACE,KAAK,EAAE;gBACL,yCAAyC,EAAE,CAAC;aACtC;YACR,OAAO,EAAE;gBACP,MAAM,EAAE,IAAI;aACb;SACF;QAED;YACE,KAAK,EAAE;gBACL,+BAA+B,EAAE,CAAC;aAC5B;YACR,OAAO,EAAE;gBACP,MAAM,EAAE,IAAI;aACb;SACF;QAED;YACE,KAAK,EAAE;gBACL,
|
|
1
|
+
{"version":3,"file":"UsersCollection.js","sourceRoot":"","sources":["../../src/db/UsersCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAGjE,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAAE,EAAc,EAAE,EAAE;IACtD,MAAM,KAAK,GAAG,EAAE,CAAC,UAAU,CAAO,OAAO,CAAC,CAAC;IAE3C,MAAM,cAAc,CAAO,KAAK,EAAE;QAChC;YACE,KAAK,EAAE;gBACL,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,CAAC;gBACV,KAAK,EAAE,CAAC;aACT;YACD,OAAO,EAAE,EAAE;SACZ;QACD;YACE,KAAK,EAAE;gBACL,KAAK,EAAE,CAAC;aACT;YACD,OAAO,EAAE;gBACP,MAAM,EAAE,IAAI;aACb;SACF;QACD;YACE,KAAK,EAAE;gBACL,OAAO,EAAE,CAAC;aACX;YACD,OAAO,EAAE,EAAE;SACZ;QACD;YACE,KAAK,EAAE;gBACL,QAAQ,EAAE,CAAC;aACZ;YACD,OAAO,EAAE;gBACP,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,IAAI;aACb;SACF;QACD;YACE,KAAK,EAAE;gBACL,gBAAgB,EAAE,CAAC;aACb;YACR,OAAO,EAAE;gBACP,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,IAAI;aACb;SACF;QAED;YACE,KAAK,EAAE;gBACL,yCAAyC,EAAE,CAAC;aACtC;YACR,OAAO,EAAE;gBACP,MAAM,EAAE,IAAI;aACb;SACF;QAED;YACE,KAAK,EAAE;gBACL,+BAA+B,EAAE,CAAC;aAC5B;YACR,OAAO,EAAE;gBACP,MAAM,EAAE,IAAI;aACb;SACF;QAED;YACE,KAAK,EAAE;gBACL,GAAG,EAAE,MAAM;gBACX,QAAQ,EAAE,MAAM;gBAChB,gBAAgB,EAAE,MAAM;gBACxB,qBAAqB,EAAE,MAAM;gBAC7B,8BAA8B,EAAE,MAAM;gBACtC,6BAA6B,EAAE,MAAM;gBACrC,4BAA4B,EAAE,MAAM;gBACpC,gCAAgC,EAAE,MAAM;gBACxC,iCAAiC,EAAE,MAAM;aACnC;YACR,OAAO,EAAE;gBACP,OAAO,EAAE;oBACP,GAAG,EAAE,CAAC;oBACN,gBAAgB,EAAE,CAAC;oBACnB,qBAAqB,EAAE,CAAC;oBACxB,8BAA8B,EAAE,CAAC;oBACjC,6BAA6B,EAAE,CAAC;oBAChC,4BAA4B,EAAE,CAAC;oBAC/B,gCAAgC,EAAE,CAAC;oBACnC,iCAAiC,EAAE,CAAC;iBACrC;gBACD,IAAI,EAAE,sBAAsB;aAC7B;SACF;KACF,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC;AACf,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { WebAuthnCredentialsCreationRequest } from '@unchainedshop/types/user.js';
|
|
2
|
+
import { mongodb } from '@unchainedshop/mongodb';
|
|
3
|
+
type Collection = WebAuthnCredentialsCreationRequest & {
|
|
4
|
+
_id: number;
|
|
5
|
+
};
|
|
6
|
+
export declare const WebAuthnCredentialsCreationRequestsCollection: (db: mongodb.Db) => Promise<mongodb.Collection<Collection>>;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=WebAuthnCredentialsCreationRequestsCollection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebAuthnCredentialsCreationRequestsCollection.d.ts","sourceRoot":"","sources":["../../src/db/WebAuthnCredentialsCreationRequestsCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kCAAkC,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,EAAE,OAAO,EAAkB,MAAM,wBAAwB,CAAC;AAEjE,KAAK,UAAU,GAAG,kCAAkC,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE,eAAO,MAAM,6CAA6C,OAAc,OAAO,CAAC,EAAE,4CAcjF,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { buildDbIndexes } from '@unchainedshop/mongodb';
|
|
2
|
+
export const WebAuthnCredentialsCreationRequestsCollection = async (db) => {
|
|
3
|
+
const WebAuthnCredentialsCreationRequests = db.collection('accounts_webauthn_credentials_creation_requests');
|
|
4
|
+
await buildDbIndexes(WebAuthnCredentialsCreationRequests, [
|
|
5
|
+
{
|
|
6
|
+
index: {
|
|
7
|
+
username: 1,
|
|
8
|
+
},
|
|
9
|
+
},
|
|
10
|
+
]);
|
|
11
|
+
return WebAuthnCredentialsCreationRequests;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=WebAuthnCredentialsCreationRequestsCollection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebAuthnCredentialsCreationRequestsCollection.js","sourceRoot":"","sources":["../../src/db/WebAuthnCredentialsCreationRequestsCollection.ts"],"names":[],"mappings":"AACA,OAAO,EAAW,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAIjE,MAAM,CAAC,MAAM,6CAA6C,GAAG,KAAK,EAAE,EAAc,EAAE,EAAE;IACpF,MAAM,mCAAmC,GAAG,EAAE,CAAC,UAAU,CACvD,iDAAiD,CAClD,CAAC;IAEF,MAAM,cAAc,CAAa,mCAAmC,EAAE;QACpE;YACE,KAAK,EAAE;gBACL,QAAQ,EAAE,CAAC;aACZ;SACF;KACF,CAAC,CAAC;IAEH,OAAO,mCAAmC,CAAC;AAC7C,CAAC,CAAC"}
|
|
@@ -1,7 +1,93 @@
|
|
|
1
|
+
import localePkg from 'locale';
|
|
2
|
+
import { Address, Contact } from '@unchainedshop/types/common.js';
|
|
1
3
|
import { ModuleInput } from '@unchainedshop/types/core.js';
|
|
2
|
-
import { User, UserQuery,
|
|
4
|
+
import { User, UserQuery, Email, UserLastLogin, UserProfile, UserSettingsOptions, UserData } from '@unchainedshop/types/user.js';
|
|
3
5
|
import { mongodb } from '@unchainedshop/mongodb';
|
|
6
|
+
import { SortOption } from '@unchainedshop/types/api.js';
|
|
4
7
|
export declare const removeConfidentialServiceHashes: (rawUser: User) => User;
|
|
5
8
|
export declare const buildFindSelector: ({ includeGuests, queryString, ...rest }: UserQuery) => mongodb.Filter<User>;
|
|
6
|
-
export declare const configureUsersModule: ({ db, migrationRepository, }: ModuleInput<
|
|
9
|
+
export declare const configureUsersModule: ({ db, options, migrationRepository, }: ModuleInput<UserSettingsOptions>) => Promise<{
|
|
10
|
+
webAuthn: {
|
|
11
|
+
findMDSMetadataForAAGUID: (aaguid: any) => Promise<any>;
|
|
12
|
+
createCredentialCreationOptions: (origin: any, username: any, extensionOptions: any) => Promise<Omit<import("fido2-lib").PublicKeyCredentialCreationOptions, "challenge" | "requestId"> & {
|
|
13
|
+
challenge: string;
|
|
14
|
+
requestId: number;
|
|
15
|
+
}>;
|
|
16
|
+
createCredentialRequestOptions: (origin: any, username: any, extensionOptions: any) => Promise<Omit<import("fido2-lib").PublicKeyCredentialRequestOptions, "challenge" | "requestId"> & {
|
|
17
|
+
challenge: string;
|
|
18
|
+
requestId: number;
|
|
19
|
+
}>;
|
|
20
|
+
verifyCredentialCreation: (username: any, credentials: any) => Promise<{
|
|
21
|
+
publicKey: any;
|
|
22
|
+
counter: any;
|
|
23
|
+
id: any;
|
|
24
|
+
aaguid: string;
|
|
25
|
+
created: Date;
|
|
26
|
+
}>;
|
|
27
|
+
verifyCredentialRequest: (userPublicKeys: any, username: any, credentials: any) => Promise<{
|
|
28
|
+
userHandle: any;
|
|
29
|
+
}>;
|
|
30
|
+
};
|
|
31
|
+
count(query: UserQuery): Promise<number>;
|
|
32
|
+
findUserById(userId: string): Promise<User>;
|
|
33
|
+
findUserByUsername(username: string): Promise<User>;
|
|
34
|
+
findUserByEmail(email: string): Promise<User>;
|
|
35
|
+
findUnverifiedEmailToken(plainToken: string): Promise<{
|
|
36
|
+
userId: string;
|
|
37
|
+
address: string;
|
|
38
|
+
when: Date;
|
|
39
|
+
}>;
|
|
40
|
+
verifyEmail(userId: string, address: string): Promise<void>;
|
|
41
|
+
findUserByResetToken(plainToken: string): Promise<User>;
|
|
42
|
+
findUserByToken(plainToken?: string): Promise<User>;
|
|
43
|
+
findUser(query: UserQuery & {
|
|
44
|
+
sort?: Array<SortOption>;
|
|
45
|
+
}, findOptions?: mongodb.FindOptions): Promise<User>;
|
|
46
|
+
findUsers({ limit, offset, ...query }: UserQuery & {
|
|
47
|
+
sort?: Array<SortOption>;
|
|
48
|
+
limit?: number;
|
|
49
|
+
offset?: number;
|
|
50
|
+
}): Promise<Array<User>>;
|
|
51
|
+
userExists({ userId }: {
|
|
52
|
+
userId: string;
|
|
53
|
+
}): Promise<boolean>;
|
|
54
|
+
primaryEmail(user: User): Email;
|
|
55
|
+
userLocale(user: User): localePkg.Locale;
|
|
56
|
+
createUser({ password, email, username, initialPassword, roles, webAuthnPublicKeyCredentials, ...userData }: UserData, { skipMessaging, skipPasswordEnrollment, }?: {
|
|
57
|
+
skipMessaging?: boolean;
|
|
58
|
+
skipPasswordEnrollment?: boolean;
|
|
59
|
+
}): Promise<string>;
|
|
60
|
+
hashPassword(password: any): Promise<{
|
|
61
|
+
pbkdf2: string;
|
|
62
|
+
}>;
|
|
63
|
+
verifyPassword({ bcrypt: bcryptHash, pbkdf2: pbkdf2SaltAndHash }: {
|
|
64
|
+
bcrypt?: string;
|
|
65
|
+
pbkdf2?: string;
|
|
66
|
+
}, plainPassword: string): Promise<boolean>;
|
|
67
|
+
addEmail(userId: string, address: string): Promise<void>;
|
|
68
|
+
removeEmail(userId: string, address: string): Promise<void>;
|
|
69
|
+
sendResetPasswordEmail(userId: string, email: string, isEnrollment?: boolean): Promise<void>;
|
|
70
|
+
sendVerificationEmail(userId: string, email: string): Promise<void>;
|
|
71
|
+
addRoles: (userId: string, roles: Array<string>) => Promise<number>;
|
|
72
|
+
setUsername(userId: string, username: string): Promise<void>;
|
|
73
|
+
setPassword(userId: string, plainPassword: string): Promise<void>;
|
|
74
|
+
updateAvatar: (_id: string, fileId: string) => Promise<User>;
|
|
75
|
+
updateGuest: (user: User, guest: boolean) => Promise<void>;
|
|
76
|
+
updateHeartbeat: (userId: string, lastLogin: UserLastLogin) => Promise<User>;
|
|
77
|
+
delete: (userId: string) => Promise<User>;
|
|
78
|
+
updateProfile: (userId: string, updatedData: {
|
|
79
|
+
profile?: UserProfile;
|
|
80
|
+
meta?: any;
|
|
81
|
+
}) => Promise<User>;
|
|
82
|
+
updateLastBillingAddress: (_id: string, lastBillingAddress: Address) => Promise<User>;
|
|
83
|
+
updateLastContact: (_id: string, lastContact: Contact) => Promise<User>;
|
|
84
|
+
updateRoles: (_id: string, roles: Array<string>) => Promise<User>;
|
|
85
|
+
updateTags: (_id: string, tags: Array<string>) => Promise<User>;
|
|
86
|
+
updateUser: (selector: mongodb.Filter<User>, modifier: mongodb.UpdateFilter<User>, updateOptions?: mongodb.FindOneAndUpdateOptions) => Promise<User>;
|
|
87
|
+
addPushSubscription: (userId: string, subscription: any, subscriptionOptions?: {
|
|
88
|
+
userAgent: string;
|
|
89
|
+
unsubscribeFromOtherUsers: boolean;
|
|
90
|
+
}) => Promise<void>;
|
|
91
|
+
removePushSubscription: (userId: string, p256dh: string) => Promise<void>;
|
|
92
|
+
}>;
|
|
7
93
|
//# sourceMappingURL=configureUsersModule.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configureUsersModule.d.ts","sourceRoot":"","sources":["../../src/module/configureUsersModule.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"configureUsersModule.d.ts","sourceRoot":"","sources":["../../src/module/configureUsersModule.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,21 +1,29 @@
|
|
|
1
1
|
import localePkg from 'locale';
|
|
2
|
-
import
|
|
2
|
+
import bcrypt from 'bcryptjs';
|
|
3
3
|
import { emit, registerEvents } from '@unchainedshop/events';
|
|
4
|
-
import { generateDbFilterById, buildSortOptions } from '@unchainedshop/mongodb';
|
|
4
|
+
import { generateDbFilterById, buildSortOptions, generateDbObjectId, } from '@unchainedshop/mongodb';
|
|
5
5
|
import { systemLocale } from '@unchainedshop/utils';
|
|
6
6
|
import { FileDirector } from '@unchainedshop/file-upload';
|
|
7
7
|
import { SortDirection } from '@unchainedshop/types/api.js';
|
|
8
|
-
import { v4 as uuidv4 } from 'uuid';
|
|
9
8
|
import { UsersCollection } from '../db/UsersCollection.js';
|
|
10
9
|
import addMigrations from './addMigrations.js';
|
|
10
|
+
import { userSettings } from '../users-settings.js';
|
|
11
|
+
import { configureUsersWebAuthnModule } from './configureUsersWebAuthnModule.js';
|
|
12
|
+
import * as pbkdf2 from './pbkdf2.js';
|
|
13
|
+
import * as sha256 from './sha256.js';
|
|
11
14
|
const { Locale } = localePkg;
|
|
12
15
|
const USER_EVENTS = [
|
|
16
|
+
'USER_ACCOUNT_ACTION',
|
|
17
|
+
'USER_CREATE',
|
|
18
|
+
'USER_ADD_ROLES',
|
|
13
19
|
'USER_UPDATE',
|
|
14
20
|
'USER_UPDATE_PROFILE',
|
|
15
|
-
'USER_ADD_ROLES',
|
|
16
21
|
'USER_UPDATE_ROLE',
|
|
17
22
|
'USER_UPDATE_TAGS',
|
|
18
23
|
'USER_UPDATE_AVATAR',
|
|
24
|
+
'USER_UPDATE_GUEST',
|
|
25
|
+
'USER_UPDATE_USERNAME',
|
|
26
|
+
'USER_UPDATE_PASSWORD',
|
|
19
27
|
'USER_UPDATE_HEARTBEAT',
|
|
20
28
|
'USER_UPDATE_BILLING_ADDRESS',
|
|
21
29
|
'USER_UPDATE_LAST_CONTACT',
|
|
@@ -39,14 +47,17 @@ FileDirector.registerFileUploadCallback('user-avatars', async (file, context) =>
|
|
|
39
47
|
const { services } = context;
|
|
40
48
|
return services.users.updateUserAvatarAfterUpload({ file }, context);
|
|
41
49
|
});
|
|
42
|
-
export const configureUsersModule = async ({ db, migrationRepository, }) => {
|
|
50
|
+
export const configureUsersModule = async ({ db, options, migrationRepository, }) => {
|
|
51
|
+
userSettings.configureSettings(options || {}, db);
|
|
43
52
|
registerEvents(USER_EVENTS);
|
|
44
53
|
const Users = await UsersCollection(db);
|
|
45
54
|
// Migration
|
|
46
55
|
addMigrations(migrationRepository);
|
|
56
|
+
const webAuthn = await configureUsersWebAuthnModule({ db, options });
|
|
47
57
|
return {
|
|
48
58
|
// Queries
|
|
49
|
-
|
|
59
|
+
webAuthn,
|
|
60
|
+
async count(query) {
|
|
50
61
|
const userCount = await Users.countDocuments(buildFindSelector(query));
|
|
51
62
|
return userCount;
|
|
52
63
|
},
|
|
@@ -55,33 +66,81 @@ export const configureUsersModule = async ({ db, migrationRepository, }) => {
|
|
|
55
66
|
return null;
|
|
56
67
|
return Users.findOne(generateDbFilterById(userId), {});
|
|
57
68
|
},
|
|
58
|
-
async
|
|
59
|
-
if (
|
|
60
|
-
return
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (
|
|
65
|
-
return
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (
|
|
70
|
-
return
|
|
69
|
+
async findUserByUsername(username) {
|
|
70
|
+
if (!username)
|
|
71
|
+
return null;
|
|
72
|
+
return Users.findOne({ username }, {});
|
|
73
|
+
},
|
|
74
|
+
async findUserByEmail(email) {
|
|
75
|
+
if (!email)
|
|
76
|
+
return null;
|
|
77
|
+
return Users.findOne({ 'emails.address': { $regex: email, $options: 'i' } }, {});
|
|
78
|
+
},
|
|
79
|
+
async findUnverifiedEmailToken(plainToken) {
|
|
80
|
+
if (!plainToken)
|
|
81
|
+
return null;
|
|
82
|
+
const token = await sha256.hash(plainToken);
|
|
83
|
+
const user = await Users.findOne({
|
|
84
|
+
'services.email.verificationTokens': {
|
|
85
|
+
$elemMatch: {
|
|
86
|
+
token,
|
|
87
|
+
when: { $gt: new Date().getTime() },
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
}, {});
|
|
91
|
+
if (!user)
|
|
92
|
+
return null;
|
|
93
|
+
const verificationToken = user.services.email.verificationTokens.find((v) => v.token === token);
|
|
94
|
+
return {
|
|
95
|
+
userId: user._id,
|
|
96
|
+
...verificationToken,
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
async verifyEmail(userId, address) {
|
|
100
|
+
await Users.updateOne({ _id: userId }, {
|
|
101
|
+
$set: {
|
|
102
|
+
'emails.$[email].verified': true,
|
|
103
|
+
},
|
|
104
|
+
$pull: {
|
|
71
105
|
'services.email.verificationTokens': {
|
|
72
|
-
|
|
73
|
-
token: verifyEmailToken,
|
|
74
|
-
},
|
|
106
|
+
address,
|
|
75
107
|
},
|
|
108
|
+
},
|
|
109
|
+
}, {
|
|
110
|
+
arrayFilters: [{ 'email.address': address }],
|
|
111
|
+
});
|
|
112
|
+
await emit('USER_ACCOUNT_ACTION', {
|
|
113
|
+
action: 'email-verified',
|
|
114
|
+
address,
|
|
115
|
+
userId,
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
async findUserByResetToken(plainToken) {
|
|
119
|
+
const token = await sha256.hash(plainToken);
|
|
120
|
+
const user = await Users.findOne({
|
|
121
|
+
'services.password.reset': {
|
|
122
|
+
$elemMatch: {
|
|
123
|
+
token,
|
|
124
|
+
when: { $gt: new Date().getTime() },
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
}, {});
|
|
128
|
+
return user;
|
|
129
|
+
},
|
|
130
|
+
async findUserByToken(plainToken) {
|
|
131
|
+
const token = await sha256.hash(plainToken);
|
|
132
|
+
if (token) {
|
|
133
|
+
return Users.findOne({
|
|
134
|
+
'services.token.secret': token,
|
|
76
135
|
});
|
|
77
136
|
}
|
|
78
137
|
return null;
|
|
79
138
|
},
|
|
80
|
-
|
|
139
|
+
async findUser(query, findOptions) {
|
|
81
140
|
const selector = buildFindSelector(query);
|
|
82
|
-
return Users.findOne(selector,
|
|
141
|
+
return Users.findOne(selector, findOptions);
|
|
83
142
|
},
|
|
84
|
-
|
|
143
|
+
async findUsers({ limit, offset, ...query }) {
|
|
85
144
|
const defaultSort = [{ key: 'created', value: SortDirection.ASC }];
|
|
86
145
|
const selector = buildFindSelector(query);
|
|
87
146
|
if (query.queryString) {
|
|
@@ -98,24 +157,197 @@ export const configureUsersModule = async ({ db, migrationRepository, }) => {
|
|
|
98
157
|
sort: buildSortOptions(query.sort || defaultSort),
|
|
99
158
|
}).toArray();
|
|
100
159
|
},
|
|
101
|
-
|
|
160
|
+
async userExists({ userId }) {
|
|
102
161
|
const selector = generateDbFilterById(userId);
|
|
103
162
|
selector.deleted = null; // skip deleted users when checked for existance!
|
|
104
163
|
const userCount = await Users.countDocuments(selector, { limit: 1 });
|
|
105
|
-
return
|
|
164
|
+
return userCount === 1;
|
|
106
165
|
},
|
|
107
166
|
// Transformations
|
|
108
|
-
primaryEmail
|
|
167
|
+
primaryEmail(user) {
|
|
109
168
|
return (user.emails || []).sort((left, right) => Number(right.verified) - Number(left.verified))?.[0];
|
|
110
169
|
},
|
|
111
|
-
userLocale
|
|
170
|
+
userLocale(user) {
|
|
112
171
|
if (!user?.lastLogin?.locale)
|
|
113
172
|
return systemLocale;
|
|
114
173
|
return new Locale(user.lastLogin.locale);
|
|
115
174
|
},
|
|
175
|
+
// Mutations
|
|
176
|
+
async createUser({ password, email, username, initialPassword, roles, webAuthnPublicKeyCredentials, ...userData }, { skipMessaging, skipPasswordEnrollment, } = {}) {
|
|
177
|
+
const normalizedUserData = await userSettings.validateNewUser(userData);
|
|
178
|
+
const webAuthnService = webAuthnPublicKeyCredentials &&
|
|
179
|
+
(await this.webAuthn.verifyCredentialCreation(username, webAuthnPublicKeyCredentials));
|
|
180
|
+
const services = {};
|
|
181
|
+
if (email) {
|
|
182
|
+
if (!(await userSettings.validateEmail(email))) {
|
|
183
|
+
throw new Error(`E-Mail address ${email} is invalid`, { cause: 'EMAIL_INVALID' });
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (password) {
|
|
187
|
+
if (!(await userSettings.validatePassword(password))) {
|
|
188
|
+
throw new Error(`Provided password is invalid`, { cause: 'PASSWORD_INVALID' });
|
|
189
|
+
}
|
|
190
|
+
services.password = await this.hashPassword(password);
|
|
191
|
+
}
|
|
192
|
+
if (webAuthnService) {
|
|
193
|
+
services.webAuthn = [webAuthnService];
|
|
194
|
+
}
|
|
195
|
+
const doc = {
|
|
196
|
+
...normalizedUserData,
|
|
197
|
+
_id: normalizedUserData._id || generateDbObjectId(),
|
|
198
|
+
roles: roles || [],
|
|
199
|
+
initialPassword: Boolean(initialPassword),
|
|
200
|
+
emails: email ? [{ address: email, verified: false }] : [],
|
|
201
|
+
created: new Date(),
|
|
202
|
+
};
|
|
203
|
+
if (username) {
|
|
204
|
+
if (!(await userSettings.validateUsername(username))) {
|
|
205
|
+
throw new Error(`Username ${username} is invalid`, { cause: 'USERNAME_INVALID' });
|
|
206
|
+
}
|
|
207
|
+
doc.username = username;
|
|
208
|
+
}
|
|
209
|
+
const { insertedId: userId } = await Users.insertOne(doc);
|
|
210
|
+
try {
|
|
211
|
+
const autoMessagingEnabled = skipMessaging
|
|
212
|
+
? false
|
|
213
|
+
: userSettings.autoMessagingAfterUserCreation && !!email && !!userId;
|
|
214
|
+
if (autoMessagingEnabled) {
|
|
215
|
+
if (password === undefined) {
|
|
216
|
+
if (!skipPasswordEnrollment && !webAuthnService) {
|
|
217
|
+
await this.sendResetPasswordEmail(userId, email, true);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
await this.sendVerificationEmail(userId, email);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
catch (e) {
|
|
226
|
+
/* */
|
|
227
|
+
}
|
|
228
|
+
const user = await Users.findOne({ _id: userId }, {});
|
|
229
|
+
await emit('USER_CREATE', {
|
|
230
|
+
user: removeConfidentialServiceHashes(user),
|
|
231
|
+
});
|
|
232
|
+
return userId;
|
|
233
|
+
},
|
|
234
|
+
async hashPassword(password) {
|
|
235
|
+
const salt = pbkdf2.generateSalt();
|
|
236
|
+
const hashedPassword = await pbkdf2.getDerivedKey(salt, password);
|
|
237
|
+
return { pbkdf2: `${salt}:${hashedPassword}` };
|
|
238
|
+
},
|
|
239
|
+
async verifyPassword({ bcrypt: bcryptHash, pbkdf2: pbkdf2SaltAndHash }, plainPassword) {
|
|
240
|
+
if (bcryptHash) {
|
|
241
|
+
const password = await sha256.hash(plainPassword);
|
|
242
|
+
return bcrypt.compare(password, bcryptHash);
|
|
243
|
+
}
|
|
244
|
+
if (pbkdf2SaltAndHash) {
|
|
245
|
+
const [pbkdf2Salt, pbkdf2Hash] = pbkdf2SaltAndHash.split(':');
|
|
246
|
+
return pbkdf2.compare(plainPassword, pbkdf2Hash, pbkdf2Salt);
|
|
247
|
+
}
|
|
248
|
+
return false;
|
|
249
|
+
},
|
|
250
|
+
async addEmail(userId, address) {
|
|
251
|
+
if (!(await userSettings.validateEmail(address))) {
|
|
252
|
+
throw new Error(`E-Mail address ${address} is invalid`, { cause: 'EMAIL_INVALID' });
|
|
253
|
+
}
|
|
254
|
+
await this.updateUser({ _id: userId, 'emails.address': { $not: { $regex: address, $options: 'i' } } }, {
|
|
255
|
+
$push: {
|
|
256
|
+
emails: {
|
|
257
|
+
address: address.trim(),
|
|
258
|
+
verified: false,
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
},
|
|
263
|
+
async removeEmail(userId, address) {
|
|
264
|
+
await this.updateUser({ _id: userId, 'emails.address': { $regex: address, $options: 'i' } }, {
|
|
265
|
+
$pull: {
|
|
266
|
+
emails: { address: { $regex: address, $options: 'i' } },
|
|
267
|
+
},
|
|
268
|
+
});
|
|
269
|
+
},
|
|
270
|
+
async sendResetPasswordEmail(userId, email, isEnrollment) {
|
|
271
|
+
const plainToken = crypto.randomUUID();
|
|
272
|
+
const resetToken = {
|
|
273
|
+
token: await sha256.hash(plainToken),
|
|
274
|
+
address: email,
|
|
275
|
+
when: new Date().getTime() + 1000 * 60 * 60, // 1 hour
|
|
276
|
+
};
|
|
277
|
+
await Users.updateOne({ _id: userId }, {
|
|
278
|
+
$push: {
|
|
279
|
+
'services.password.reset': resetToken,
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
await emit('USER_ACCOUNT_ACTION', {
|
|
283
|
+
action: isEnrollment ? 'enroll-account' : 'reset-password',
|
|
284
|
+
userId,
|
|
285
|
+
...resetToken,
|
|
286
|
+
token: plainToken,
|
|
287
|
+
});
|
|
288
|
+
},
|
|
289
|
+
async sendVerificationEmail(userId, email) {
|
|
290
|
+
const plainToken = crypto.randomUUID();
|
|
291
|
+
const verificationToken = {
|
|
292
|
+
token: await sha256.hash(plainToken),
|
|
293
|
+
address: email,
|
|
294
|
+
when: new Date().getTime() + 1000 * 60 * 60, // 1 hour
|
|
295
|
+
};
|
|
296
|
+
await Users.updateOne({ _id: userId }, {
|
|
297
|
+
$push: {
|
|
298
|
+
'services.email.verificationTokens': verificationToken,
|
|
299
|
+
},
|
|
300
|
+
});
|
|
301
|
+
await emit('USER_ACCOUNT_ACTION', {
|
|
302
|
+
action: 'verify-email',
|
|
303
|
+
userId,
|
|
304
|
+
...verificationToken,
|
|
305
|
+
token: plainToken,
|
|
306
|
+
});
|
|
307
|
+
},
|
|
308
|
+
addRoles: async (userId, roles) => {
|
|
309
|
+
const selector = generateDbFilterById(userId);
|
|
310
|
+
const updateResult = await Users.updateOne(selector, {
|
|
311
|
+
$addToSet: { roles: { $each: roles } },
|
|
312
|
+
});
|
|
313
|
+
const user = await Users.findOne(selector, {});
|
|
314
|
+
await emit('USER_ADD_ROLES', {
|
|
315
|
+
user: removeConfidentialServiceHashes(user),
|
|
316
|
+
});
|
|
317
|
+
return updateResult.modifiedCount;
|
|
318
|
+
},
|
|
319
|
+
async setUsername(userId, username) {
|
|
320
|
+
if (!(await userSettings.validateUsername(username))) {
|
|
321
|
+
throw new Error(`Username ${username} is invalid`, { cause: 'USERNAME_INVALID' });
|
|
322
|
+
}
|
|
323
|
+
await Users.updateOne({ _id: userId }, {
|
|
324
|
+
$set: {
|
|
325
|
+
username: username.trim(),
|
|
326
|
+
},
|
|
327
|
+
});
|
|
328
|
+
const user = await Users.findOne({ _id: userId }, {});
|
|
329
|
+
await emit('USER_UPDATE_USERNAME', {
|
|
330
|
+
user: removeConfidentialServiceHashes(user),
|
|
331
|
+
});
|
|
332
|
+
},
|
|
333
|
+
async setPassword(userId, plainPassword) {
|
|
334
|
+
if (!(await userSettings.validatePassword(plainPassword))) {
|
|
335
|
+
throw new Error(`Password ***** is invalid`, { cause: 'PASSWORD_INVALID' });
|
|
336
|
+
}
|
|
337
|
+
const password = plainPassword || crypto.randomUUID().split('-').pop();
|
|
338
|
+
await Users.updateOne({ _id: userId }, {
|
|
339
|
+
$set: {
|
|
340
|
+
initialPassword: false,
|
|
341
|
+
'services.password': await this.hashPassword(password || crypto.randomUUID().split('-').pop()),
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
const user = await Users.findOne({ _id: userId }, {});
|
|
345
|
+
await emit('USER_UPDATE_PASSWORD', {
|
|
346
|
+
user: removeConfidentialServiceHashes(user),
|
|
347
|
+
});
|
|
348
|
+
},
|
|
116
349
|
updateAvatar: async (_id, fileId) => {
|
|
117
350
|
const userFilter = generateDbFilterById(_id);
|
|
118
|
-
log('Update Avatar', { userId: _id });
|
|
119
351
|
const modifier = {
|
|
120
352
|
$set: {
|
|
121
353
|
avatarId: fileId,
|
|
@@ -131,9 +363,14 @@ export const configureUsersModule = async ({ db, migrationRepository, }) => {
|
|
|
131
363
|
return user;
|
|
132
364
|
},
|
|
133
365
|
updateGuest: async (user, guest) => {
|
|
134
|
-
log('Update guest', { userId: user._id });
|
|
135
366
|
const modifier = { $set: { guest } };
|
|
136
367
|
await Users.updateOne(generateDbFilterById(user._id), modifier);
|
|
368
|
+
await emit('USER_UPDATE_GUEST', {
|
|
369
|
+
user: removeConfidentialServiceHashes({
|
|
370
|
+
...user,
|
|
371
|
+
guest,
|
|
372
|
+
}),
|
|
373
|
+
});
|
|
137
374
|
},
|
|
138
375
|
updateHeartbeat: async (userId, lastLogin) => {
|
|
139
376
|
const modifier = {
|
|
@@ -152,14 +389,6 @@ export const configureUsersModule = async ({ db, migrationRepository, }) => {
|
|
|
152
389
|
});
|
|
153
390
|
return user;
|
|
154
391
|
},
|
|
155
|
-
updateInitialPassword: async (user, initialPassword) => {
|
|
156
|
-
log(`Update initial password flag to ${initialPassword}`, {
|
|
157
|
-
userId: user._id,
|
|
158
|
-
level: LogLevel.Verbose,
|
|
159
|
-
});
|
|
160
|
-
const modifier = { $set: { initialPassword } };
|
|
161
|
-
await Users.updateOne(generateDbFilterById(user._id), modifier);
|
|
162
|
-
},
|
|
163
392
|
delete: async (userId) => {
|
|
164
393
|
const userFilter = generateDbFilterById(userId);
|
|
165
394
|
const existingUser = await Users.findOne(userFilter, {
|
|
@@ -167,17 +396,18 @@ export const configureUsersModule = async ({ db, migrationRepository, }) => {
|
|
|
167
396
|
});
|
|
168
397
|
if (!existingUser)
|
|
169
398
|
return null;
|
|
399
|
+
const uuid = crypto.randomUUID();
|
|
170
400
|
const obfuscatedEmails = existingUser.emails?.flatMap(({ address, verified }) => {
|
|
171
401
|
if (!verified)
|
|
172
402
|
return [];
|
|
173
403
|
return [
|
|
174
404
|
{
|
|
175
|
-
address: `${address}@${
|
|
405
|
+
address: `${address}@${uuid}.unchained.local`,
|
|
176
406
|
verified: true,
|
|
177
407
|
},
|
|
178
408
|
];
|
|
179
409
|
});
|
|
180
|
-
const obfuscatedUsername = existingUser.username ? `${existingUser.username}-${
|
|
410
|
+
const obfuscatedUsername = existingUser.username ? `${existingUser.username}-${uuid}` : null;
|
|
181
411
|
Users.updateOne(userFilter, {
|
|
182
412
|
$set: {
|
|
183
413
|
emails: obfuscatedEmails,
|
|
@@ -299,9 +529,9 @@ export const configureUsersModule = async ({ db, migrationRepository, }) => {
|
|
|
299
529
|
});
|
|
300
530
|
return user;
|
|
301
531
|
},
|
|
302
|
-
updateUser: async (
|
|
303
|
-
const user = await Users.findOneAndUpdate(
|
|
304
|
-
...
|
|
532
|
+
updateUser: async (selector, modifier, updateOptions) => {
|
|
533
|
+
const user = await Users.findOneAndUpdate(selector, modifier, {
|
|
534
|
+
...updateOptions,
|
|
305
535
|
returnDocument: 'after',
|
|
306
536
|
});
|
|
307
537
|
await emit('USER_UPDATE', {
|
|
@@ -309,16 +539,16 @@ export const configureUsersModule = async ({ db, migrationRepository, }) => {
|
|
|
309
539
|
});
|
|
310
540
|
return user;
|
|
311
541
|
},
|
|
312
|
-
addPushSubscription: async (userId, subscription,
|
|
542
|
+
addPushSubscription: async (userId, subscription, subscriptionOptions) => {
|
|
313
543
|
const updateResult = await Users.updateOne({ _id: userId, 'pushSubscriptions.keys.p256dh': { $ne: subscription?.keys?.p256dh } }, {
|
|
314
544
|
$push: {
|
|
315
545
|
pushSubscriptions: {
|
|
316
|
-
userAgent,
|
|
546
|
+
userAgent: subscriptionOptions?.userAgent,
|
|
317
547
|
...subscription,
|
|
318
548
|
},
|
|
319
549
|
},
|
|
320
550
|
}, {});
|
|
321
|
-
if (updateResult.modifiedCount === 1 && unsubscribeFromOtherUsers) {
|
|
551
|
+
if (updateResult.modifiedCount === 1 && subscriptionOptions?.unsubscribeFromOtherUsers) {
|
|
322
552
|
await Users.updateMany({ _id: { $ne: userId }, 'pushSubscriptions.keys.p256dh': subscription?.keys?.p256dh }, {
|
|
323
553
|
$pull: {
|
|
324
554
|
pushSubscriptions: { 'keys.p256dh': subscription?.keys?.p256dh },
|