@aneuhold/be-ts-db-lib 4.2.18 → 4.2.20
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/CHANGELOG.md +24 -0
- package/lib/repositories/common/UserRepository.d.ts +6 -0
- package/lib/repositories/common/UserRepository.d.ts.map +1 -1
- package/lib/repositories/common/UserRepository.js +12 -0
- package/lib/repositories/common/UserRepository.js.map +1 -1
- package/lib/repositories/common/UserRepository.ts +13 -0
- package/lib/services/GoogleAuthService.d.ts +16 -0
- package/lib/services/GoogleAuthService.d.ts.map +1 -1
- package/lib/services/GoogleAuthService.js +57 -28
- package/lib/services/GoogleAuthService.js.map +1 -1
- package/lib/services/GoogleAuthService.ts +70 -30
- package/lib/services/MigrationService.d.ts.map +1 -1
- package/lib/services/MigrationService.js +35 -352
- package/lib/services/MigrationService.js.map +1 -1
- package/lib/services/MigrationService.ts +42 -425
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## 🔖 [4.2.20] (2026-03-19)
|
|
9
|
+
|
|
10
|
+
### ✅ Added
|
|
11
|
+
|
|
12
|
+
- Added `GoogleAuthService.verifyAndFindUser` method that returns `null` when no matching user exists (does not create one).
|
|
13
|
+
|
|
14
|
+
### 🏗️ Changed
|
|
15
|
+
|
|
16
|
+
- Refactored `GoogleAuthService`: extracted private `verifyToken` helper and restructured `verifyAndFindOrCreateUser` to delegate to `verifyAndFindUser`.
|
|
17
|
+
- Refactored `MigrationService` to fill in missing `projectAccess` fields with safe defaults instead of patching `refreshTokenHashes`.
|
|
18
|
+
- Updated dependencies on `@aneuhold/be-ts-lib` to `^3.1.7` and `@aneuhold/core-ts-db-lib` to `^5.0.2`.
|
|
19
|
+
|
|
20
|
+
## 🔖 [4.2.19] (2026-03-18)
|
|
21
|
+
|
|
22
|
+
### ✅ Added
|
|
23
|
+
|
|
24
|
+
- Added `UserRepository.getUserByRefreshTokenHash()` to look up a user by a SHA-256 hashed refresh token stored in `auth.refreshTokenHashes`.
|
|
25
|
+
|
|
26
|
+
### 🏗️ Changed
|
|
27
|
+
|
|
28
|
+
- `MigrationService` updated to backfill `auth.refreshTokenHashes` for users missing the field; removed the previous large ObjectId-to-UUID migration logic.
|
|
29
|
+
|
|
8
30
|
## 🔖 [4.2.18] (2026-03-15)
|
|
9
31
|
|
|
10
32
|
### ✅ Added
|
|
@@ -338,6 +360,8 @@ Updated dependencies: now requires `@aneuhold/core-ts-db-lib@^3.0.0`, `@aneuhold
|
|
|
338
360
|
|
|
339
361
|
<!-- Link References -->
|
|
340
362
|
|
|
363
|
+
[4.2.20]: https://github.com/aneuhold/ts-libs/compare/be-ts-db-lib-v4.2.19...be-ts-db-lib-v4.2.20
|
|
364
|
+
[4.2.19]: https://github.com/aneuhold/ts-libs/compare/be-ts-db-lib-v4.2.18...be-ts-db-lib-v4.2.19
|
|
341
365
|
[4.2.18]: https://github.com/aneuhold/ts-libs/compare/be-ts-db-lib-v4.2.17...be-ts-db-lib-v4.2.18
|
|
342
366
|
[4.2.17]: https://github.com/aneuhold/ts-libs/compare/be-ts-db-lib-v4.2.16...be-ts-db-lib-v4.2.17
|
|
343
367
|
[4.2.16]: https://github.com/aneuhold/ts-libs/compare/be-ts-db-lib-v4.2.15...be-ts-db-lib-v4.2.16
|
|
@@ -14,6 +14,12 @@ export default class UserRepository extends BaseRepository<User> {
|
|
|
14
14
|
*/
|
|
15
15
|
static getRepo(): UserRepository;
|
|
16
16
|
getUserCTOByUsername(userName: string): Promise<UserCTO | null>;
|
|
17
|
+
/**
|
|
18
|
+
* Finds a user that has a refresh token with the given SHA-256 hash.
|
|
19
|
+
*
|
|
20
|
+
* @param tokenHash - The SHA-256 hash of the refresh token.
|
|
21
|
+
*/
|
|
22
|
+
getUserByRefreshTokenHash(tokenHash: string): Promise<User | null>;
|
|
17
23
|
getUserCTOsByIds(userIds: UUID[]): Promise<UserCTO[]>;
|
|
18
24
|
}
|
|
19
25
|
//# sourceMappingURL=UserRepository.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserRepository.d.ts","sourceRoot":"","sources":["../../../src/repositories/common/UserRepository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEnC,OAAO,cAAc,MAAM,sBAAsB,CAAC;AAalD;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,cAAc,CAAC,IAAI,CAAC;IAC9D,OAAO,CAAC,MAAM,CAAC,eAAe,CAAW;IAEzC,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAA6B;IAE7D,OAAO;IAIP,SAAS,CAAC,gBAAgB,IAAI,IAAI;IAclC;;OAEG;IACH,MAAM,CAAC,OAAO,IAAI,cAAc;IAO1B,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"UserRepository.d.ts","sourceRoot":"","sources":["../../../src/repositories/common/UserRepository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEnC,OAAO,cAAc,MAAM,sBAAsB,CAAC;AAalD;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,cAAc,CAAC,IAAI,CAAC;IAC9D,OAAO,CAAC,MAAM,CAAC,eAAe,CAAW;IAEzC,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAA6B;IAE7D,OAAO;IAIP,SAAS,CAAC,gBAAgB,IAAI,IAAI;IAclC;;OAEG;IACH,MAAM,CAAC,OAAO,IAAI,cAAc;IAO1B,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAWrE;;;;OAIG;IACG,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAQlE,gBAAgB,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;CAO5D"}
|
|
@@ -52,6 +52,18 @@ export default class UserRepository extends BaseRepository {
|
|
|
52
52
|
}
|
|
53
53
|
return null;
|
|
54
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Finds a user that has a refresh token with the given SHA-256 hash.
|
|
57
|
+
*
|
|
58
|
+
* @param tokenHash - The SHA-256 hash of the refresh token.
|
|
59
|
+
*/
|
|
60
|
+
async getUserByRefreshTokenHash(tokenHash) {
|
|
61
|
+
const collection = await this.getCollection();
|
|
62
|
+
const result = await collection.findOne({
|
|
63
|
+
'auth.refreshTokenHashes.tokenHash': tokenHash
|
|
64
|
+
});
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
55
67
|
async getUserCTOsByIds(userIds) {
|
|
56
68
|
const users = await this.getList(userIds);
|
|
57
69
|
return users.map((user) => ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserRepository.js","sourceRoot":"","sources":["../../../src/repositories/common/UserRepository.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"UserRepository.js","sourceRoot":"","sources":["../../../src/repositories/common/UserRepository.ts"],"names":[],"mappings":"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"}
|
|
@@ -61,6 +61,19 @@ export default class UserRepository extends BaseRepository<User> {
|
|
|
61
61
|
return null;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Finds a user that has a refresh token with the given SHA-256 hash.
|
|
66
|
+
*
|
|
67
|
+
* @param tokenHash - The SHA-256 hash of the refresh token.
|
|
68
|
+
*/
|
|
69
|
+
async getUserByRefreshTokenHash(tokenHash: string): Promise<User | null> {
|
|
70
|
+
const collection = await this.getCollection();
|
|
71
|
+
const result = await collection.findOne({
|
|
72
|
+
'auth.refreshTokenHashes.tokenHash': tokenHash
|
|
73
|
+
});
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
|
|
64
77
|
async getUserCTOsByIds(userIds: UUID[]): Promise<UserCTO[]> {
|
|
65
78
|
const users = await this.getList(userIds);
|
|
66
79
|
return users.map((user) => ({
|
|
@@ -6,6 +6,16 @@ import type { ApiKey, User } from '@aneuhold/core-ts-db-lib';
|
|
|
6
6
|
*/
|
|
7
7
|
export default class GoogleAuthService {
|
|
8
8
|
private static readonly client;
|
|
9
|
+
/**
|
|
10
|
+
* Verifies a Google ID token and finds the associated user. Returns
|
|
11
|
+
* `null` if no matching user exists (does **not** create one).
|
|
12
|
+
*
|
|
13
|
+
* @param googleCredentialToken - The Google ID token string from the client.
|
|
14
|
+
*/
|
|
15
|
+
static verifyAndFindUser(googleCredentialToken: string): Promise<{
|
|
16
|
+
user: User;
|
|
17
|
+
apiKey: ApiKey;
|
|
18
|
+
} | null>;
|
|
9
19
|
/**
|
|
10
20
|
* Verifies a Google ID token and finds or creates the associated user.
|
|
11
21
|
*
|
|
@@ -15,5 +25,11 @@ export default class GoogleAuthService {
|
|
|
15
25
|
user: User;
|
|
16
26
|
apiKey: ApiKey;
|
|
17
27
|
}>;
|
|
28
|
+
/**
|
|
29
|
+
* Verifies a Google ID token and returns the Google ID and email.
|
|
30
|
+
*
|
|
31
|
+
* @param googleCredentialToken - The Google ID token string from the client.
|
|
32
|
+
*/
|
|
33
|
+
private static verifyToken;
|
|
18
34
|
}
|
|
19
35
|
//# sourceMappingURL=GoogleAuthService.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GoogleAuthService.d.ts","sourceRoot":"","sources":["../../src/services/GoogleAuthService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAM7D;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,iBAAiB;IACpC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAsC;IAEpE;;;;OAIG;WACU,yBAAyB,CACpC,qBAAqB,EAAE,MAAM,GAC5B,OAAO,CAAC;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"GoogleAuthService.d.ts","sourceRoot":"","sources":["../../src/services/GoogleAuthService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAM7D;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,iBAAiB;IACpC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAsC;IAEpE;;;;;OAKG;WACU,iBAAiB,CAC5B,qBAAqB,EAAE,MAAM,GAC5B,OAAO,CAAC;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IA+BjD;;;;OAIG;WACU,yBAAyB,CACpC,qBAAqB,EAAE,MAAM,GAC5B,OAAO,CAAC;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IA+B1C;;;;OAIG;mBACkB,WAAW;CAmBjC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GOOGLE_CLIENT_ID, UserSchema } from '@aneuhold/core-ts-db-lib';
|
|
1
|
+
import { GOOGLE_CLIENT_ID, ProjectName, UserSchema } from '@aneuhold/core-ts-db-lib';
|
|
2
2
|
import { OAuth2Client } from 'google-auth-library';
|
|
3
3
|
import ApiKeyRepository from '../repositories/common/ApiKeyRepository.js';
|
|
4
4
|
import UserRepository from '../repositories/common/UserRepository.js';
|
|
@@ -10,23 +10,13 @@ import UserRepository from '../repositories/common/UserRepository.js';
|
|
|
10
10
|
export default class GoogleAuthService {
|
|
11
11
|
static client = new OAuth2Client(GOOGLE_CLIENT_ID);
|
|
12
12
|
/**
|
|
13
|
-
* Verifies a Google ID token and finds
|
|
13
|
+
* Verifies a Google ID token and finds the associated user. Returns
|
|
14
|
+
* `null` if no matching user exists (does **not** create one).
|
|
14
15
|
*
|
|
15
16
|
* @param googleCredentialToken - The Google ID token string from the client.
|
|
16
17
|
*/
|
|
17
|
-
static async
|
|
18
|
-
const
|
|
19
|
-
idToken: googleCredentialToken,
|
|
20
|
-
audience: GOOGLE_CLIENT_ID
|
|
21
|
-
});
|
|
22
|
-
const payload = ticket.getPayload();
|
|
23
|
-
if (!payload) {
|
|
24
|
-
throw new Error('Invalid Google token payload');
|
|
25
|
-
}
|
|
26
|
-
const { sub: googleId, email } = payload;
|
|
27
|
-
if (!email) {
|
|
28
|
-
throw new Error('Google account has no email');
|
|
29
|
-
}
|
|
18
|
+
static async verifyAndFindUser(googleCredentialToken) {
|
|
19
|
+
const { googleId, email } = await this.verifyToken(googleCredentialToken);
|
|
30
20
|
const userRepo = UserRepository.getRepo();
|
|
31
21
|
const apiKeyRepo = ApiKeyRepository.getRepo();
|
|
32
22
|
// 1. Look up by googleId
|
|
@@ -40,20 +30,8 @@ export default class GoogleAuthService {
|
|
|
40
30
|
user.auth.googleId = googleId;
|
|
41
31
|
}
|
|
42
32
|
}
|
|
43
|
-
// 3. Create new user if neither match. The ApiKey subscriber on
|
|
44
|
-
// UserRepository automatically creates an API key on user insertion.
|
|
45
33
|
if (!user) {
|
|
46
|
-
|
|
47
|
-
userName: email,
|
|
48
|
-
email,
|
|
49
|
-
auth: { googleId },
|
|
50
|
-
projectAccess: { dashboard: false, workout: true }
|
|
51
|
-
});
|
|
52
|
-
const insertedUser = await userRepo.insertNew(newUser);
|
|
53
|
-
if (!insertedUser) {
|
|
54
|
-
throw new Error('Failed to create user');
|
|
55
|
-
}
|
|
56
|
-
user = insertedUser;
|
|
34
|
+
return null;
|
|
57
35
|
}
|
|
58
36
|
const apiKey = await apiKeyRepo.get({ userId: user._id });
|
|
59
37
|
if (!apiKey) {
|
|
@@ -61,5 +39,56 @@ export default class GoogleAuthService {
|
|
|
61
39
|
}
|
|
62
40
|
return { user, apiKey };
|
|
63
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Verifies a Google ID token and finds or creates the associated user.
|
|
44
|
+
*
|
|
45
|
+
* @param googleCredentialToken - The Google ID token string from the client.
|
|
46
|
+
*/
|
|
47
|
+
static async verifyAndFindOrCreateUser(googleCredentialToken) {
|
|
48
|
+
const result = await this.verifyAndFindUser(googleCredentialToken);
|
|
49
|
+
if (result) {
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
// Create new user. The ApiKey subscriber on UserRepository automatically
|
|
53
|
+
// creates an API key on user insertion.
|
|
54
|
+
const { googleId, email } = await this.verifyToken(googleCredentialToken);
|
|
55
|
+
const userRepo = UserRepository.getRepo();
|
|
56
|
+
const apiKeyRepo = ApiKeyRepository.getRepo();
|
|
57
|
+
const newUser = UserSchema.parse({
|
|
58
|
+
userName: email,
|
|
59
|
+
email,
|
|
60
|
+
auth: { googleId },
|
|
61
|
+
projectAccess: { [ProjectName.Dashboard]: false, [ProjectName.Workout]: true }
|
|
62
|
+
});
|
|
63
|
+
const insertedUser = await userRepo.insertNew(newUser);
|
|
64
|
+
if (!insertedUser) {
|
|
65
|
+
throw new Error('Failed to create user');
|
|
66
|
+
}
|
|
67
|
+
const apiKey = await apiKeyRepo.get({ userId: insertedUser._id });
|
|
68
|
+
if (!apiKey) {
|
|
69
|
+
throw new Error(`No API key found for user ${insertedUser._id}`);
|
|
70
|
+
}
|
|
71
|
+
return { user: insertedUser, apiKey };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Verifies a Google ID token and returns the Google ID and email.
|
|
75
|
+
*
|
|
76
|
+
* @param googleCredentialToken - The Google ID token string from the client.
|
|
77
|
+
*/
|
|
78
|
+
static async verifyToken(googleCredentialToken) {
|
|
79
|
+
const ticket = await this.client.verifyIdToken({
|
|
80
|
+
idToken: googleCredentialToken,
|
|
81
|
+
audience: GOOGLE_CLIENT_ID
|
|
82
|
+
});
|
|
83
|
+
const payload = ticket.getPayload();
|
|
84
|
+
if (!payload) {
|
|
85
|
+
throw new Error('Invalid Google token payload');
|
|
86
|
+
}
|
|
87
|
+
const { sub: googleId, email } = payload;
|
|
88
|
+
if (!email) {
|
|
89
|
+
throw new Error('Google account has no email');
|
|
90
|
+
}
|
|
91
|
+
return { googleId, email };
|
|
92
|
+
}
|
|
64
93
|
}
|
|
65
94
|
//# sourceMappingURL=GoogleAuthService.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GoogleAuthService.js","sourceRoot":"","sources":["../../src/services/GoogleAuthService.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"GoogleAuthService.js","sourceRoot":"","sources":["../../src/services/GoogleAuthService.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ApiKey, User } from '@aneuhold/core-ts-db-lib';
|
|
2
|
-
import { GOOGLE_CLIENT_ID, UserSchema } from '@aneuhold/core-ts-db-lib';
|
|
2
|
+
import { GOOGLE_CLIENT_ID, ProjectName, UserSchema } from '@aneuhold/core-ts-db-lib';
|
|
3
3
|
import { OAuth2Client } from 'google-auth-library';
|
|
4
4
|
import ApiKeyRepository from '../repositories/common/ApiKeyRepository.js';
|
|
5
5
|
import UserRepository from '../repositories/common/UserRepository.js';
|
|
@@ -13,26 +13,15 @@ export default class GoogleAuthService {
|
|
|
13
13
|
private static readonly client = new OAuth2Client(GOOGLE_CLIENT_ID);
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* Verifies a Google ID token and finds
|
|
16
|
+
* Verifies a Google ID token and finds the associated user. Returns
|
|
17
|
+
* `null` if no matching user exists (does **not** create one).
|
|
17
18
|
*
|
|
18
19
|
* @param googleCredentialToken - The Google ID token string from the client.
|
|
19
20
|
*/
|
|
20
|
-
static async
|
|
21
|
+
static async verifyAndFindUser(
|
|
21
22
|
googleCredentialToken: string
|
|
22
|
-
): Promise<{ user: User; apiKey: ApiKey }> {
|
|
23
|
-
const
|
|
24
|
-
idToken: googleCredentialToken,
|
|
25
|
-
audience: GOOGLE_CLIENT_ID
|
|
26
|
-
});
|
|
27
|
-
const payload = ticket.getPayload();
|
|
28
|
-
if (!payload) {
|
|
29
|
-
throw new Error('Invalid Google token payload');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const { sub: googleId, email } = payload;
|
|
33
|
-
if (!email) {
|
|
34
|
-
throw new Error('Google account has no email');
|
|
35
|
-
}
|
|
23
|
+
): Promise<{ user: User; apiKey: ApiKey } | null> {
|
|
24
|
+
const { googleId, email } = await this.verifyToken(googleCredentialToken);
|
|
36
25
|
|
|
37
26
|
const userRepo = UserRepository.getRepo();
|
|
38
27
|
const apiKeyRepo = ApiKeyRepository.getRepo();
|
|
@@ -50,20 +39,8 @@ export default class GoogleAuthService {
|
|
|
50
39
|
}
|
|
51
40
|
}
|
|
52
41
|
|
|
53
|
-
// 3. Create new user if neither match. The ApiKey subscriber on
|
|
54
|
-
// UserRepository automatically creates an API key on user insertion.
|
|
55
42
|
if (!user) {
|
|
56
|
-
|
|
57
|
-
userName: email,
|
|
58
|
-
email,
|
|
59
|
-
auth: { googleId },
|
|
60
|
-
projectAccess: { dashboard: false, workout: true }
|
|
61
|
-
});
|
|
62
|
-
const insertedUser = await userRepo.insertNew(newUser);
|
|
63
|
-
if (!insertedUser) {
|
|
64
|
-
throw new Error('Failed to create user');
|
|
65
|
-
}
|
|
66
|
-
user = insertedUser;
|
|
43
|
+
return null;
|
|
67
44
|
}
|
|
68
45
|
|
|
69
46
|
const apiKey = await apiKeyRepo.get({ userId: user._id });
|
|
@@ -73,4 +50,67 @@ export default class GoogleAuthService {
|
|
|
73
50
|
|
|
74
51
|
return { user, apiKey };
|
|
75
52
|
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Verifies a Google ID token and finds or creates the associated user.
|
|
56
|
+
*
|
|
57
|
+
* @param googleCredentialToken - The Google ID token string from the client.
|
|
58
|
+
*/
|
|
59
|
+
static async verifyAndFindOrCreateUser(
|
|
60
|
+
googleCredentialToken: string
|
|
61
|
+
): Promise<{ user: User; apiKey: ApiKey }> {
|
|
62
|
+
const result = await this.verifyAndFindUser(googleCredentialToken);
|
|
63
|
+
if (result) {
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Create new user. The ApiKey subscriber on UserRepository automatically
|
|
68
|
+
// creates an API key on user insertion.
|
|
69
|
+
const { googleId, email } = await this.verifyToken(googleCredentialToken);
|
|
70
|
+
const userRepo = UserRepository.getRepo();
|
|
71
|
+
const apiKeyRepo = ApiKeyRepository.getRepo();
|
|
72
|
+
|
|
73
|
+
const newUser = UserSchema.parse({
|
|
74
|
+
userName: email,
|
|
75
|
+
email,
|
|
76
|
+
auth: { googleId },
|
|
77
|
+
projectAccess: { [ProjectName.Dashboard]: false, [ProjectName.Workout]: true }
|
|
78
|
+
});
|
|
79
|
+
const insertedUser = await userRepo.insertNew(newUser);
|
|
80
|
+
if (!insertedUser) {
|
|
81
|
+
throw new Error('Failed to create user');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const apiKey = await apiKeyRepo.get({ userId: insertedUser._id });
|
|
85
|
+
if (!apiKey) {
|
|
86
|
+
throw new Error(`No API key found for user ${insertedUser._id}`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return { user: insertedUser, apiKey };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Verifies a Google ID token and returns the Google ID and email.
|
|
94
|
+
*
|
|
95
|
+
* @param googleCredentialToken - The Google ID token string from the client.
|
|
96
|
+
*/
|
|
97
|
+
private static async verifyToken(
|
|
98
|
+
googleCredentialToken: string
|
|
99
|
+
): Promise<{ googleId: string; email: string }> {
|
|
100
|
+
const ticket = await this.client.verifyIdToken({
|
|
101
|
+
idToken: googleCredentialToken,
|
|
102
|
+
audience: GOOGLE_CLIENT_ID
|
|
103
|
+
});
|
|
104
|
+
const payload = ticket.getPayload();
|
|
105
|
+
if (!payload) {
|
|
106
|
+
throw new Error('Invalid Google token payload');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const { sub: googleId, email } = payload;
|
|
110
|
+
if (!email) {
|
|
111
|
+
throw new Error('Google account has no email');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return { googleId, email };
|
|
115
|
+
}
|
|
76
116
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MigrationService.d.ts","sourceRoot":"","sources":["../../src/services/MigrationService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MigrationService.d.ts","sourceRoot":"","sources":["../../src/services/MigrationService.ts"],"names":[],"mappings":"AAeA;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAgB;IACnC;;;;;;;;OAQG;WACU,SAAS,CAAC,MAAM,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;CAkDtD"}
|