5htp-core 0.1.2-3 → 0.2.0

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.
Files changed (126) hide show
  1. package/changelog.md +5 -0
  2. package/doc/TODO.md +71 -0
  3. package/package.json +5 -4
  4. package/src/client/{App.tsx → app/component.tsx} +15 -8
  5. package/src/client/app/index.ts +128 -0
  6. package/src/client/app/service.ts +34 -0
  7. package/src/client/app.tsconfig.json +0 -4
  8. package/src/client/components/Card/index.tsx +1 -1
  9. package/src/client/components/Dialog/Manager.tsx +39 -12
  10. package/src/client/components/Form/index.tsx +1 -1
  11. package/src/client/components/button.tsx +2 -2
  12. package/src/client/components/containers/Popover/index.tsx +1 -1
  13. package/src/client/components/data/spintext/index.tsx +1 -1
  14. package/src/client/components/dropdown/index.tsx +1 -1
  15. package/src/client/components/index.ts +8 -0
  16. package/src/client/components/input/BaseV2/index.tsx +1 -1
  17. package/src/client/components/input/UploadImage/index.tsx +1 -1
  18. package/src/client/hooks/index.ts +5 -0
  19. package/src/client/hooks/useState/index.tsx +2 -2
  20. package/src/client/hooks.ts +22 -0
  21. package/src/client/index.ts +5 -0
  22. package/src/client/pages/_layout/landing/index.tsx +0 -2
  23. package/src/client/pages/_messages/400.tsx +2 -2
  24. package/src/client/pages/_messages/401.tsx +2 -2
  25. package/src/client/pages/_messages/403.tsx +2 -2
  26. package/src/client/pages/_messages/404.tsx +2 -2
  27. package/src/client/pages/_messages/500.tsx +2 -2
  28. package/src/client/pages/bug.tsx +1 -1
  29. package/src/client/pages/useHeader.tsx +1 -1
  30. package/src/client/{context/captcha.ts → services/captcha/index.ts} +0 -0
  31. package/src/client/services/metrics/index.ts +37 -0
  32. package/src/client/{router → services/router/components}/Link.tsx +1 -1
  33. package/src/client/services/router/components/Page.tsx +59 -0
  34. package/src/client/{router/component.tsx → services/router/components/router.tsx} +43 -74
  35. package/src/client/services/router/index.tsx +448 -0
  36. package/src/client/services/router/request/api.ts +229 -0
  37. package/src/client/{router → services/router}/request/history.ts +0 -0
  38. package/src/client/services/router/request/index.ts +52 -0
  39. package/src/client/services/router/response/index.tsx +107 -0
  40. package/src/client/services/router/response/page.ts +95 -0
  41. package/src/client/{context/socket.ts → services/socket/index.ts} +2 -2
  42. package/src/client/utils/dom.ts +1 -1
  43. package/src/common/app/index.ts +9 -0
  44. package/src/common/data/chaines/index.ts +9 -6
  45. package/src/common/data/input/validate.ts +3 -166
  46. package/src/common/data/objets.ts +25 -0
  47. package/src/common/data/tableaux.ts +8 -0
  48. package/src/common/errors/index.ts +3 -1
  49. package/src/common/router/index.ts +67 -88
  50. package/src/common/router/layouts.ts +50 -0
  51. package/src/common/router/register.ts +62 -0
  52. package/src/common/router/request/api.ts +72 -0
  53. package/src/common/router/request/index.ts +31 -0
  54. package/src/common/router/{response.ts → response/index.ts} +9 -13
  55. package/src/common/router/response/page.ts +40 -56
  56. package/src/common/validation/index.ts +3 -0
  57. package/src/common/validation/schema.ts +184 -0
  58. package/src/common/validation/validator.ts +88 -0
  59. package/src/common/validation/validators.ts +313 -0
  60. package/src/server/app/config.ts +8 -10
  61. package/src/server/app/index.ts +81 -124
  62. package/src/server/app/service.ts +98 -0
  63. package/src/server/app.tsconfig.json +0 -8
  64. package/src/server/error/index.ts +13 -0
  65. package/src/server/index.ts +5 -0
  66. package/src/server/patch.ts +0 -6
  67. package/src/server/{data/Cache.ts → services/cache/index.ts} +79 -47
  68. package/src/server/services/console/bugReporter.ts +26 -16
  69. package/src/server/services/console/index.ts +50 -51
  70. package/src/server/services/cron/index.ts +12 -26
  71. package/src/server/services/database/bucket.ts +40 -0
  72. package/src/server/services/database/connection.ts +206 -75
  73. package/src/server/services/database/datatypes.ts +63 -40
  74. package/src/server/services/database/index.ts +295 -272
  75. package/src/server/services/database/metas.ts +246 -135
  76. package/src/server/services/database/stats.ts +151 -126
  77. package/src/server/services/email/index.ts +24 -54
  78. package/src/server/services/{router/request/services → metrics}/detect.ts +6 -10
  79. package/src/server/services/{router/request/services/tracking.ts → metrics/index.ts} +68 -45
  80. package/src/server/services/{http → router/http}/index.ts +19 -47
  81. package/src/server/services/{http → router/http}/multipart.ts +0 -0
  82. package/src/server/services/{http → router/http}/session.ts.old +0 -0
  83. package/src/server/services/router/index.ts +273 -203
  84. package/src/server/services/router/request/api.ts +73 -0
  85. package/src/server/services/router/request/index.ts +16 -95
  86. package/src/server/services/router/request/service.ts +21 -0
  87. package/src/server/services/router/response/index.ts +125 -64
  88. package/src/server/services/router/response/{filter → mask}/Filter.ts +0 -0
  89. package/src/server/services/router/response/{filter → mask}/index.ts +0 -2
  90. package/src/server/services/router/response/{filter → mask}/selecteurs.ts +0 -0
  91. package/src/server/services/router/response/page/document.tsx +194 -0
  92. package/src/server/services/router/response/page/index.tsx +157 -0
  93. package/src/server/{libs/pages → services/router/response/page}/schemaGenerator.ts +0 -0
  94. package/src/server/services/router/service.ts +48 -0
  95. package/src/server/services/schema/index.ts +47 -0
  96. package/src/server/services/schema/request.ts +55 -0
  97. package/src/server/services/schema/router.ts +33 -0
  98. package/src/server/services/socket/index.ts +38 -43
  99. package/src/server/services/socket/scope.ts +6 -4
  100. package/src/server/services/users/index.ts +203 -0
  101. package/src/server/services/{auth/base.ts → users/old.ts} +20 -111
  102. package/src/server/services/users/router/index.ts +72 -0
  103. package/src/server/services/users/router/request.ts +49 -0
  104. package/src/types/aliases.d.ts +43 -2
  105. package/templates/composant.tsx +1 -1
  106. package/templates/modal.tsx +1 -1
  107. package/templates/page.tsx +1 -1
  108. package/tsconfig.common.json +0 -4
  109. package/src/client/context/api.ts +0 -92
  110. package/src/client/context/index.ts +0 -246
  111. package/src/client/index.tsx +0 -129
  112. package/src/client/router/index.ts +0 -286
  113. package/src/client/router/request/index.ts +0 -106
  114. package/src/client/router/response/index.ts +0 -38
  115. package/src/client/router/route.ts +0 -75
  116. package/src/common/data/input/validators/basic.ts +0 -299
  117. package/src/common/data/input/validators/build.ts +0 -63
  118. package/src/common/router/request.ts +0 -83
  119. package/src/server/data/ApiClient.ts +0 -119
  120. package/src/server/data/input.ts +0 -41
  121. package/src/server/libs/pages/document.static.tsx +0 -41
  122. package/src/server/libs/pages/document.tsx +0 -203
  123. package/src/server/libs/pages/render.tsx +0 -90
  124. package/src/server/routes/auth.ts +0 -151
  125. package/src/server/services/redis/index.ts +0 -71
  126. package/src/server/services/router/request/services/auth.ts +0 -177
