@dotpress/auth 1.3.2 → 2.0.0-alpha.1
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/LICENSE +1 -1
- package/README.md +355 -329
- package/dist/index.d.ts +679 -8
- package/dist/index.js +1226 -20
- package/dist/index.js.map +1 -0
- package/package.json +32 -46
- package/dist/__tests__/functional/cookies.test.d.ts +0 -1
- package/dist/__tests__/functional/cookies.test.js +0 -621
- package/dist/__tests__/functional/handlers.test.d.ts +0 -1
- package/dist/__tests__/functional/handlers.test.js +0 -239
- package/dist/__tests__/functional/middlewares.test.d.ts +0 -1
- package/dist/__tests__/functional/middlewares.test.js +0 -111
- package/dist/__tests__/unit/cookies.test.d.ts +0 -1
- package/dist/__tests__/unit/cookies.test.js +0 -466
- package/dist/__tests__/unit/tokens.test.d.ts +0 -1
- package/dist/__tests__/unit/tokens.test.js +0 -225
- package/dist/lib/cookies.d.ts +0 -42
- package/dist/lib/cookies.js +0 -136
- package/dist/lib/generators.d.ts +0 -1
- package/dist/lib/generators.js +0 -4
- package/dist/lib/handlers.d.ts +0 -2
- package/dist/lib/handlers.js +0 -263
- package/dist/lib/ip.d.ts +0 -2
- package/dist/lib/ip.js +0 -15
- package/dist/lib/middleware.d.ts +0 -2
- package/dist/lib/middleware.js +0 -23
- package/dist/lib/settings.d.ts +0 -3
- package/dist/lib/settings.js +0 -42
- package/dist/lib/tokens.d.ts +0 -38
- package/dist/lib/tokens.js +0 -112
- package/dist/types/types.d.ts +0 -107
- package/dist/types/types.js +0 -1
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
-
import request from 'supertest';
|
|
3
|
-
import bcrypt from 'bcryptjs';
|
|
4
|
-
import { $clearRoutes, createApp } from 'dotpress';
|
|
5
|
-
import * as tokenFns from '../../lib/tokens.js';
|
|
6
|
-
import { configurePlugin } from '../../index.js';
|
|
7
|
-
describe('Handlers', () => {
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
vi.resetAllMocks();
|
|
10
|
-
$clearRoutes();
|
|
11
|
-
});
|
|
12
|
-
const dataProvider = {
|
|
13
|
-
storeRefreshToken: vi.fn(),
|
|
14
|
-
findRefreshToken: vi.fn(),
|
|
15
|
-
markRefreshTokenAsUsed: vi.fn(),
|
|
16
|
-
revokeTokens: vi.fn(),
|
|
17
|
-
findUserById: vi.fn(),
|
|
18
|
-
findUserIdentifiers: vi.fn(),
|
|
19
|
-
};
|
|
20
|
-
const onLoginFailedCallback = vi.fn();
|
|
21
|
-
const onLoginSuccessCallback = vi.fn();
|
|
22
|
-
const authPlugin = configurePlugin({
|
|
23
|
-
keys: {
|
|
24
|
-
secretKey: '',
|
|
25
|
-
publicKey: '',
|
|
26
|
-
},
|
|
27
|
-
dataProvider,
|
|
28
|
-
onLoginFailed: onLoginFailedCallback,
|
|
29
|
-
onLoginSuccess: onLoginSuccessCallback,
|
|
30
|
-
});
|
|
31
|
-
describe('Login Route', () => {
|
|
32
|
-
it('should return 401 if user not found', async () => {
|
|
33
|
-
const findUserIdentifiersFn = vi
|
|
34
|
-
.mocked(dataProvider.findUserIdentifiers)
|
|
35
|
-
.mockResolvedValue(undefined);
|
|
36
|
-
const app = await createApp({
|
|
37
|
-
plugins: [authPlugin],
|
|
38
|
-
});
|
|
39
|
-
const res = await request(app).post('/auth/login').send({
|
|
40
|
-
username: 'JaneDoe',
|
|
41
|
-
password: '123456',
|
|
42
|
-
client: 'User-Agent String',
|
|
43
|
-
});
|
|
44
|
-
expect(res.status).toBe(401);
|
|
45
|
-
expect(findUserIdentifiersFn).toHaveBeenCalledTimes(1);
|
|
46
|
-
expect(findUserIdentifiersFn).toHaveBeenCalledWith('JaneDoe');
|
|
47
|
-
expect(onLoginFailedCallback).toHaveBeenCalledTimes(1);
|
|
48
|
-
expect(onLoginFailedCallback).toHaveBeenCalledWith({
|
|
49
|
-
username: 'JaneDoe',
|
|
50
|
-
errorType: 'invalid_username',
|
|
51
|
-
client: 'User-Agent String',
|
|
52
|
-
ipAddress: '',
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
it('should return 401 if user password mismatches', async () => {
|
|
56
|
-
const findUserIdentifiersFn = vi
|
|
57
|
-
.mocked(dataProvider.findUserIdentifiers)
|
|
58
|
-
.mockResolvedValue({
|
|
59
|
-
userId: '101',
|
|
60
|
-
passwordHash: '',
|
|
61
|
-
});
|
|
62
|
-
const app = await createApp({
|
|
63
|
-
plugins: [authPlugin],
|
|
64
|
-
});
|
|
65
|
-
const res = await request(app).post('/auth/login').send({
|
|
66
|
-
username: 'JaneDoe',
|
|
67
|
-
password: '123456',
|
|
68
|
-
});
|
|
69
|
-
expect(res.status).toBe(401);
|
|
70
|
-
expect(findUserIdentifiersFn).toHaveBeenCalledTimes(1);
|
|
71
|
-
expect(findUserIdentifiersFn).toHaveBeenCalledWith('JaneDoe');
|
|
72
|
-
expect(onLoginFailedCallback).toHaveBeenCalledTimes(1);
|
|
73
|
-
expect(onLoginFailedCallback).toHaveBeenCalledWith({
|
|
74
|
-
username: 'JaneDoe',
|
|
75
|
-
errorType: 'invalid_password',
|
|
76
|
-
client: '',
|
|
77
|
-
ipAddress: '',
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
it('should return tokens if password is correct', async () => {
|
|
81
|
-
const pwdHash = await bcrypt.hash('123456', 10);
|
|
82
|
-
const findUserIdentifiersFn = vi
|
|
83
|
-
.mocked(dataProvider.findUserIdentifiers)
|
|
84
|
-
.mockResolvedValue({
|
|
85
|
-
userId: '101',
|
|
86
|
-
passwordHash: pwdHash,
|
|
87
|
-
});
|
|
88
|
-
vi.spyOn(tokenFns, 'generateTokensForUser').mockResolvedValue({
|
|
89
|
-
accessToken: 'acc-111222333',
|
|
90
|
-
refreshToken: 'ref-999888777',
|
|
91
|
-
});
|
|
92
|
-
const app = await createApp({
|
|
93
|
-
plugins: [authPlugin],
|
|
94
|
-
});
|
|
95
|
-
const res = await request(app).post('/auth/login').send({
|
|
96
|
-
username: 'JaneDoe',
|
|
97
|
-
password: '123456',
|
|
98
|
-
});
|
|
99
|
-
expect(res.status).toBe(200);
|
|
100
|
-
expect(findUserIdentifiersFn).toHaveBeenCalledTimes(1);
|
|
101
|
-
expect(findUserIdentifiersFn).toHaveBeenCalledWith('JaneDoe');
|
|
102
|
-
expect(onLoginSuccessCallback).toHaveBeenCalledTimes(1);
|
|
103
|
-
expect(onLoginSuccessCallback).toHaveBeenCalledWith({
|
|
104
|
-
userId: '101',
|
|
105
|
-
username: 'JaneDoe',
|
|
106
|
-
client: '',
|
|
107
|
-
ipAddress: '',
|
|
108
|
-
});
|
|
109
|
-
expect(res.body).toEqual({
|
|
110
|
-
userId: '101',
|
|
111
|
-
accessToken: 'acc-111222333',
|
|
112
|
-
refreshToken: 'ref-999888777',
|
|
113
|
-
expiresIn: expect.any(Number),
|
|
114
|
-
expiresAt: expect.any(String),
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
describe('Refresh Token Route', () => {
|
|
119
|
-
it('should return 401 if refresh token is invalid', async () => {
|
|
120
|
-
const generateTokenFn = vi
|
|
121
|
-
.spyOn(tokenFns, 'generateTokensFromRefreshToken')
|
|
122
|
-
.mockImplementation(() => {
|
|
123
|
-
throw new Error('Invalid_Refresh_Token');
|
|
124
|
-
});
|
|
125
|
-
const app = await createApp({
|
|
126
|
-
plugins: [authPlugin],
|
|
127
|
-
});
|
|
128
|
-
const res = await request(app).post('/auth/refresh').send({
|
|
129
|
-
accessToken: '123456789',
|
|
130
|
-
refreshToken: '000000000',
|
|
131
|
-
});
|
|
132
|
-
expect(res.status).toBe(401);
|
|
133
|
-
expect(res.body).toEqual({
|
|
134
|
-
status: 401,
|
|
135
|
-
error: 'UNAUTHORIZED',
|
|
136
|
-
message: 'INVALID_REFRESH_TOKEN',
|
|
137
|
-
});
|
|
138
|
-
expect(generateTokenFn).toHaveBeenCalledTimes(1);
|
|
139
|
-
expect(generateTokenFn).toHaveBeenCalledWith({
|
|
140
|
-
accessToken: '123456789',
|
|
141
|
-
refreshToken: '000000000',
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
it('should return 200 OK and new tokens if refresh token is valid', async () => {
|
|
145
|
-
const generateTokenFn = vi
|
|
146
|
-
.spyOn(tokenFns, 'generateTokensFromRefreshToken')
|
|
147
|
-
.mockResolvedValue({
|
|
148
|
-
userId: '102',
|
|
149
|
-
accessToken: '111222333',
|
|
150
|
-
refreshToken: '111111111',
|
|
151
|
-
});
|
|
152
|
-
const app = await createApp({
|
|
153
|
-
plugins: [authPlugin],
|
|
154
|
-
});
|
|
155
|
-
const res = await request(app).post('/auth/refresh').send({
|
|
156
|
-
accessToken: '123456789',
|
|
157
|
-
refreshToken: '000000000',
|
|
158
|
-
});
|
|
159
|
-
expect(res.status).toBe(200);
|
|
160
|
-
expect(res.body).toEqual({
|
|
161
|
-
userId: '102',
|
|
162
|
-
accessToken: '111222333',
|
|
163
|
-
refreshToken: '111111111',
|
|
164
|
-
expiresIn: expect.any(Number),
|
|
165
|
-
expiresAt: expect.any(String),
|
|
166
|
-
});
|
|
167
|
-
expect(generateTokenFn).toHaveBeenCalledTimes(1);
|
|
168
|
-
expect(generateTokenFn).toHaveBeenCalledWith({
|
|
169
|
-
accessToken: '123456789',
|
|
170
|
-
refreshToken: '000000000',
|
|
171
|
-
});
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
describe('Current User Route', () => {
|
|
175
|
-
it('should return 401 if no current user', async () => {
|
|
176
|
-
const app = await createApp({
|
|
177
|
-
plugins: [authPlugin],
|
|
178
|
-
});
|
|
179
|
-
const res = await request(app).get('/auth/me');
|
|
180
|
-
expect(res.status).toBe(401);
|
|
181
|
-
});
|
|
182
|
-
it('should load current user', async () => {
|
|
183
|
-
const findUserFn = vi
|
|
184
|
-
.mocked(dataProvider.findUserById)
|
|
185
|
-
.mockResolvedValue({
|
|
186
|
-
id: 'usr-123',
|
|
187
|
-
username: 'JohnDoe111',
|
|
188
|
-
email: 'JohnDoe111@example.com',
|
|
189
|
-
});
|
|
190
|
-
const decodeFn = vi
|
|
191
|
-
.spyOn(tokenFns, 'validateAndDecodeAccessToken')
|
|
192
|
-
.mockReturnValue({ userId: 'usr-123' });
|
|
193
|
-
const app = await createApp({
|
|
194
|
-
plugins: [authPlugin],
|
|
195
|
-
});
|
|
196
|
-
const res = await request(app)
|
|
197
|
-
.get('/auth/me')
|
|
198
|
-
.set('Authorization', 'Bearer 0123456789');
|
|
199
|
-
expect(decodeFn).toBeCalledWith('0123456789');
|
|
200
|
-
expect(findUserFn).toBeCalledTimes(1);
|
|
201
|
-
expect(findUserFn).toBeCalledWith('usr-123');
|
|
202
|
-
expect(res.status).toBe(200);
|
|
203
|
-
expect(res.body).toEqual({
|
|
204
|
-
id: 'usr-123',
|
|
205
|
-
username: 'JohnDoe111',
|
|
206
|
-
email: 'JohnDoe111@example.com',
|
|
207
|
-
});
|
|
208
|
-
});
|
|
209
|
-
});
|
|
210
|
-
describe('Logout Route', () => {
|
|
211
|
-
it('should return 401 if no current user', async () => {
|
|
212
|
-
const app = await createApp({
|
|
213
|
-
plugins: [authPlugin],
|
|
214
|
-
});
|
|
215
|
-
const res = await request(app).post('/auth/logout');
|
|
216
|
-
expect(res.status).toBe(401);
|
|
217
|
-
});
|
|
218
|
-
it('should revoke token and return 200 OK', async () => {
|
|
219
|
-
vi.mocked(dataProvider.findUserById).mockResolvedValue({
|
|
220
|
-
id: 'usr-123',
|
|
221
|
-
username: 'JohnDoe111',
|
|
222
|
-
email: 'JohnDoe111@example.com',
|
|
223
|
-
});
|
|
224
|
-
vi.spyOn(tokenFns, 'validateAndDecodeAccessToken').mockReturnValue({
|
|
225
|
-
userId: 'usr-123',
|
|
226
|
-
});
|
|
227
|
-
const app = await createApp({
|
|
228
|
-
plugins: [authPlugin],
|
|
229
|
-
});
|
|
230
|
-
const res = await request(app)
|
|
231
|
-
.post('/auth/logout')
|
|
232
|
-
.set('Authorization', 'Bearer 0123456789');
|
|
233
|
-
expect(vi.mocked(dataProvider.revokeTokens)).toBeCalledTimes(1);
|
|
234
|
-
expect(vi.mocked(dataProvider.revokeTokens)).toBeCalledWith('usr-123');
|
|
235
|
-
expect(res.status).toBe(200);
|
|
236
|
-
expect(res.body).toEqual({ success: true });
|
|
237
|
-
});
|
|
238
|
-
});
|
|
239
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
-
import request from 'supertest';
|
|
3
|
-
import { createApp, defineRoute } from 'dotpress';
|
|
4
|
-
import * as tokenFns from '../../lib/tokens.js';
|
|
5
|
-
import { configurePlugin } from '../../index.js';
|
|
6
|
-
describe('Middlewares', () => {
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
vi.resetAllMocks();
|
|
9
|
-
});
|
|
10
|
-
const dataProvider = {
|
|
11
|
-
storeRefreshToken: vi.fn(),
|
|
12
|
-
findRefreshToken: vi.fn(),
|
|
13
|
-
markRefreshTokenAsUsed: vi.fn(),
|
|
14
|
-
revokeTokens: vi.fn(),
|
|
15
|
-
findUserById: vi.fn(),
|
|
16
|
-
findUserIdentifiers: vi.fn(),
|
|
17
|
-
};
|
|
18
|
-
const authPlugin = configurePlugin({
|
|
19
|
-
keys: {
|
|
20
|
-
secretKey: '',
|
|
21
|
-
publicKey: '',
|
|
22
|
-
},
|
|
23
|
-
dataProvider,
|
|
24
|
-
});
|
|
25
|
-
it('should not attach a user if token not provided', async () => {
|
|
26
|
-
defineRoute({
|
|
27
|
-
path: '/test',
|
|
28
|
-
handler: async ({ req }) => {
|
|
29
|
-
return {
|
|
30
|
-
status: 'ok',
|
|
31
|
-
user: req.user,
|
|
32
|
-
};
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
|
-
const app = await createApp({
|
|
36
|
-
plugins: [authPlugin],
|
|
37
|
-
});
|
|
38
|
-
const res = await request(app).get('/test');
|
|
39
|
-
expect(res.status).toBe(200);
|
|
40
|
-
expect(res.body).toEqual({
|
|
41
|
-
status: 'ok',
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
it('should attach a user to request if authenticated', async () => {
|
|
45
|
-
const decodeFn = vi
|
|
46
|
-
.spyOn(tokenFns, 'validateAndDecodeAccessToken')
|
|
47
|
-
.mockReturnValue({ userId: 'usr-123' });
|
|
48
|
-
const findUserFn = vi.mocked(dataProvider.findUserById).mockResolvedValue({
|
|
49
|
-
id: 'usr-123',
|
|
50
|
-
username: 'JohnDoe111',
|
|
51
|
-
email: 'JohnDoe111@example.com',
|
|
52
|
-
});
|
|
53
|
-
defineRoute({
|
|
54
|
-
path: '/test',
|
|
55
|
-
handler: async ({ req }) => {
|
|
56
|
-
return {
|
|
57
|
-
status: 'ok',
|
|
58
|
-
user: req.user,
|
|
59
|
-
};
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
|
-
const app = await createApp({
|
|
63
|
-
plugins: [authPlugin],
|
|
64
|
-
});
|
|
65
|
-
const res = await request(app)
|
|
66
|
-
.get('/test')
|
|
67
|
-
.set('Authorization', 'Bearer 1234567890');
|
|
68
|
-
expect(decodeFn).toBeCalledWith('1234567890');
|
|
69
|
-
expect(findUserFn).toBeCalledTimes(1);
|
|
70
|
-
expect(findUserFn).toBeCalledWith('usr-123');
|
|
71
|
-
expect(res.status).toBe(200);
|
|
72
|
-
expect(res.body).toEqual({
|
|
73
|
-
status: 'ok',
|
|
74
|
-
user: {
|
|
75
|
-
id: 'usr-123',
|
|
76
|
-
username: 'JohnDoe111',
|
|
77
|
-
email: 'JohnDoe111@example.com',
|
|
78
|
-
},
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
it('should not attach a user if token is valid but user provider returns nothing', async () => {
|
|
82
|
-
const decodeFn = vi
|
|
83
|
-
.spyOn(tokenFns, 'validateAndDecodeAccessToken')
|
|
84
|
-
.mockReturnValue({ userId: 'usr-123' });
|
|
85
|
-
const findUserFn = vi
|
|
86
|
-
.mocked(dataProvider.findUserById)
|
|
87
|
-
.mockResolvedValue(undefined);
|
|
88
|
-
defineRoute({
|
|
89
|
-
path: '/test',
|
|
90
|
-
handler: async ({ req }) => {
|
|
91
|
-
return {
|
|
92
|
-
status: 'ok',
|
|
93
|
-
user: req.user,
|
|
94
|
-
};
|
|
95
|
-
},
|
|
96
|
-
});
|
|
97
|
-
const app = await createApp({
|
|
98
|
-
plugins: [authPlugin],
|
|
99
|
-
});
|
|
100
|
-
const res = await request(app)
|
|
101
|
-
.get('/test')
|
|
102
|
-
.set('Authorization', 'Bearer 1234567890');
|
|
103
|
-
expect(decodeFn).toBeCalledWith('1234567890');
|
|
104
|
-
expect(findUserFn).toBeCalledTimes(1);
|
|
105
|
-
expect(findUserFn).toBeCalledWith('usr-123');
|
|
106
|
-
expect(res.status).toBe(200);
|
|
107
|
-
expect(res.body).toEqual({
|
|
108
|
-
status: 'ok',
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|