5htp-core 0.1.1 → 0.1.2-2

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "5htp-core",
3
3
  "description": "5-HTP, scientifically called 5-Hydroxytryptophan, is the precursor of happiness neurotransmitter.",
4
- "version": "0.1.1",
4
+ "version": "0.1.2-2",
5
5
  "author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
6
6
  "repository": "git://github.com/gaetanlegac/5htp-core.git",
7
7
  "license": "MIT",
@@ -58,6 +58,8 @@
58
58
  "nodemailer": "^6.6.3",
59
59
  "path-to-regexp": "^6.2.0",
60
60
  "picomatch": "^2.3.1",
61
+ "preact": "^10.5.15",
62
+ "preact-render-to-string": "^5.1.19",
61
63
  "react-scrollbars-custom": "^4.0.27",
62
64
  "react-slider": "^2.0.1",
63
65
  "react-textarea-autosize": "^8.3.3",
@@ -66,7 +68,6 @@
66
68
  "request": "^2.88.2",
67
69
  "sharp": "^0.29.1",
68
70
  "sql-formatter": "^4.0.2",
69
- "ts-alias": "^0.0.3-1",
70
71
  "tslog": "^3.2.2",
71
72
  "uuid": "^8.3.2",
72
73
  "uuid-by-string": "^3.0.4",
@@ -83,9 +84,5 @@
83
84
  "@types/universal-analytics": "^0.4.5",
84
85
  "@types/webpack-env": "^1.16.2",
85
86
  "@types/ws": "^7.4.7"
86
- },
87
- "peerDependencies": {
88
- "preact": "^10.5.15",
89
- "preact-render-to-string": "^5.1.19"
90
- }
87
+ }
91
88
  }