@@ -7,7 +7,7 @@ import ws from 'ws';
7
7
  import type { IncomingMessage } from 'http';
8
8
 
9
9
  // Core
10
- import AuthService from '@server/services/router/request/services/auth';
10
+ import type SocketService from '.';
11
11
  import context from '@server/context';
12
12
 
13
13
  /*----------------------------------
@@ -33,7 +33,7 @@ const activityDelay = 10 * 1000; // Clearn broken connections veery 10s
33
33
  /*----------------------------------
34
34
  - SCOPE
35
35
  ----------------------------------*/
36
- export default class SocketScope {
36
+ export default class SocketScope<TUser extends {}> {
37
37
 
38
38
  private connectEvent?: TConnectCallback;
39
39
  private disconnectEvent?: TConnectCallback;
@@ -41,7 +41,9 @@ export default class SocketScope {
41
41
  public users: { [username: string]: WebSocket[] } = {}
42
42
 
43
43
  public constructor(
44
- public path: string
44
+ public path: string,
45
+ private socket: SocketService<TUser>,
46
+ private app = socket.app
45
47
  ) {
46
48
 
47
49
  }
@@ -74,7 +76,7 @@ export default class SocketScope {
74
76
  context.run({ channelType: 'socket', channelId: this.path }, async () => {
75
77
 
76
78
  // Auth
77
- const username = await AuthService.decode(req);
79
+ const username = await this.socket.config.users.decode(req);
78
80
  if (!username) {
79
81
  console.log(`Rejecting connection on ${this.path} for client ${socket.ip} (${socket.id})}: Not authenticated`);
80
82
  socket.close(4004, "auth");
@@ -0,0 +1,203 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import jwt from 'jsonwebtoken';
7
+ import type express from 'express';
8
+ import type http from 'http';
9
+
10
+ // Core
11
+ import Application from '@server/app';
12
+ import Service from '@server/app/service';
13
+ import {
14
+ default as Router, Request as ServerRequest,
15
+ } from '@server/services/router';
16
+ import { InputError, AuthRequired, Forbidden } from '@common/errors';
17
+
18
+ /*----------------------------------
19
+ - TYPES
20
+ ----------------------------------*/
21
+
22
+ export type TUserRole = typeof UserRoles[number]
23
+
24
+ export type THttpRequest = express.Request | http.IncomingMessage;
25
+
26
+ /*----------------------------------
27
+ - CONFIG
28
+ ----------------------------------*/
29
+
30
+ const LogPrefix = '[auth]'
31
+
32
+ export const UserRoles = ['USER', 'ADMIN', 'TEST', 'DEV'] as const
33
+
34
+ /*----------------------------------
35
+ - SERVICE CONVIG
36
+ ----------------------------------*/
37
+
38
+ export type TConfig = {
39
+ debug: boolean,
40
+ logoutUrl: string,
41
+ jwt: {
42
+ // 2048 bits
43
+ key: string,
44
+ expiration: string,
45
+ },
46
+ google?: {
47
+ web: {
48
+ clientId: string,
49
+ secret: string,
50
+ },
51
+ android: {
52
+ clientId: string
53
+ }
54
+ }
55
+ }
56
+
57
+ export type THooks = {
58
+
59
+ }
60
+
61
+ /*----------------------------------
62
+ - SERVICE
63
+ ----------------------------------*/
64
+ export default abstract class UsersManagementService<
65
+ TUser extends {},
66
+ TApplication extends Application,
67
+ TJwtSession extends {} = {},
68
+ TRequest extends ServerRequest<Router> = ServerRequest<Router>,
69
+ > extends Service<TConfig, THooks, TApplication> {
70
+
71
+ public async register() {
72
+
73
+ }
74
+
75
+ public async start() {
76
+
77
+ }
78
+
79
+ public abstract login( ...args: any[] ): Promise<{ user: TUser, token: string }>;
80
+ public abstract decodeSession( jwt: TJwtSession, req: THttpRequest ): Promise<TUser>;
81
+
82
+ protected abstract displayName(user: TUser): string;
83
+ protected abstract displaySessionName(session: TJwtSession): string;
84
+
85
+ public async decode( req: THttpRequest, withData: true ): Promise<TUser | null>;
86
+ public async decode( req: THttpRequest, withData?: false ): Promise<TJwtSession | null>;
87
+ public async decode( req: THttpRequest, withData: boolean = false ): Promise<TJwtSession | TUser | null> {
88
+
89
+ this.config.debug && console.log(LogPrefix, 'Decode:', { cookie: req.cookies['authorization'] });
90
+
91
+ let token: string | undefined;
92
+ if (('cookies' in req) && typeof req.cookies['authorization'] === 'string')
93
+ token = req.cookies['authorization'];
94
+ // Desktop app webview do not support cookie config, so wwe retrieve it from headers
95
+ else if (typeof req.headers['authorization'] === 'string')
96
+ token = req.headers['authorization'];
97
+
98
+ if (token === undefined)
99
+ return this.unauthorized(req);
100
+
101
+ let session: TJwtSession;
102
+ try {
103
+ session = jwt.verify(token, this.config.jwt.key, {
104
+ maxAge: this.config.jwt.expiration
105
+ });
106
+ } catch (error) {
107
+ console.warn(LogPrefix, "Failed to decode jwt token:", token);
108
+ return this.unauthorized(req);
109
+ }
110
+
111
+ // Return email only
112
+ const sessionName = this.displaySessionName(session);
113
+ if (!withData) {
114
+ this.config.debug && console.log(LogPrefix, `Auth user ${sessionName} successfull. Return email only`);
115
+ return session;
116
+ }
117
+
118
+ // Deserialize full user data
119
+ this.config.debug && console.log(LogPrefix, `Deserialize user ${sessionName}`);
120
+ const user = await this.decodeSession(session, req);
121
+ this.config.debug && console.log(LogPrefix, `Deserialized user ${sessionName}:`, user);
122
+
123
+ return user;
124
+ }
125
+
126
+ public unauthorized( req: THttpRequest ) {
127
+
128
+ if ('res' in req) {
129
+ // If use auth failed, we remove the jwt token so we avoid to trigger the same auth error in the next request
130
+ console.warn(LogPrefix, "Auth failed: remove authorization cookie");
131
+ req.res?.clearCookie('authorization');
132
+ }
133
+
134
+ return null;
135
+ }
136
+
137
+ protected createSession( session: TJwtSession, request: TRequest ): string {
138
+
139
+ this.config.debug && console.info(LogPrefix, `Creating new session:`, session);
140
+
141
+ const token = jwt.sign(session, this.config.jwt.key);
142
+
143
+ this.config.debug && console.info(LogPrefix, `Generated JWT token for session:` + token);
144
+
145
+ request.res.cookie('authorization', token);
146
+
147
+ return token;
148
+ }
149
+
150
+ public logout( request: TRequest ) {
151
+
152
+ const user = request.user;
153
+ if (!user) return;
154
+
155
+ this.config.debug && console.info(LogPrefix, `Logout ${this.displayName(user)}`);
156
+ request.res.clearCookie('authorization');
157
+ }
158
+
159
+ public check( request: TRequest, role: TUserRole, motivation?: string): TUser;
160
+ public check( request: TRequest, role: false, motivation?: string): null;
161
+ public check( request: TRequest, role: TUserRole | boolean = 'USER', motivation?: string): TUser | null {
162
+
163
+ const user = request.user;
164
+
165
+ this.config.debug && console.warn(LogPrefix, `Check auth, role = ${role}. Current user =`, user);
166
+
167
+ if (user === undefined) {
168
+
169
+ throw new Error(`request.user has not been decoded.`);
170
+
171
+ // Shortcut: { auth: true } <=> { auth: 'USER' }
172
+ } else if (role === true) {
173
+
174
+ role = 'USER';
175
+
176
+ // No auth needed
177
+ } else if (role === false) {
178
+
179
+ return user;
180
+
181
+ // Not connected
182
+ } else if (user === null) {
183
+
184
+ this.config.debug && console.warn(LogPrefix, "Refusé pour anonyme (" + request.ip + ")");
185
+ throw new AuthRequired(motivation);
186
+
187
+ // Insufficient permissions
188
+ } else if (!user.roles.includes(role)) {
189
+
190
+ console.warn(LogPrefix, "Refusé: " + role + " pour " + this.displayName(user) + " (" + (user.roles ? user.roles.join(', ') : 'role inconnu') + ")");
191
+
192
+ throw new Forbidden("You do not have sufficient permissions to access this resource.");
193
+
194
+ } else {
195
+
196
+ console.warn(LogPrefix, "Autorisé " + role + " pour " + this.displayName(user) + " (" + user.roles.join(', ') + ")");
197
+
198
+ }
199
+
200
+ return user;
201
+ }
202
+
203
+ }
@@ -1,28 +1,8 @@
1
- /*----------------------------------
2
- - DEPENDANCES
3
- ----------------------------------*/
4
1
 
5
- // Npm
6
2
  import md5 from 'md5';
7
3
  import { OAuth2Client, LoginTicket } from 'google-auth-library';
8
4
 
9
- // Core libs
10
- import { Forbidden } from '@common/errors';
11
5
 
12
- // App Libs
13
- import { IP } from '@server/models';
14
- import app, { $ } from '@server/app';
15
-
16
- // Serbices
17
- import '@server/services/database';
18
-
19
- /*----------------------------------
20
- - TYPES
21
- ----------------------------------*/
22
-
23
- import type ServerRequest from '@server/services/router/request';
24
-
25
- export type TUserRole = typeof UserRoles[number]
26
6
 
27
7
  type AuthResponse = {
28
8
  token: string,
@@ -30,96 +10,26 @@ type AuthResponse = {
30
10
  user: User
31
11
  }
32
12
 
33
- /*----------------------------------
34
- - CONFIG
35
- ----------------------------------*/
36
-
37
- const config = app.config.auth;
38
-
39
- const LogPrefix = '[auth]'
40
-
41
- export const UserRoles = ['USER', 'ADMIN', 'TEST', 'DEV'] as const
42
-
43
- /*----------------------------------
44
- - SERVICE CONVIG
45
- ----------------------------------*/
46
-
47
- export type AuthConfig = {
48
- debug: boolean,
49
- logoutUrl: string,
50
- jwt: {
51
- // 2048 bits
52
- key: string,
53
- expiration: string,
54
- },
55
- google?: {
56
- web: {
57
- clientId: string,
58
- secret: string,
59
- },
60
- android: {
61
- clientId: string
62
- }
63
- }
64
- }
65
-
66
- declare global {
67
- namespace Core {
68
-
69
- interface Services {
70
- auth: UserAuthBase
71
- }
72
-
73
- namespace Config {
74
- interface Services {
75
- auth: AuthConfig
76
- }
77
- }
78
- }
79
- }
13
+ export default class {
80
14
 
81
- /*----------------------------------
82
- - SERVICE
83
- ----------------------------------*/
84
- export default abstract class UserAuthBase {
85
15
 
86
- public abstract getData( where: string ): Promise<User> ;
87
- public abstract SsrMask: string;
88
-
89
- public abstract beforeSignup(user: User): Promise< void >;
90
- public abstract afterSignup(user: User): Promise<{ redirect: string }>;
91
-
92
- private googleClient: OAuth2Client | undefined;
93
-
94
- public async load() {
16
+ public async start() {
95
17
 
96
18
  // Google auth client
97
- if (app.config.auth.google) {
19
+ if (this.config.google) {
98
20
 
99
- const httpConfig = app.services.http.publicUrl;
21
+ const httpConfig = this.app.http.publicUrl;
100
22
 
101
23
  this.googleClient = new OAuth2Client(
102
- app.config.auth.google.web.clientId, // Google Client ID
103
- app.config.auth.google.web.secret, // Private key
24
+ this.config.google.web.clientId, // Google Client ID
25
+ this.config.google.web.secret, // Private key
104
26
  httpConfig + "/auth/google/response" // Redirect url
105
27
  );
106
28
  }
107
-
108
29
  }
109
30
 
110
- public async FromEmail(
111
- email: string,
112
- request: ServerRequest,
113
- userInfo: Partial<User> = {}
114
- ) {
115
-
116
- const { token, user } = await this.Auth(email, request, false, userInfo);
117
-
118
- return await request.response.json(
119
- { token, user },
120
- `token user( ` + this.SsrMask + ` )`
121
- )
122
- }
31
+
32
+ private googleClient: OAuth2Client | undefined;
123
33
 
124
34
  public async FromGoogle(request: ServerRequest): Promise<string> {
125
35
 
@@ -151,7 +61,7 @@ export default abstract class UserAuthBase {
151
61
  request: ServerRequest,
152
62
  ): Promise<AuthResponse> {
153
63
 
154
- const googleConfig = app.config.auth.google;
64
+ const googleConfig = this.config.google;
155
65
  if (!this.googleClient || !googleConfig)
156
66
  throw new Forbidden(`Authentication method disabled.`);
157
67
 
@@ -163,7 +73,7 @@ export default abstract class UserAuthBase {
163
73
  return this.GoogleResponse('token', r.tokens.id_token, request);
164
74
  }
165
75
 
166
- config.debug && console.log(LogPrefix, "Auth via google", googleConfig);
76
+ this.config.debug && console.log(LogPrefix, "Auth via google", googleConfig);
167
77
 
168
78
  let ticket: LoginTicket;
169
79
  try {
@@ -205,7 +115,7 @@ export default abstract class UserAuthBase {
205
115
  userInfo: Partial<User> = {}
206
116
  ): Promise<AuthResponse> {
207
117
 
208
- let user = await this.getData('email = ' + $.sql.esc(email));
118
+ let user = await this.getData('email = ' + this.sql.esc(email));
209
119
  let ip: IP;
210
120
  let redirect: string;
211
121
  if (!user) { // Signup
@@ -232,7 +142,7 @@ export default abstract class UserAuthBase {
232
142
 
233
143
  }
234
144
 
235
- /*await $.sql`
145
+ /*await this.sql`
236
146
  INSERT INTO UserLogin SET
237
147
  user = ${user.email},
238
148
  date = NOW(),
@@ -251,7 +161,7 @@ export default abstract class UserAuthBase {
251
161
  let username = email.split('@')[0];
252
162
 
253
163
  // Prefix username if alreasy existing
254
- const duplicates = await $.sql`
164
+ const duplicates = await this.sql`
255
165
  FROM User
256
166
  WHERE name REGEXP CONCAT('^', ${username}, '[0-9]*$');
257
167
  `.count();
@@ -275,12 +185,12 @@ export default abstract class UserAuthBase {
275
185
  // Referrer
276
186
  if (user.referrer !== undefined) {
277
187
 
278
- const refExists = await $.sql`FROM User WHERE name = ${user.referrer}`.exists();
188
+ const refExists = await this.sql`FROM User WHERE name = ${user.referrer}`.exists();
279
189
  if (!refExists)
280
190
  user.referrer = undefined;
281
191
  else {
282
192
 
283
- await $.sql.upsert('UserStats', {
193
+ await this.sql.upsert('UserStats', {
284
194
  user: user.referrer,
285
195
  date: new Date,
286
196
  refSignups: 1
@@ -291,8 +201,8 @@ export default abstract class UserAuthBase {
291
201
  }
292
202
 
293
203
  // Create user
294
- await $.sql.insert('User', user);
295
- await $.sql.update('logs.IP', { user_name: username }, { address: request.ip });
204
+ await this.sql.insert('User', user);
205
+ await this.sql.update('logs.IP', { user_name: username }, { address: request.ip });
296
206
 
297
207
  // Hook
298
208
  let redirect: string = '/';
@@ -303,7 +213,7 @@ export default abstract class UserAuthBase {
303
213
  // remove user.emailHash
304
214
 
305
215
  // Notif email
306
- await $.email.send({
216
+ await this.email.send({
307
217
  to: app.identity.author.email,
308
218
  subject: app.identity.name + ": New User",
309
219
  html: JSON.stringify(user)
@@ -342,7 +252,7 @@ export default abstract class UserAuthBase {
342
252
  return;
343
253
 
344
254
  // Check if user exists
345
- const referrerExists = await $.sql`FROM User WHERE name = ${referrer}`.count();
255
+ const referrerExists = await this.sql`FROM User WHERE name = ${referrer}`.count();
346
256
  if (referrerExists === 0)
347
257
  return;
348
258
 
@@ -354,7 +264,7 @@ export default abstract class UserAuthBase {
354
264
  response.cookie('r', referrer);
355
265
 
356
266
  // Count the clic
357
- await $.sql.upsert('UserStats', {
267
+ await this.sql.upsert('UserStats', {
358
268
  user: referrer,
359
269
  date: new Date,
360
270
  refClics: 1
@@ -364,5 +274,4 @@ export default abstract class UserAuthBase {
364
274
  }
365
275
 
366
276
  }
367
-
368
277
  }
@@ -0,0 +1,72 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+
7
+ // Core
8
+ import type Application from '@server/app';
9
+
10
+ import {
11
+ default as Router, Request as ServerRequest, TRoute,
12
+ RouterService
13
+ } from '@server/services/router';
14
+
15
+ // Specific
16
+ import type { default as UsersService, TUserRole } from '..';
17
+ import UsersRequestService from './request';
18
+
19
+ /*----------------------------------
20
+ - TYPES
21
+ ----------------------------------*/
22
+
23
+
24
+ /*----------------------------------
25
+ - CONFIG
26
+ ----------------------------------*/
27
+
28
+ const LogPrefix = '[router][auth]';
29
+
30
+ /*----------------------------------
31
+ - SERVICE
32
+ ----------------------------------*/
33
+ export default class AuthenticationRouterService<
34
+ TUser extends {} = {},
35
+ TRequest extends ServerRequest<Router> = ServerRequest<Router>,
36
+ > extends RouterService {
37
+
38
+ public constructor(
39
+ public users: UsersService<TUser, Application>,
40
+ public config = users.config
41
+ ) {
42
+
43
+ super();
44
+
45
+ }
46
+
47
+ public async register() {
48
+
49
+ // Decode current user
50
+ this.router.on('request', async (request: TRequest) => {
51
+
52
+ // TODO: Typings. (context.user ?)
53
+ const decoded = await this.users.decode( request.req, true);
54
+
55
+ console.log("DECODED", decoded);
56
+
57
+ request.user = decoded || null;
58
+ })
59
+
60
+ // Check route permissions
61
+ this.router.on('resolved', async (route: TRoute, request: TRequest) => {
62
+
63
+ if (route.options.auth !== undefined)
64
+ // TODO: How to pas the router type to router config ? Circular rfeerence ?
65
+ this.users.check(request, route.options.auth);
66
+ })
67
+ }
68
+
69
+ public requestService( request: TRequest ): UsersRequestService<TUser> {
70
+ return new UsersRequestService( request, this );
71
+ }
72
+ }
@@ -0,0 +1,49 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import jwt from 'jsonwebtoken';
7
+
8
+ // Core
9
+ import type { default as Router, Request as ServerRequest } from '@server/services/router';
10
+ import RequestService from '@server/services/router/request/service';
11
+ import { InputError, AuthRequired, Forbidden } from '@common/errors';
12
+
13
+ // Specific
14
+ import type AuthenticationRouterService from '.';
15
+ import type { default as UsersManagementService, TUserRole } from '..';
16
+
17
+ /*----------------------------------
18
+ - TYPES
19
+ ----------------------------------*/
20
+
21
+ /*----------------------------------
22
+ - MODULE
23
+ ----------------------------------*/
24
+ export default class UsersRequestService<
25
+ TUser extends {}
26
+ > extends RequestService {
27
+
28
+ public constructor(
29
+ request: ServerRequest<Router>,
30
+ public auth: AuthenticationRouterService,
31
+ public users = auth.users,
32
+ ) {
33
+ super(request);
34
+ }
35
+
36
+ public login( email: string ) {
37
+ return this.users.login( this.request, email );
38
+ }
39
+
40
+ public logout() {
41
+ return this.users.logout( this.request );
42
+ }
43
+
44
+ public check( role: TUserRole, motivation?: string): TUser;
45
+ public check( role: false, motivation?: string): null;
46
+ public check( role: TUserRole | boolean = 'USER', motivation?: string): TUser | null {
47
+ return this.users.check( this.request, role, motivation );
48
+ }
49
+ }
@@ -1,13 +1,54 @@
1
+ declare module "@/client/pages/\*\*/_layout/index.tsx" {
2
+ const Layout: import("../common/router/layouts").ImportedLayouts;
3
+ export = LayoutsList
4
+ }
5
+
1
6
  declare module "@/client/pages/\*.tsx" {
2
- const value: import("../client/router").TRoutesLoaders;
7
+ const value: import("../client/services/router").TRoutesLoaders;
3
8
  export = value;
4
9
  }
10
+
5
11
  declare module "@client/pages/\*.tsx" {
6
- const value: import("../client/router").TRoutesLoaders;
12
+ const value: import("../client/services/router").TRoutesLoaders;
7
13
  export = value;
8
14
  }
9
15
 
10
16
  declare module "@/server/services/auth" {
11
17
  const UserAuthService: import("../server/services/auth/base").default;
12
18
  export = UserAuthService;
19
+ }
20
+
21
+ declare module "@/server" {
22
+ const ServerApplicationClass: import("../server/app").default;
23
+ export = InstanceType<ServerApplicationClass>;
24
+ }
25
+
26
+ declare module "@/client" {
27
+ const ClientApplicationClass: import("../client/app").default;
28
+ export = InstanceType<ClientApplicationClass>;
29
+ }
30
+
31
+ declare module "@/client/context" {
32
+
33
+ const Test: true;
34
+
35
+ const ClientRouter: import('../client/services/router').default;
36
+ const ServerRouter: import('../server/services/router').default;
37
+
38
+ const TServerRouterRequestContext: import('../server/services/router/response').TRouterContext;
39
+ const TClientRouterRequestContext: import('../client/services/router/response').TRouterContext;
40
+
41
+ export const ClientContext = (
42
+ // TO Fix: TClientRouterRequestContext is unable to get the right type of CrossPathClient["router"]
43
+ // (it gets ClientApplication instead of CrossPathClient)
44
+ TClientRouterRequestContext<ClientRouter, ClientRouter["app"]>
45
+ |
46
+ TServerRouterRequestContext<ServerRouter>
47
+ )
48
+
49
+ export const ReactClientContext: preact.Context<ClientContext>;
50
+
51
+ const useContext: () => ClientContext;
52
+
53
+ export = useContext;
13
54
  }
@@ -8,7 +8,7 @@
8
8
  import React from 'react';
9
9
 
10
10
  // Core libs
11
- import useContext from '@client/context';
11
+ import useContext from '@/client/context';
12
12
 
13
13
  // Core components
14
14
  import Button from '@client/components/button';
@@ -8,7 +8,7 @@
8
8
  import React from 'react';
9
9
 
10
10
  // Cre libs
11
- import useContext from '@client/context';
11
+ import useContext from '@/client/context';
12
12
 
13
13
  // Core components
14
14
  import Card, { Props as CardProps } from '@client/components/Dialog/card';
@@ -9,7 +9,7 @@ import React from 'react';
9
9
 
10
10
  // Core
11
11
  import route from '@router';
12
- import { useState } from '@client/context';
12
+ import { useState } from '@/client/context';
13
13
 
14
14
  // Core components
15
15
  import Button from '@client/components/button';