@flowerforce/flowerbase 1.4.2-beta.3 → 1.4.2-beta.4
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/dist/auth/controller.d.ts.map +1 -1
- package/dist/auth/controller.js +8 -0
- package/dist/auth/providers/anon-user/controller.d.ts.map +1 -1
- package/dist/auth/providers/anon-user/controller.js +9 -15
- package/dist/auth/utils.js +8 -8
- package/package.json +1 -1
- package/src/auth/__tests__/controller.test.ts +51 -0
- package/src/auth/controller.ts +11 -0
- package/src/auth/providers/anon-user/__tests__/controller.test.ts +82 -0
- package/src/auth/providers/anon-user/controller.ts +9 -19
- package/src/auth/utils.ts +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/auth/controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAQzC;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/auth/controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAQzC;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,eAAe,iBA0JxD"}
|
package/dist/auth/controller.js
CHANGED
|
@@ -31,6 +31,14 @@ function authController(app) {
|
|
|
31
31
|
catch (error) {
|
|
32
32
|
console.error('Failed to ensure refresh token TTL index', error);
|
|
33
33
|
}
|
|
34
|
+
try {
|
|
35
|
+
yield db.collection(authCollection).createIndex({ email: 1 }, {
|
|
36
|
+
unique: true
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.error('Failed to ensure auth email unique index', error);
|
|
41
|
+
}
|
|
34
42
|
app.addHook(HANDLER_TYPE, app.jwtAuthentication);
|
|
35
43
|
/**
|
|
36
44
|
* Endpoint to retrieve the authenticated user's profile.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/anon-user/controller.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/anon-user/controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAOzC;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,eAAe,iBAmE5D"}
|
|
@@ -10,9 +10,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.anonUserController = anonUserController;
|
|
13
|
+
const bson_1 = require("bson");
|
|
13
14
|
const constants_1 = require("../../../constants");
|
|
14
|
-
const crypto_1 = require("../../../utils/crypto");
|
|
15
15
|
const handleUserRegistration_model_1 = require("../../../shared/models/handleUserRegistration.model");
|
|
16
|
+
const crypto_1 = require("../../../utils/crypto");
|
|
16
17
|
const utils_1 = require("../../utils");
|
|
17
18
|
/**
|
|
18
19
|
* Controller for handling anonymous user login.
|
|
@@ -41,30 +42,23 @@ function anonUserController(app) {
|
|
|
41
42
|
throw new Error('Anonymous authentication disabled');
|
|
42
43
|
}
|
|
43
44
|
const now = new Date();
|
|
44
|
-
const
|
|
45
|
+
const userId = new bson_1.ObjectId();
|
|
46
|
+
const anonEmail = `anon-${userId.toString()}@users.invalid`;
|
|
47
|
+
yield db.collection(authCollection).insertOne({
|
|
48
|
+
_id: userId,
|
|
49
|
+
email: anonEmail,
|
|
45
50
|
status: 'confirmed',
|
|
46
51
|
createdAt: now,
|
|
47
52
|
custom_data: {},
|
|
48
53
|
identities: [
|
|
49
54
|
{
|
|
55
|
+
id: userId.toString(),
|
|
56
|
+
provider_id: userId.toString(),
|
|
50
57
|
provider_type: handleUserRegistration_model_1.PROVIDER.ANON_USER,
|
|
51
58
|
provider_data: {}
|
|
52
59
|
}
|
|
53
60
|
]
|
|
54
61
|
});
|
|
55
|
-
const userId = insertResult.insertedId;
|
|
56
|
-
yield db.collection(authCollection).updateOne({ _id: userId }, {
|
|
57
|
-
$set: {
|
|
58
|
-
identities: [
|
|
59
|
-
{
|
|
60
|
-
id: userId.toString(),
|
|
61
|
-
provider_id: userId.toString(),
|
|
62
|
-
provider_type: handleUserRegistration_model_1.PROVIDER.ANON_USER,
|
|
63
|
-
provider_data: {}
|
|
64
|
-
}
|
|
65
|
-
]
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
62
|
const currentUserData = {
|
|
69
63
|
_id: userId,
|
|
70
64
|
user_data: {}
|
package/dist/auth/utils.js
CHANGED
|
@@ -15,10 +15,10 @@ exports.LOGIN_SCHEMA = {
|
|
|
15
15
|
username: {
|
|
16
16
|
type: 'string',
|
|
17
17
|
pattern: '^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$',
|
|
18
|
-
minLength:
|
|
18
|
+
minLength: 5,
|
|
19
19
|
maxLength: 254
|
|
20
20
|
},
|
|
21
|
-
password: { type: 'string', minLength:
|
|
21
|
+
password: { type: 'string', minLength: 6, maxLength: 128 }
|
|
22
22
|
},
|
|
23
23
|
required: ['username', 'password']
|
|
24
24
|
}
|
|
@@ -30,7 +30,7 @@ exports.RESET_SEND_SCHEMA = {
|
|
|
30
30
|
email: {
|
|
31
31
|
type: 'string',
|
|
32
32
|
pattern: '^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$',
|
|
33
|
-
minLength:
|
|
33
|
+
minLength: 5,
|
|
34
34
|
maxLength: 254
|
|
35
35
|
}
|
|
36
36
|
},
|
|
@@ -44,10 +44,10 @@ exports.RESET_CALL_SCHEMA = {
|
|
|
44
44
|
email: {
|
|
45
45
|
type: 'string',
|
|
46
46
|
pattern: '^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$',
|
|
47
|
-
minLength:
|
|
47
|
+
minLength: 5,
|
|
48
48
|
maxLength: 254
|
|
49
49
|
},
|
|
50
|
-
password: { type: 'string', minLength:
|
|
50
|
+
password: { type: 'string', minLength: 6, maxLength: 128 },
|
|
51
51
|
arguments: { type: 'array' }
|
|
52
52
|
},
|
|
53
53
|
required: ['email', 'password']
|
|
@@ -57,7 +57,7 @@ exports.CONFIRM_RESET_SCHEMA = {
|
|
|
57
57
|
body: {
|
|
58
58
|
type: 'object',
|
|
59
59
|
properties: {
|
|
60
|
-
password: { type: 'string', minLength:
|
|
60
|
+
password: { type: 'string', minLength: 6, maxLength: 128 },
|
|
61
61
|
token: { type: 'string' },
|
|
62
62
|
tokenId: { type: 'string' }
|
|
63
63
|
},
|
|
@@ -82,10 +82,10 @@ exports.REGISTRATION_SCHEMA = {
|
|
|
82
82
|
email: {
|
|
83
83
|
type: 'string',
|
|
84
84
|
pattern: '^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$',
|
|
85
|
-
minLength:
|
|
85
|
+
minLength: 5,
|
|
86
86
|
maxLength: 254
|
|
87
87
|
},
|
|
88
|
-
password: { type: 'string', minLength:
|
|
88
|
+
password: { type: 'string', minLength: 6, maxLength: 128 }
|
|
89
89
|
},
|
|
90
90
|
required: ['email', 'password']
|
|
91
91
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { authController } from '../controller'
|
|
2
|
+
|
|
3
|
+
jest.mock('../../constants', () => ({
|
|
4
|
+
AUTH_CONFIG: {
|
|
5
|
+
authCollection: 'auth_users',
|
|
6
|
+
refreshTokensCollection: 'refresh_tokens',
|
|
7
|
+
userCollection: 'users',
|
|
8
|
+
user_id_field: 'id'
|
|
9
|
+
},
|
|
10
|
+
DB_NAME: 'test-db',
|
|
11
|
+
DEFAULT_CONFIG: {
|
|
12
|
+
REFRESH_TOKEN_TTL_DAYS: 1
|
|
13
|
+
}
|
|
14
|
+
}))
|
|
15
|
+
|
|
16
|
+
describe('authController', () => {
|
|
17
|
+
it('creates a unique email index on the auth collection', async () => {
|
|
18
|
+
const authCollection = {
|
|
19
|
+
createIndex: jest.fn().mockResolvedValue('ok')
|
|
20
|
+
}
|
|
21
|
+
const refreshCollection = {
|
|
22
|
+
createIndex: jest.fn().mockResolvedValue('ok')
|
|
23
|
+
}
|
|
24
|
+
const db = {
|
|
25
|
+
collection: jest.fn((name: string) => {
|
|
26
|
+
if (name === 'auth_users') {
|
|
27
|
+
return authCollection
|
|
28
|
+
}
|
|
29
|
+
if (name === 'refresh_tokens') {
|
|
30
|
+
return refreshCollection
|
|
31
|
+
}
|
|
32
|
+
return { createIndex: jest.fn().mockResolvedValue('ok') }
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
const app = {
|
|
36
|
+
mongo: { client: { db: jest.fn().mockReturnValue(db) } },
|
|
37
|
+
addHook: jest.fn(),
|
|
38
|
+
get: jest.fn(),
|
|
39
|
+
post: jest.fn(),
|
|
40
|
+
delete: jest.fn(),
|
|
41
|
+
jwtAuthentication: jest.fn()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
await authController(app as unknown as never)
|
|
45
|
+
|
|
46
|
+
expect(authCollection.createIndex).toHaveBeenCalledWith(
|
|
47
|
+
{ email: 1 },
|
|
48
|
+
{ unique: true }
|
|
49
|
+
)
|
|
50
|
+
})
|
|
51
|
+
})
|
package/src/auth/controller.ts
CHANGED
|
@@ -27,6 +27,17 @@ export async function authController(app: FastifyInstance) {
|
|
|
27
27
|
console.error('Failed to ensure refresh token TTL index', error)
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
try {
|
|
31
|
+
await db.collection(authCollection).createIndex(
|
|
32
|
+
{ email: 1 },
|
|
33
|
+
{
|
|
34
|
+
unique: true
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error('Failed to ensure auth email unique index', error)
|
|
39
|
+
}
|
|
40
|
+
|
|
30
41
|
app.addHook(HANDLER_TYPE, app.jwtAuthentication)
|
|
31
42
|
|
|
32
43
|
/**
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { anonUserController } from '../controller'
|
|
2
|
+
import { PROVIDER } from '../../../../shared/models/handleUserRegistration.model'
|
|
3
|
+
|
|
4
|
+
jest.mock('../../../../constants', () => ({
|
|
5
|
+
AUTH_CONFIG: {
|
|
6
|
+
authCollection: 'auth_users',
|
|
7
|
+
refreshTokensCollection: 'refresh_tokens',
|
|
8
|
+
providers: {
|
|
9
|
+
'anon-user': { disabled: false }
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
DB_NAME: 'test-db',
|
|
13
|
+
DEFAULT_CONFIG: {
|
|
14
|
+
REFRESH_TOKEN_TTL_DAYS: 1,
|
|
15
|
+
ANON_USER_TTL_SECONDS: 3600
|
|
16
|
+
}
|
|
17
|
+
}))
|
|
18
|
+
|
|
19
|
+
describe('anonUserController', () => {
|
|
20
|
+
it('inserts anon users with a generated email', async () => {
|
|
21
|
+
let insertedDoc: Record<string, unknown> | undefined
|
|
22
|
+
const authCollection = {
|
|
23
|
+
createIndex: jest.fn().mockResolvedValue('ok'),
|
|
24
|
+
insertOne: jest.fn(async (doc: Record<string, unknown>) => {
|
|
25
|
+
insertedDoc = doc
|
|
26
|
+
return { insertedId: doc._id }
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
const refreshCollection = {
|
|
30
|
+
insertOne: jest.fn().mockResolvedValue({})
|
|
31
|
+
}
|
|
32
|
+
const db = {
|
|
33
|
+
collection: jest.fn((name: string) => {
|
|
34
|
+
if (name === 'auth_users') {
|
|
35
|
+
return authCollection
|
|
36
|
+
}
|
|
37
|
+
if (name === 'refresh_tokens') {
|
|
38
|
+
return refreshCollection
|
|
39
|
+
}
|
|
40
|
+
return authCollection
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let loginHandler: ((...args: unknown[]) => unknown) | undefined
|
|
45
|
+
const app = {
|
|
46
|
+
mongo: { client: { db: jest.fn().mockReturnValue(db) } },
|
|
47
|
+
post: jest.fn((path: string, handler: (...args: unknown[]) => unknown) => {
|
|
48
|
+
loginHandler = handler
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
await anonUserController(app as unknown as never)
|
|
53
|
+
|
|
54
|
+
const context = {
|
|
55
|
+
createRefreshToken: jest.fn(() => 'refresh'),
|
|
56
|
+
createAccessToken: jest.fn(() => 'access')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
await (loginHandler as (...args: unknown[]) => Promise<unknown>).call(context, {})
|
|
60
|
+
|
|
61
|
+
const doc = insertedDoc as {
|
|
62
|
+
_id: { toString: () => string }
|
|
63
|
+
email: string
|
|
64
|
+
identities: Array<{
|
|
65
|
+
id?: string
|
|
66
|
+
provider_id?: string
|
|
67
|
+
provider_type?: string
|
|
68
|
+
provider_data?: Record<string, unknown>
|
|
69
|
+
}>
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
expect(doc.email).toBe(`anon-${doc._id.toString()}@users.invalid`)
|
|
73
|
+
expect(doc.identities[0]).toEqual(
|
|
74
|
+
expect.objectContaining({
|
|
75
|
+
id: doc._id.toString(),
|
|
76
|
+
provider_id: doc._id.toString(),
|
|
77
|
+
provider_type: PROVIDER.ANON_USER,
|
|
78
|
+
provider_data: {}
|
|
79
|
+
})
|
|
80
|
+
)
|
|
81
|
+
})
|
|
82
|
+
})
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { ObjectId } from 'bson'
|
|
1
2
|
import { FastifyInstance } from 'fastify'
|
|
2
3
|
import { AUTH_CONFIG, DB_NAME, DEFAULT_CONFIG } from '../../../constants'
|
|
3
|
-
import { hashToken } from '../../../utils/crypto'
|
|
4
4
|
import { PROVIDER } from '../../../shared/models/handleUserRegistration.model'
|
|
5
|
+
import { hashToken } from '../../../utils/crypto'
|
|
5
6
|
import { AUTH_ENDPOINTS } from '../../utils'
|
|
6
7
|
import { LoginDto } from './dtos'
|
|
7
8
|
|
|
@@ -37,35 +38,24 @@ export async function anonUserController(app: FastifyInstance) {
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
const now = new Date()
|
|
40
|
-
const
|
|
41
|
+
const userId = new ObjectId()
|
|
42
|
+
const anonEmail = `anon-${userId.toString()}@users.invalid`
|
|
43
|
+
await db.collection(authCollection!).insertOne({
|
|
44
|
+
_id: userId,
|
|
45
|
+
email: anonEmail,
|
|
41
46
|
status: 'confirmed',
|
|
42
47
|
createdAt: now,
|
|
43
48
|
custom_data: {},
|
|
44
49
|
identities: [
|
|
45
50
|
{
|
|
51
|
+
id: userId.toString(),
|
|
52
|
+
provider_id: userId.toString(),
|
|
46
53
|
provider_type: PROVIDER.ANON_USER,
|
|
47
54
|
provider_data: {}
|
|
48
55
|
}
|
|
49
56
|
]
|
|
50
57
|
})
|
|
51
58
|
|
|
52
|
-
const userId = insertResult.insertedId
|
|
53
|
-
await db.collection(authCollection!).updateOne(
|
|
54
|
-
{ _id: userId },
|
|
55
|
-
{
|
|
56
|
-
$set: {
|
|
57
|
-
identities: [
|
|
58
|
-
{
|
|
59
|
-
id: userId.toString(),
|
|
60
|
-
provider_id: userId.toString(),
|
|
61
|
-
provider_type: PROVIDER.ANON_USER,
|
|
62
|
-
provider_data: {}
|
|
63
|
-
}
|
|
64
|
-
]
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
)
|
|
68
|
-
|
|
69
59
|
const currentUserData = {
|
|
70
60
|
_id: userId,
|
|
71
61
|
user_data: {}
|
package/src/auth/utils.ts
CHANGED
|
@@ -11,10 +11,10 @@ export const LOGIN_SCHEMA = {
|
|
|
11
11
|
username: {
|
|
12
12
|
type: 'string',
|
|
13
13
|
pattern: '^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$',
|
|
14
|
-
minLength:
|
|
14
|
+
minLength: 5,
|
|
15
15
|
maxLength: 254
|
|
16
16
|
},
|
|
17
|
-
password: { type: 'string', minLength:
|
|
17
|
+
password: { type: 'string', minLength: 6, maxLength: 128 }
|
|
18
18
|
},
|
|
19
19
|
required: ['username', 'password']
|
|
20
20
|
}
|
|
@@ -27,7 +27,7 @@ export const RESET_SEND_SCHEMA = {
|
|
|
27
27
|
email: {
|
|
28
28
|
type: 'string',
|
|
29
29
|
pattern: '^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$',
|
|
30
|
-
minLength:
|
|
30
|
+
minLength: 5,
|
|
31
31
|
maxLength: 254
|
|
32
32
|
}
|
|
33
33
|
},
|
|
@@ -42,10 +42,10 @@ export const RESET_CALL_SCHEMA = {
|
|
|
42
42
|
email: {
|
|
43
43
|
type: 'string',
|
|
44
44
|
pattern: '^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$',
|
|
45
|
-
minLength:
|
|
45
|
+
minLength: 5,
|
|
46
46
|
maxLength: 254
|
|
47
47
|
},
|
|
48
|
-
password: { type: 'string', minLength:
|
|
48
|
+
password: { type: 'string', minLength: 6, maxLength: 128 },
|
|
49
49
|
arguments: { type: 'array' }
|
|
50
50
|
},
|
|
51
51
|
required: ['email', 'password']
|
|
@@ -56,7 +56,7 @@ export const CONFIRM_RESET_SCHEMA = {
|
|
|
56
56
|
body: {
|
|
57
57
|
type: 'object',
|
|
58
58
|
properties: {
|
|
59
|
-
password: { type: 'string', minLength:
|
|
59
|
+
password: { type: 'string', minLength: 6, maxLength: 128 },
|
|
60
60
|
token: { type: 'string' },
|
|
61
61
|
tokenId: { type: 'string' }
|
|
62
62
|
},
|
|
@@ -84,10 +84,10 @@ export const REGISTRATION_SCHEMA = {
|
|
|
84
84
|
email: {
|
|
85
85
|
type: 'string',
|
|
86
86
|
pattern: '^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$',
|
|
87
|
-
minLength:
|
|
87
|
+
minLength: 5,
|
|
88
88
|
maxLength: 254
|
|
89
89
|
},
|
|
90
|
-
password: { type: 'string', minLength:
|
|
90
|
+
password: { type: 'string', minLength: 6, maxLength: 128 }
|
|
91
91
|
},
|
|
92
92
|
required: ['email', 'password']
|
|
93
93
|
}
|