@@ -1,3 +1,10 @@
1
+ .white-card() {
2
+ background: white;
3
+ box-shadow: 0 3px 2px fade(#000, 10%);
4
+ border: solid 1px fade(#000, 10%);
5
+ border-radius: @radius;
6
+ }
7
+
1
8
  .card,
2
9
  .input.text,
3
10
  .btn,
@@ -7,10 +14,7 @@ i.solid {
7
14
  .build-theme-bg( #fff, #8E8E8E);
8
15
 
9
16
  &:not(.bg) {
10
- background: white;
11
- box-shadow: 0 3px 2px fade(#000, 10%);
12
- border: solid 1px fade(#000, 10%);
13
- border-radius: @radius;
17
+ .white-card();
14
18
  }
15
19
 
16
20
  .bg & {
@@ -29,7 +29,7 @@ export type Props = {
29
29
  cover?: {
30
30
  color?: string,
31
31
  title?: string,
32
- logo?: string
32
+ logo?: ComponentChild
33
33
  },
34
34
  metas: TMeta[],
35
35
  class?: string,
@@ -19,7 +19,6 @@ import SocketClient from './socket';
19
19
  /*----------------------------------
20
20
  - TYPES
21
21
  ----------------------------------*/
22
- import { User, GuestUser } from '@common/models';
23
22
 
24
23
  import type { Layout } from '@common/router';
25
24
 
@@ -63,7 +62,7 @@ export const useState = <TData extends TObjetDonnees>(initial: TData): [
63
62
  export class ClientContext {
64
63
 
65
64
  public context = this; // To access to the full nstance within a destructuration
66
- public user: User | typeof GuestUser;
65
+ public user: User | null;
67
66
 
68
67
  public id = Date.now();
69
68
  public bridges: { [name: string]: Function } = {};
@@ -109,7 +108,7 @@ export class ClientContext {
109
108
  ) {
110
109
 
111
110
  this.request = request;
112
- this.user = this.request.user || { ...GuestUser };
111
+ this.user = this.request.user || null;
113
112
 
114
113
  }
115
114
 
@@ -120,7 +119,7 @@ export class ClientContext {
120
119
  // Actions on the native app
121
120
  reloadDaemon: () => { },
122
121
  reloadGui: () => {
123
- this.request.response?.redirect('/');
122
+ this.page?.go('/');
124
123
  },
125
124
  optimize: () => {},
126
125
 
@@ -14,7 +14,6 @@ import router from '@client/router';
14
14
  import { location } from '@client/router/request/history';
15
15
  import coreRoutes from '@client/pages/**/*.tsx';
16
16
  import appRoutes from '@/client/pages/**/*.tsx';
17
- import { GuestUser } from '@common/models';
18
17
 
19
18
  import ClientResponse from './router/response';
20
19
  import ClientRequest from './router/request';
@@ -99,7 +98,7 @@ try {
99
98
  if (!route)
100
99
  throw new Error(`Route ${ssrResponse.page.id} was not found in ssr routes list.`);
101
100
 
102
- context.user = request.user = ssrResponse.user || { ...GuestUser };
101
+ context.user = request.user = ssrResponse.user || null;
103
102
 
104
103
  request.data = ssrResponse.request.data;
105
104
 
@@ -0,0 +1,36 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import React from 'react';
7
+ import type { ComponentChild } from 'preact';
8
+ import { history } from './request/history';
9
+
10
+ /*----------------------------------
11
+ - COMPONENT
12
+ ----------------------------------*/
13
+ // Simple link
14
+ export const Link = ({ to, ...props }: {
15
+ to: string,
16
+ children?: ComponentChild,
17
+ class?: string,
18
+ className?: string
19
+ } & React.HTMLProps<HTMLAnchorElement>) => {
20
+
21
+ // External = open in new tab by default
22
+ if (to[0] !== '/' || to.startsWith('//'))
23
+ props.target = '_blank';
24
+ // Otherwise, propagate to the router
25
+ else
26
+ props.onClick = (e) => {
27
+ history?.push(to);
28
+ e.preventDefault();
29
+ return false
30
+ }
31
+
32
+ return (
33
+ <a {...props} href={to} />
34
+ )
35
+
36
+ }
@@ -4,119 +4,102 @@
4
4
 
5
5
  // Npm
6
6
  import React from 'react';
7
- import type { ComponentChild } from 'preact';
8
- import type { Location } from 'history';
9
7
 
10
8
  // Core: libs
11
9
  import ClientRequest from './request';
12
10
  import ClientResponse from './response';
13
- import { history } from './request/history';
14
11
 
15
12
  // Core: types
16
- import BaseRouter, { TBaseRoute, TRouteOptions, defaultOptions, } from '@common/router'
13
+ import BaseRouter, { defaultOptions, } from '@common/router'
17
14
  import { PageResponse } from '@common/router/response';
18
- import { TFetcher, TFetcherList } from '@common/router/request';
19
- import type { TSsrData, default as ServerResponse } from '@server/services/router/response';
15
+ import type { TSsrData } from '@server/services/router/response';
20
16
  import type { ClientContext } from '@client/context';
21
17
 
22
18
  // Type xports
23
19
  export type { default as ClientResponse } from "./response";
20
+ export { Link } from './Link';
21
+ import type {
22
+ TClientRoute,
23
+ TUnresolvedRoute,
24
+ TSsrUnresolvedRoute,
25
+ TRoutesLoaders,
26
+ TRouteCallback,
27
+ TFetchedRoute,
28
+ TRegisterPageArgs
29
+ } from './route';
30
+
31
+ // Temporary
32
+ // TODO: Import these types directly from router/routes
33
+ export type {
34
+ TClientRoute,
35
+ TUnresolvedRoute,
36
+ TSsrUnresolvedRoute,
37
+ TRoutesLoaders,
38
+ TRouteCallback,
39
+ TFetchedRoute,
40
+ TRegisterPageArgs,
41
+ TFrontController
42
+ } from './route';
24
43
 
25
44
  /*----------------------------------
26
- - TYPES: PARTIAL ROUTES
45
+ - CONFIG
27
46
  ----------------------------------*/
28
47
 
29
- export type TSsrUnresolvedRoute = Pick<TClientRoute, 'type' | 'keys'> & {
30
- regex: string,
31
- chunk: string,
32
- }
33
-
34
- export type TUnresolvedRoute = Pick<TClientRoute, 'type' | 'keys'> & {
35
- regex: RegExp,
36
- chunk: string,
37
- load: TRouteLoader,
38
- }
39
-
40
- type TFetchedRoute = Pick<TClientRoute, 'path' | 'options' | 'controller' | 'renderer' | 'method'>
48
+ const debug = true;
49
+ const LogPrefix = '[router]'
41
50
 
42
51
  /*----------------------------------
43
- - TYPES: REGISTER
52
+ - TYPES
44
53
  ----------------------------------*/
45
54
 
46
- type TRouteLoader = () => Promise<{ default: TFetchedRoute }>;
47
-
48
- export type TRoutesLoaders = {
49
- [chunkId: string]: /* Preloaded via require() */TFetchedRoute | /* Loader via import() */TRouteLoader/* | undefined*/
50
- }
55
+ export type THookCallback = (request: ClientRequest) => void;
51
56
 
52
- type TRouteCallback = (route?: TClientRoute) => void;
53
-
54
- export type TRegisterPageArgs<TControllerData extends TFetcherList = {}> = [
55
- path: string,
56
- options: Partial<TRouteOptions>,
57
- controller: TFrontController<TControllerData> | null,
58
- renderer: TFrontRenderer<TControllerData>
59
- ];
57
+ type THookName = 'locationChange'
60
58
 
61
59
  /*----------------------------------
62
- - TYPES: COMPLETE ROUTES
60
+ - ROUTER
63
61
  ----------------------------------*/
62
+ class Router extends BaseRouter {
64
63
 
65
- export type TClientRoute = TBaseRoute & {
66
- type: 'PAGE',
67
- method: 'GET',
68
- controller: TFrontController | null,
69
- renderer: TFrontRenderer
70
- }
64
+ /*----------------------------------
65
+ - HOOKS
66
+ ----------------------------------*/
67
+ private hooks: {
68
+ [hookname in THookName]?: (THookCallback | null)[]
69
+ } = {}
71
70
 
72
- // https://stackoverflow.com/questions/44851268/typescript-how-to-extract-the-generic-parameter-from-a-type
73
- type TypeWithGeneric<T> = TFetcher<T>
74
- type extractGeneric<Type> = Type extends TypeWithGeneric<infer X> ? X : never
75
-
76
- export type TFrontController<TControllerData extends TFetcherList = {}> =
77
- (urlParams: TObjetDonnees, context: ClientContext) => TControllerData
78
-
79
- export type TFrontRenderer<TControllerData extends TFetcherList = {}> = (
80
- data: {
81
- [Property in keyof TControllerData]: undefined | (extractGeneric<TControllerData[Property]> extends ((...args: any[]) => any)
82
- ? ThenArg<ReturnType< extractGeneric<TControllerData[Property]> >>
83
- : extractGeneric<TControllerData[Property]>
84
- )
85
- },
86
- context: ClientContext
87
- ) => ComponentChild
88
-
89
- // Simple link
90
- export const Link = ({ to, ...props }: {
91
- to: string,
92
- children?: ComponentChild,
93
- class?: string,
94
- className?: string
95
- }) => {
96
-
97
- // External = open in new tab by default
98
- if (to[0] !== '/' || to.startsWith('//'))
99
- props.target = '_blank';
100
- // Otherwise, propagate to the router
101
- else
102
- props.onClick = (e) => {
103
- history?.push(to);
104
- e.preventDefault();
105
- return false
106
- }
71
+ public on( hookName: THookName, callback: THookCallback ) {
107
72
 
108
- return (
109
- <a {...props} href={to} />
110
- )
73
+ debug && console.info(LogPrefix, `Register hook ${hookName}`);
111
74
 
112
- }
75
+ let cbIndex: number;
76
+ let callbacks = this.hooks[ hookName ];
77
+ if (!callbacks) {
78
+ cbIndex = 0;
79
+ callbacks = this.hooks[ hookName ] = [callback]
80
+ } else {
81
+ cbIndex = callbacks.length;
82
+ callbacks.push(callback);
83
+ }
113
84
 
114
- const debug = true;
85
+ // Listener remover
86
+ return () => {
87
+ debug && console.info(LogPrefix, `De-register hook ${hookName} (index ${cbIndex})`);
88
+ delete (callbacks as THookCallback[])[ cbIndex ];
89
+ }
115
90
 
116
- /*----------------------------------
117
- - ROUTER
118
- ----------------------------------*/
119
- class Router extends BaseRouter {
91
+ }
92
+ private runHook( hookName: THookName, request: ClientRequest ) {
93
+ const callbacks = this.hooks[hookName];
94
+ if (callbacks)
95
+ for (const callback of callbacks)
96
+ // callback can be null since we use delete to unregister
97
+ callback && callback(request);
98
+ }
99
+
100
+ /*----------------------------------
101
+ - ROUTES MANAGEMENT
102
+ ----------------------------------*/
120
103
 
121
104
  public disableResolver = false;
122
105
 
@@ -171,6 +154,8 @@ class Router extends BaseRouter {
171
154
  public async resolve( request: ClientRequest, context: ClientContext ): Promise<PageResponse | undefined | null> {
172
155
  debug && console.log('Resolving request', request.path, Object.keys(request.data));
173
156
 
157
+ this.runHook('locationChange', request);
158
+
174
159
  for (let iRoute = 0; iRoute < this.routes.length; iRoute++) {
175
160
 
176
161
  let route = this.routes[iRoute];
@@ -0,0 +1,75 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import type { ComponentChild } from 'preact';
7
+
8
+ // Core
9
+ import type { ClientContext } from '@client/context';
10
+ import type { TBaseRoute, TRouteOptions, } from '@common/router'
11
+ import type { TFetcher, TFetcherList } from '@common/router/request';
12
+
13
+ /*----------------------------------
14
+ - TYPES: PARTIAL ROUTES
15
+ ----------------------------------*/
16
+
17
+ export type TSsrUnresolvedRoute = Pick<TClientRoute, 'type' | 'keys'> & {
18
+ regex: string,
19
+ chunk: string,
20
+ }
21
+
22
+ export type TUnresolvedRoute = Pick<TClientRoute, 'type' | 'keys'> & {
23
+ regex: RegExp | null,
24
+ chunk: string,
25
+ load: TRouteLoader,
26
+ }
27
+
28
+ export type TFetchedRoute = Pick<TClientRoute, 'path' | 'options' | 'controller' | 'renderer' | 'method'>
29
+
30
+ /*----------------------------------
31
+ - TYPES: REGISTER
32
+ ----------------------------------*/
33
+
34
+ type TRouteLoader = () => Promise<{ default: TFetchedRoute }>;
35
+
36
+ export type TRoutesLoaders = {
37
+ [chunkId: string]: /* Preloaded via require() */TFetchedRoute | /* Loader via import() */TRouteLoader/* | undefined*/
38
+ }
39
+
40
+ export type TRouteCallback = (route?: TClientRoute) => void;
41
+
42
+ export type TRegisterPageArgs<TControllerData extends TFetcherList = {}> = [
43
+ path: string,
44
+ options: Partial<TRouteOptions>,
45
+ controller: TFrontController<TControllerData> | null,
46
+ renderer: TFrontRenderer<TControllerData>
47
+ ];
48
+
49
+ /*----------------------------------
50
+ - TYPES: COMPLETE ROUTES
51
+ ----------------------------------*/
52
+
53
+ export type TClientRoute = TBaseRoute & {
54
+ type: 'PAGE',
55
+ method: 'GET',
56
+ controller: TFrontController | null,
57
+ renderer: TFrontRenderer
58
+ }
59
+
60
+ // https://stackoverflow.com/questions/44851268/typescript-how-to-extract-the-generic-parameter-from-a-type
61
+ type TypeWithGeneric<T> = TFetcher<T>
62
+ type extractGeneric<Type> = Type extends TypeWithGeneric<infer X> ? X : never
63
+
64
+ export type TFrontController<TControllerData extends TFetcherList = {}> =
65
+ (urlParams: TObjetDonnees, context: ClientContext) => TControllerData
66
+
67
+ export type TFrontRenderer<TControllerData extends TFetcherList = {}> = (
68
+ data: {
69
+ [Property in keyof TControllerData]: undefined | (extractGeneric<TControllerData[Property]> extends ((...args: any[]) => any)
70
+ ? ThenArg<ReturnType< extractGeneric<TControllerData[Property]> >>
71
+ : extractGeneric<TControllerData[Property]>
72
+ )
73
+ },
74
+ context: ClientContext
75
+ ) => ComponentChild
@@ -13,11 +13,13 @@ import type {
13
13
  TFrontRenderer
14
14
  } from '@client/router';
15
15
 
16
- import type { TApiServerRoute } from '@server/services/router';
16
+ import type { ClientContext } from '@client/context';
17
17
 
18
18
  import type { TSchema } from '@common/data/input/validate';
19
19
 
20
- import { TUserRole } from '@common/models';
20
+ import type { TApiServerRoute } from '@server/services/router';
21
+
22
+ import type { TUserRole } from '@server/services/auth/base';
21
23
 
22
24
  /*----------------------------------
23
25
  - TYPES: layouts
@@ -25,7 +27,7 @@ import { TUserRole } from '@common/models';
25
27
 
26
28
  import layouts from '@/client/pages/**/_layout/index.tsx';
27
29
 
28
- type LayoutComponent = ({ context: ClientContext }) => ComponentChild;
30
+ type LayoutComponent = (attributes: { context: ClientContext }) => ComponentChild;
29
31
  export type Layout = { path: string, Component: LayoutComponent }
30
32
  const getLayout = (routePath: string | undefined): Layout | undefined => {
31
33
 
@@ -84,7 +86,7 @@ export type TRouteOptions = {
84
86
 
85
87
  }
86
88
 
87
- export const defaultOptions: TRouteOptions = {
89
+ export const defaultOptions = {
88
90
  priority: 0,
89
91
  }
90
92
 
@@ -30,14 +30,8 @@ declare global {
30
30
 
31
31
  export type TEnvName = TEnvConfig["name"];
32
32
  export type TEnvConfig = {
33
-
34
33
  name: 'local' | 'server',
35
34
  profile: 'dev' | 'prod',
36
- level: 'silly' | 'info' | 'warn' | 'error',
37
-
38
- localIP: string,
39
- domain: string,
40
- url: string,
41
35
  }
42
36
 
43
37
  type AppIdentityConfig = {
@@ -93,20 +87,10 @@ export default class ConfigParser {
93
87
  console.log("Using environment:", process.env.NODE_ENV);
94
88
  return process.env.NODE_ENV === 'development' ? {
95
89
  name: 'local',
96
- profile: 'dev',
97
- level: 'silly',
98
-
99
- localIP: '86.76.176.80',
100
- domain: 'localhost:3010',
101
- url: 'http://localhost:3010',
90
+ profile: 'dev'
102
91
  } : {
103
92
  name: 'server',
104
93
  profile: 'prod',
105
- level: 'silly',
106
-
107
- localIP: '86.76.176.80',
108
- domain: 'megacharger.io',
109
- url: 'https://megacharger.io',
110
94
  }
111
95
  }
112
96
 
@@ -74,7 +74,7 @@ export class App {
74
74
  get: (container, serviceId, receiver) => {
75
75
 
76
76
  if (!( serviceId in container ) && typeof serviceId === 'string')
77
- throw new Error(`Service not loaded: ${serviceId}`);
77
+ throw new Error(`The following service is required as a dependancy: ${serviceId}`);
78
78
 
79
79
  return container[serviceId];
80
80
  }
@@ -34,7 +34,7 @@ export default ({ page, children: html, request, ssrData }: {
34
34
 
35
35
  const routesForClient = JSON.stringify( services.router.ssrRoutes );
36
36
 
37
- const fullUrl = services.http.url + request.path;
37
+ const fullUrl = services.http.publicUrl + request.path;
38
38
 
39
39
  let attrsBody = {
40
40
  className: [...page.bodyClass].join(' '),
@@ -10,7 +10,7 @@ import { OAuth2Client, LoginTicket } from 'google-auth-library';
10
10
  import { Forbidden } from '@common/errors';
11
11
 
12
12
  // App Libs
13
- import { IP } from '@models';
13
+ import { IP } from '@server/models';
14
14
  import app, { $ } from '@server/app';
15
15
 
16
16
  // Serbices
@@ -22,6 +22,8 @@ import '@server/services/database';
22
22
 
23
23
  import type ServerRequest from '@server/services/router/request';
24
24
 
25
+ export type TUserRole = typeof UserRoles[number]
26
+
25
27
  type AuthResponse = {
26
28
  token: string,
27
29
  redirect: string,
@@ -36,6 +38,12 @@ const config = app.config.auth;
36
38
 
37
39
  const LogPrefix = '[auth]'
38
40
 
41
+ export const UserRoles = ['USER', 'ADMIN', 'TEST', 'DEV'] as const
42
+
43
+ /*----------------------------------
44
+ - SERVICE CONVIG
45
+ ----------------------------------*/
46
+
39
47
  export type AuthConfig = {
40
48
  debug: boolean,
41
49
  logoutUrl: string,
@@ -81,16 +89,22 @@ export default abstract class UserAuthBase {
81
89
  public abstract beforeSignup(user: User): Promise< void >;
82
90
  public abstract afterSignup(user: User): Promise<{ redirect: string }>;
83
91
 
84
- private googleClient = app.config.auth.google
85
- ? new OAuth2Client(
86
- app.config.auth.google.web.clientId, // Google Client ID
87
- app.config.auth.google.web.secret, // Private key
88
- "https://" + app.env.domain + "/auth/google/response" // Redirect url
89
- )
90
- : undefined;
92
+ private googleClient: OAuth2Client | undefined;
91
93
 
92
94
  public async load() {
93
95
 
96
+ // Google auth client
97
+ if (app.config.auth.google) {
98
+
99
+ const httpConfig = app.services.http.publicUrl;
100
+
101
+ this.googleClient = new OAuth2Client(
102
+ app.config.auth.google.web.clientId, // Google Client ID
103
+ app.config.auth.google.web.secret, // Private key
104
+ httpConfig + "/auth/google/response" // Redirect url
105
+ );
106
+ }
107
+
94
108
  }
95
109
 
96
110
  public async FromEmail(
@@ -137,7 +151,8 @@ export default abstract class UserAuthBase {
137
151
  request: ServerRequest,
138
152
  ): Promise<AuthResponse> {
139
153
 
140
- if (!this.googleClient)
154
+ const googleConfig = app.config.auth.google;
155
+ if (!this.googleClient || !googleConfig)
141
156
  throw new Forbidden(`Authentication method disabled.`);
142
157
 
143
158
  if (codeOrToken === undefined)
@@ -148,15 +163,15 @@ export default abstract class UserAuthBase {
148
163
  return this.GoogleResponse('token', r.tokens.id_token, request);
149
164
  }
150
165
 
151
- config.debug && console.log(LogPrefix, "Auth via google", app.config.auth.google);
166
+ config.debug && console.log(LogPrefix, "Auth via google", googleConfig);
152
167
 
153
168
  let ticket: LoginTicket;
154
169
  try {
155
170
  ticket = await this.googleClient.verifyIdToken({
156
171
  idToken: codeOrToken,
157
172
  audience: [
158
- app.config.auth.google.web.clientId,
159
- app.config.auth.google.android.clientId,
173
+ googleConfig.web.clientId,
174
+ googleConfig.android.clientId,
160
175
  ]
161
176
  });
162
177
  } catch (error) {
@@ -32,6 +32,9 @@ type AppBugInfos = {
32
32
  }
33
33
 
34
34
  export type ServerBug = {
35
+
36
+ type: 'server',
37
+
35
38
  // Context
36
39
  hash: string,
37
40
  date: Date, // Timestamp
@@ -42,11 +45,15 @@ export type ServerBug = {
42
45
  ip: string | null | undefined,
43
46
 
44
47
  // Error
48
+ error: Error,
45
49
  stacktrace: string,
46
- logs: string
50
+ logs: string,
47
51
  }
48
52
 
49
53
  export type ApplicationBug = {
54
+
55
+ type: 'application',
56
+
50
57
  // Context
51
58
  hash: string,
52
59
  date: Date,
@@ -146,6 +153,9 @@ export default class BugReporter {
146
153
  );
147
154
 
148
155
  const bugReport: ServerBug = {
156
+
157
+ type: 'server',
158
+
149
159
  // Context
150
160
  hash: hash,
151
161
  date: now,
@@ -155,6 +165,7 @@ export default class BugReporter {
155
165
  user: request?.user?.name,
156
166
  ip: request?.ip,
157
167
  // Error
168
+ error,
158
169
  stacktrace: error.stack || error.message,
159
170
  logs: logsHtml
160
171
  }
@@ -193,6 +204,8 @@ export default class BugReporter {
193
204
 
194
205
  const bugReport: ApplicationBug = {
195
206
 
207
+ type: 'application',
208
+
196
209
  // Context
197
210
  hash: hash,
198
211
  date: now,
@@ -19,8 +19,15 @@ import BugReporter from "./bugReporter";
19
19
 
20
20
  export type TReportTransport = keyof typeof $
21
21
 
22
+ type TLogProfile = 'silly' | 'info' | 'warn' | 'error'
23
+
22
24
  export type ConsoleConfig = {
23
- bugReport: TReportTransport[]
25
+ dev: {
26
+ level: TLogProfile,
27
+ },
28
+ prod: {
29
+ level: TLogProfile
30
+ }
24
31
  }
25
32
 
26
33
  declare global {
@@ -120,6 +127,8 @@ export class Console {
120
127
  ----------------------------------*/
121
128
  public load() {
122
129
 
130
+ const envConfig = app.config.console[ app.env.profile ];
131
+
123
132
  this.logger = new Logger({
124
133
  overwriteConsole: true,
125
134
  //type: app.env.profile === 'dev' ? 'pretty' : 'hidden',
@@ -138,7 +147,7 @@ export class Console {
138
147
  warn: this.log.bind(this),
139
148
  error: this.log.bind(this),
140
149
  fatal: this.log.bind(this),
141
- }, app.env.level);
150
+ }, envConfig.level);
142
151
 
143
152
  setInterval(() => this.clean(), 60000);
144
153
 
@@ -11,7 +11,6 @@ import app, { $ } from '@server/app';
11
11
  //import templates from './templates';
12
12
  const templates = {} as {[template: string]: (data: any) => string}
13
13
  import { jsonToHtml } from './utils';
14
- import greetings from '@common/data/chaines/greetings';
15
14
 
16
15
  /*----------------------------------
17
16
  - SERVICE CONFIG
@@ -20,10 +19,14 @@ import greetings from '@common/data/chaines/greetings';
20
19
  export type EmailServiceConfig = {
21
20
  debug: boolean,
22
21
  default: {
23
- transporter: TransporterName,
22
+ transporter: string,
24
23
  from: string
25
24
  },
26
- transporters: Core.Config.EmailTransporters
25
+ transporters: Core.EmailTransporters,
26
+ bugReport: {
27
+ from: string,
28
+ to: string
29
+ }
27
30
  }
28
31
 
29
32
  declare global {
@@ -67,32 +70,15 @@ export type TCompleteEmail = With<THtmlEmail, {
67
70
  - TYPES: OPTIONS
68
71
  ----------------------------------*/
69
72
 
70
- type TransporterName = keyof Core.Config.EmailTransporters;
71
-
72
73
  export abstract class Transporter {
73
74
  public abstract send( emails: TCompleteEmail[] ): Promise<void>;
74
75
  }
75
76
 
76
77
  type TOptions = {
77
- transporter?: TransporterName,
78
+ transporter?: string,
78
79
  testing?: boolean
79
80
  }
80
81
 
81
- // TODO: to normalize
82
- export const userMail = (username: string, content: string) => `
83
- ${greetings(username)}<br/><br/>
84
-
85
- ${content}
86
-
87
- <br/><br/>
88
-
89
- If you need any help, send me an email at <a href="mailto:contact@gaetan-legac.fr">contact@gaetan-legac.fr</a>, and I will reply to as soon as I can.
90
-
91
- <br/><br/>
92
- Peace,<br/>
93
- <a href="https://www.linkedin.com/in/ga%C3%ABtanlegac/">Gaëtan Le Gac</a>
94
- `
95
-
96
82
  const config = app.config.email;
97
83
 
98
84
  /*----------------------------------
@@ -100,23 +86,31 @@ const config = app.config.email;
100
86
  ----------------------------------*/
101
87
  export default class Email {
102
88
 
103
- private transporters = {} as {[name in TransporterName]: Transporter};
104
- public register( name: TransporterName, transporter: (new () => Transporter) ) {
89
+ private transporters = {} as {[name: string]: Transporter};
90
+ public register( name: string, transporter: (new () => Transporter) ) {
105
91
  console.log(`[email] registering email transporter: ${name}`);
106
92
  this.transporters[ name ] = new transporter();
107
93
  }
108
94
 
109
95
  public load() {
110
- $.console.bugReport.addTransporter('email', (report, error) => this.send({
111
- to: app.identity.author.email,
112
- subject: "Server bug: " + error.message,
96
+ $.console.bugReport.addTransporter('email', (report) => this.send(report.type === 'server' ? {
97
+ from: config.bugReport.from,
98
+ to: config.bugReport.to,
99
+ subject: "Bug on server: " + (report.error.message),
113
100
  html: `
114
- <a href="${app.env.url}/admin/activity/requests/${report.channelId}">
101
+ <a href="${app.services.http.publicUrl}/admin/activity/requests/${report.channelId}">
115
102
  View Request details & console
116
103
  </a>
117
104
  <br/>
118
105
  ${report.logs}
119
106
  `
107
+ } : {
108
+ from: config.bugReport.from,
109
+ to: config.bugReport.to,
110
+ subject: "Bug on application " + (report.action),
111
+ html: {
112
+ ...report
113
+ }
120
114
  }));
121
115
 
122
116
  }
@@ -11,9 +11,6 @@ import path from 'path';
11
11
  import cors from 'cors';
12
12
  //var serveStatic = require('serve-static')
13
13
 
14
- // Npm: Autres
15
- import fs from 'fs-extra';
16
-
17
14
  // Middlewares (npm)
18
15
  import morgan from 'morgan';
19
16
  import hpp from 'hpp'; // Protection contre la pollution des reuqtees http
@@ -38,13 +35,18 @@ import { MiddlewareFormData } from './multipart';
38
35
  ----------------------------------*/
39
36
 
40
37
  export type HttpServiceConfig = {
41
- port: number
42
- ssl: boolean,
43
38
 
39
+ // Access
40
+ domain: string,
41
+ port: number,
42
+ ssl: number,
43
+
44
+ // Limitations / Load restriction
44
45
  upload: {
45
46
  maxSize: string // Expression package bytes
46
47
  },
47
48
 
49
+ // Protections against bots
48
50
  security: {
49
51
  recaptcha: {
50
52
  prv: string,
@@ -75,35 +77,19 @@ export default class HttpServer {
75
77
  public router: Router;
76
78
 
77
79
  public config: HttpServiceConfig;
78
- public url: string;
80
+ public publicUrl: string;
79
81
 
80
82
  public constructor() {
81
83
 
82
84
  // Init
83
85
  this.config = app.config.http;
84
- this.url = (this.config.ssl ? 'https' : 'http') + '://' + app.env.domain;
85
- this.express = express();
86
+ this.publicUrl = app.env.name === 'local'
87
+ ? 'http://localhost:' + this.config.port
88
+ : ((this.config.ssl ? 'https' : 'http') + '://' + this.config.domain);
86
89
 
87
90
  // Configure HTTP server
88
- if (!this.config.ssl) {
89
-
90
- this.http = http.createServer(this.express);
91
-
92
- } /*else if ('ssh' in app.env) {
93
-
94
- const ssh = app.env.ssh;
95
-
96
- console.log("Création du serveur https pour le socket:", '/home/' + ssh.login + '/ssl.*');
97
- this.http = https.createServer({
98
- key: fs.readFileSync('/home/' + ssh.login + '/ssl.key'),
99
- cert: fs.readFileSync('/home/' + ssh.login + '/ssl.cert'),
100
- ca: fs.readFileSync('/home/' + ssh.login + '/ssl.ca'),
101
- requestCert: true,
102
- rejectUnauthorized: false
103
- }, this.express);
104
-
105
- }*/ else
106
- throw new Error(`SSL was enabled, but no ssh config was specified in app.env (required to load ssl certificate files)`);
91
+ this.express = express();
92
+ this.http = http.createServer(this.express);
107
93
 
108
94
  // Start HTTP Server
109
95
  this.router = app.services.router;
@@ -248,7 +234,7 @@ export default class HttpServer {
248
234
  // Impossible donc de créer un serveur http ici, on le fera dans start.js
249
235
  console.info("Lancement du serveur web");
250
236
  this.http.listen(this.config.port, () => {
251
- console.info(`Serveur web démarré sur https://${app.env.domain}:${this.config.port}/`);
237
+ console.info(`Serveur web démarré sur ${this.publicUrl}`);
252
238
  });
253
239
 
254
240
  }
File without changes
@@ -96,8 +96,6 @@ export default class ServerRequest extends BaseRequest {
96
96
  this.cookies = res.req.cookies;
97
97
 
98
98
  this.ip = res.req.ip;
99
- if (this.ip === '::1' && app.env.localIP)
100
- this.ip = app.env.localIP;
101
99
 
102
100
  this.data = data || {};
103
101
 
@@ -10,14 +10,12 @@ import jwt from 'jsonwebtoken';
10
10
  // Cre
11
11
  import app, { $ } from '@server/app';
12
12
  import { InputError, AuthRequired, Forbidden } from '@common/errors';
13
- import { TUserRole } from '@common/models';
13
+ import type { TUserRole } from '@server/services/auth/base';
14
14
 
15
15
  /*----------------------------------
16
16
  - TYPES
17
17
  ----------------------------------*/
18
18
 
19
- import { User } from '@models';
20
-
21
19
  import type ServerRequest from '@server/services/router/request'
22
20
 
23
21
  type TJwtSession = { email: string }
@@ -80,6 +80,8 @@ export default class ProtectService {
80
80
 
81
81
  return conflict;*/
82
82
 
83
+ return false;
84
+
83
85
  }
84
86
 
85
87
  public async captcha(token?: string) {
@@ -7,17 +7,6 @@ declare module "@client/pages/\*.tsx" {
7
7
  export = value;
8
8
  }
9
9
 
10
- // Basic Models
11
- declare module "@/server/models/User" {
12
- const User: import("../common/models").User;
13
- export = User;
14
- }
15
-
16
- declare module "@/server/models/IP" {
17
- const IP: import("../common/models").IP;
18
- export = IP;
19
- }
20
-
21
10
  declare module "@/server/services/auth" {
22
11
  const UserAuthService: import("../server/services/auth/base").default;
23
12
  export = UserAuthService;
@@ -1,43 +0,0 @@
1
-
2
-
3
- export const UserRoles = ['USER', 'ADMIN', 'TEST', 'DEV'] as const
4
- export type TUserRole = typeof UserRoles[number]
5
-
6
- export interface User {
7
- name: string,
8
- email: string,
9
- emailHash: string,
10
- roles: TUserRole[],
11
-
12
- balance: number,
13
- banned?: Date,
14
- }
15
-
16
- export const GuestUser = {
17
- name: "Guest",
18
-
19
- balance: 10,
20
- multiplier: 1,
21
- level: 1,
22
-
23
- isGuest: true
24
- }
25
-
26
- export interface IP {
27
- address: string,
28
-
29
- country: string,
30
- isp?: string,
31
- user_name?: string,
32
-
33
- meet: Date,
34
- activity: Date,
35
- updated?: Date,
36
-
37
- iphub?: number,
38
- getipintel?: number,
39
- ipinfo?: number,
40
-
41
- banned?: Date,
42
- banReason?: string,
43
- }