5htp-core 0.0.9 → 0.1.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.
- package/package.json +1 -1
- package/src/client/assets/css/components/button.less +47 -44
- package/src/client/assets/css/components/card.less +44 -15
- package/src/client/assets/css/components/components.less +25 -0
- package/src/client/assets/css/components/lists.less +30 -15
- package/src/client/assets/css/components/other.less +9 -5
- package/src/client/assets/css/core.less +1 -0
- package/src/client/assets/css/layouts.less +14 -0
- package/src/client/assets/css/medias.less +3 -1
- package/src/client/assets/css/spacing.less +2 -1
- package/src/client/assets/css/text/icons.less +1 -1
- package/src/client/assets/css/text/text.less +6 -5
- package/src/client/assets/css/text/titres.less +5 -5
- package/src/client/assets/css/theme.less +15 -13
- package/src/client/components/Dialog/card.tsx +1 -1
- package/src/client/components/Dialog/index.less +4 -3
- package/src/client/components/Form/index.tsx +2 -2
- package/src/client/components/button.tsx +1 -1
- package/src/client/components/chart/base.tsx +1 -1
- package/src/client/components/containers/Scrollbar/index.less +1 -1
- package/src/client/components/containers/tabs/index.tsx +2 -2
- package/src/client/components/data/progressbar/index.less +1 -1
- package/src/client/components/data/progressbar/index.tsx +3 -3
- package/src/client/components/input/BaseV2/index.less +4 -3
- package/src/client/components/input/Slider/index.less +1 -1
- package/src/client/components/input/UploadImage/index.less +1 -1
- package/src/client/context/index.ts +0 -1
- package/src/client/router/index.tsx +10 -3
- package/src/common/data/input/validate.ts +2 -2
- package/src/common/data/input/validators/basic.ts +18 -18
- package/src/common/data/input/validators/build.ts +2 -2
- package/src/common/errors/index.ts +17 -13
- package/src/server/data/Token.olg.ts +2 -2
- package/src/server/data/aes.ts +2 -2
- package/src/server/routes/auth.ts +6 -0
- package/src/server/services/auth/base.ts +20 -12
- package/src/server/services/cron/index.ts +2 -2
- package/src/server/services/database/index.ts +9 -11
- package/src/server/services/email/index.ts +2 -5
- package/src/server/services/router/index.ts +2 -2
- package/src/server/services/router/request/index.ts +1 -1
- package/src/server/services/router/request/services/auth.ts +5 -5
- package/src/server/services/router/request/services/detect.ts +4 -4
- package/src/server/services/router/request/services/tracking.ts +2 -2
- package/src/server/services/router/response/index.ts +3 -3
|
@@ -55,7 +55,7 @@ export const MenuOnglets = (props: JSX.HTMLAttributes<HTMLDivElement>) => {
|
|
|
55
55
|
|
|
56
56
|
const onglets = React.useContext(ContexteOnglets);
|
|
57
57
|
if (onglets === null)
|
|
58
|
-
return <>Contexte onglets
|
|
58
|
+
return <>Contexte onglets NotFound</>;
|
|
59
59
|
|
|
60
60
|
return (
|
|
61
61
|
<ul {...props} className={"row tabs" + (props.className ? ' ' + props.className : '')}>
|
|
@@ -76,7 +76,7 @@ export const Onglet = ({ id, children, asDiv, ...props }: {
|
|
|
76
76
|
|
|
77
77
|
const onglets = React.useContext(ContexteOnglets);
|
|
78
78
|
if (onglets === null)
|
|
79
|
-
return <>Contexte onglets
|
|
79
|
+
return <>Contexte onglets NotFound</>;
|
|
80
80
|
|
|
81
81
|
if (id !== onglets.actuel)
|
|
82
82
|
return null;
|
|
@@ -39,9 +39,9 @@ const hsl = (h: number, s: number = 80, l: number = 70) => `hsl(${Math.floor(h)}
|
|
|
39
39
|
export const couleurViaPc = (pc: number, couleurs: [number, number], ecart: number) => {
|
|
40
40
|
|
|
41
41
|
return {
|
|
42
|
-
couleur1: 'var(--
|
|
43
|
-
couleur2: 'var(--
|
|
44
|
-
couleurTxt: 'var(--
|
|
42
|
+
couleur1: 'var(--cAccent)',
|
|
43
|
+
couleur2: 'var(--cAccent)',
|
|
44
|
+
couleurTxt: 'var(--cAccent)'
|
|
45
45
|
}
|
|
46
46
|
const [couleurMin, couleurMax] = couleurs;
|
|
47
47
|
const couleur = couleurMin + (pc * (couleurMax - couleurMin));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
@import (reference) '~@/client/assets/theme.less';
|
|
2
2
|
|
|
3
|
-
@hInput: @sizeComponent
|
|
3
|
+
@hInput: @sizeComponent;
|
|
4
4
|
|
|
5
5
|
// TODO: Adapter textarea à input/basev2
|
|
6
6
|
.contChamp textarea {
|
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
border-radius: @radius;
|
|
25
25
|
|
|
26
26
|
--cBg2: #eee;
|
|
27
|
-
background: fade(#000, 5%);
|
|
28
27
|
//box-shadow: 1px 3px 0 fade(#000,4%), 0 1px 2px 0 fade(#000,2%);
|
|
29
28
|
|
|
30
29
|
> i {
|
|
31
30
|
margin-left: 0.5em;
|
|
31
|
+
color: var(--cTxtDesc);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
.contValue {
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
@gapAround: (@hInput - @labelH) / 2;
|
|
43
43
|
> .btn:first-child { margin-left: 0 - @gapAround / 2; }
|
|
44
44
|
|
|
45
|
-
@labelH:
|
|
45
|
+
@labelH: 0.6em;
|
|
46
46
|
label {
|
|
47
47
|
position: absolute;
|
|
48
48
|
left: 0; width: 100%;
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
align-items: center;
|
|
52
52
|
|
|
53
53
|
height: @labelH;
|
|
54
|
+
font-size: 0.8em;
|
|
54
55
|
color: var(--cTxtDesc);
|
|
55
56
|
transition: all .1s ease-out;
|
|
56
57
|
}
|
|
@@ -7,7 +7,6 @@ import React from 'react';
|
|
|
7
7
|
import type { ComponentChild } from 'preact';
|
|
8
8
|
|
|
9
9
|
// Core
|
|
10
|
-
import { AuthRequise } from '@common/errors';
|
|
11
10
|
import { createDialog } from '@client/components/Dialog/Manager';
|
|
12
11
|
import BaseRequest from '@common/router/request';
|
|
13
12
|
import router, { TClientRoute } from '@client/router';
|
|
@@ -94,12 +94,19 @@ export const Link = ({ to, ...props }: {
|
|
|
94
94
|
className?: string
|
|
95
95
|
}) => {
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
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) => {
|
|
99
103
|
history?.push(to);
|
|
100
104
|
e.preventDefault();
|
|
101
105
|
return false
|
|
102
|
-
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<a {...props} href={to} />
|
|
103
110
|
)
|
|
104
111
|
|
|
105
112
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { ComponentChild } from 'preact'
|
|
9
9
|
|
|
10
10
|
// Libs
|
|
11
|
-
import { Erreur, TListeErreursSaisie,
|
|
11
|
+
import { Erreur, TListeErreursSaisie, InputErrorSchema } from '@common/errors';
|
|
12
12
|
|
|
13
13
|
import { EXCLURE_VALEUR } from './validators/build';
|
|
14
14
|
|
|
@@ -216,7 +216,7 @@ export const validate = async <TSchemaA extends TSchema, TDonnees extends TObjet
|
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
if (nbErreurs !== 0 && opts.critique === true) {
|
|
219
|
-
throw new
|
|
219
|
+
throw new InputErrorSchema(erreurs);
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
debug && console.log('[schema][valider]', inputAvalider, '=>', output);
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from 'validator';
|
|
12
12
|
|
|
13
13
|
// Libs
|
|
14
|
-
import {
|
|
14
|
+
import { InputError } from '@common/errors';
|
|
15
15
|
import File from '@common/data/file';
|
|
16
16
|
|
|
17
17
|
// Libs métier
|
|
@@ -39,7 +39,7 @@ export const object = (opts: TSchemaChamp<object> & {} = {}) => champ<object>('o
|
|
|
39
39
|
}*/
|
|
40
40
|
|
|
41
41
|
if (typeof val !== 'object' || val.constructor !== Object)
|
|
42
|
-
throw new
|
|
42
|
+
throw new InputError("This value must be an object.");
|
|
43
43
|
|
|
44
44
|
return opts.valider ? await opts.valider(val, donneesSaisie, donneesRetour) : val;
|
|
45
45
|
},
|
|
@@ -60,7 +60,7 @@ export const array = (subtype?: Schema<any> | TSchemaChamp<any[]>, { choix, ...o
|
|
|
60
60
|
//console.log('VALIDER ARRAY', items, donneesSaisie);
|
|
61
61
|
|
|
62
62
|
if (!Array.isArray(items))
|
|
63
|
-
throw new
|
|
63
|
+
throw new InputError("This value must be an array.");
|
|
64
64
|
|
|
65
65
|
// Verif items
|
|
66
66
|
if (subtype !== undefined) {
|
|
@@ -86,7 +86,7 @@ export const choice = (values: any[], opts: TSchemaChamp<any> & {} = {}) => cham
|
|
|
86
86
|
valider: async (val: any, donneesSaisie: TObjetDonnees, donneesRetour: TObjetDonnees) => {
|
|
87
87
|
|
|
88
88
|
if (!values.includes(val))
|
|
89
|
-
throw new
|
|
89
|
+
throw new InputError("Invalid value. Must be: " + values.join(', '));
|
|
90
90
|
|
|
91
91
|
return opts.valider ? await opts.valider(val, donneesSaisie, donneesRetour) : val;
|
|
92
92
|
},
|
|
@@ -104,21 +104,21 @@ export const string = ({ min, max, ...opts }: TSchemaChamp<string> = {}) => cham
|
|
|
104
104
|
else if (typeof val === 'number')
|
|
105
105
|
return val.toString();
|
|
106
106
|
else if (typeof val !== 'string')
|
|
107
|
-
throw new
|
|
107
|
+
throw new InputError("This value must be a string.");
|
|
108
108
|
|
|
109
109
|
// Espaces blancs
|
|
110
110
|
val = trim(val);
|
|
111
111
|
|
|
112
112
|
// Taille min
|
|
113
113
|
if (val.length < min)
|
|
114
|
-
throw new
|
|
114
|
+
throw new InputError(`Must be at least ` + min + ' characters');
|
|
115
115
|
|
|
116
116
|
// Taille max
|
|
117
117
|
if (val.length > max)
|
|
118
118
|
if (corriger)
|
|
119
119
|
val = val.substring(0, max);
|
|
120
120
|
else
|
|
121
|
-
throw new
|
|
121
|
+
throw new InputError(`Must be up to ` + max + ' characters');
|
|
122
122
|
|
|
123
123
|
return opts.valider ? await opts.valider(val, donneesSaisie, donneesRetour) : val;
|
|
124
124
|
},
|
|
@@ -131,7 +131,7 @@ export const url = (opts: TSchemaChamp<string> & {} = {}) => string({
|
|
|
131
131
|
if (!isURL(val, {
|
|
132
132
|
// https://www.npmjs.com/package/validator
|
|
133
133
|
}))
|
|
134
|
-
throw new
|
|
134
|
+
throw new InputError(`Please provide a valid URL.`);
|
|
135
135
|
|
|
136
136
|
return opts.valider ? await opts.valider(val, donneesSaisie, donneesRetour, corriger) : val;
|
|
137
137
|
},
|
|
@@ -142,7 +142,7 @@ export const email = (opts: TSchemaChamp<string> & {} = {}) => string({
|
|
|
142
142
|
valider: async (val: any, donneesSaisie: TObjetDonnees, donneesRetour: TObjetDonnees, corriger?: boolean) => {
|
|
143
143
|
|
|
144
144
|
if (!isEmail(val))
|
|
145
|
-
throw new
|
|
145
|
+
throw new InputError("Please enter a valid email address.");
|
|
146
146
|
|
|
147
147
|
const retour = normalizeEmail(val);
|
|
148
148
|
|
|
@@ -177,7 +177,7 @@ const nombre = (float: boolean) => ({ ...opts }: TSchemaChamp<number> & {} = {})
|
|
|
177
177
|
if (corriger)
|
|
178
178
|
val = opts.min;
|
|
179
179
|
else
|
|
180
|
-
throw new
|
|
180
|
+
throw new InputError("This value must be a number.");
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
// Minimum
|
|
@@ -185,14 +185,14 @@ const nombre = (float: boolean) => ({ ...opts }: TSchemaChamp<number> & {} = {})
|
|
|
185
185
|
if (corriger)
|
|
186
186
|
val = opts.min;
|
|
187
187
|
else
|
|
188
|
-
throw new
|
|
188
|
+
throw new InputError(`Must be at least ` + opts.min);
|
|
189
189
|
|
|
190
190
|
// Maximum
|
|
191
191
|
if (opts.max !== undefined && val > opts.max)
|
|
192
192
|
if (corriger)
|
|
193
193
|
val = opts.max;
|
|
194
194
|
else
|
|
195
|
-
throw new
|
|
195
|
+
throw new InputError(`Must be up to ` + opts.max);
|
|
196
196
|
|
|
197
197
|
}
|
|
198
198
|
|
|
@@ -210,7 +210,7 @@ export const bool = (opts: TSchemaChamp<boolean> & {} = {}) => champ<boolean>('b
|
|
|
210
210
|
valider: async (val: any, donneesSaisie: TObjetDonnees, donneesRetour: TObjetDonnees) => {
|
|
211
211
|
|
|
212
212
|
if (typeof val !== 'boolean' && !['true', 'false'].includes(val))
|
|
213
|
-
throw new
|
|
213
|
+
throw new InputError("This value must be a boolean.");
|
|
214
214
|
|
|
215
215
|
val = !!val;
|
|
216
216
|
|
|
@@ -233,12 +233,12 @@ export const date = (opts: TSchemaChamp<Date> & {} = {}) => champ<Date>('date',
|
|
|
233
233
|
if (chaine) {
|
|
234
234
|
|
|
235
235
|
if (!isISO8601(val))
|
|
236
|
-
throw new
|
|
236
|
+
throw new InputError("This value must be a date.");
|
|
237
237
|
|
|
238
238
|
val = toDate(val);
|
|
239
239
|
|
|
240
240
|
} else if (!(val instanceof Date))
|
|
241
|
-
throw new
|
|
241
|
+
throw new InputError("This value must be a date.");
|
|
242
242
|
|
|
243
243
|
return opts.valider ? await opts.valider(val, donneesSaisie, donneesRetour) : val;
|
|
244
244
|
|
|
@@ -265,7 +265,7 @@ export const validateurFichier = async (
|
|
|
265
265
|
console.log('VALIDER FICHIER', type, val);
|
|
266
266
|
|
|
267
267
|
if (!(val instanceof NormalizedFile))
|
|
268
|
-
throw new
|
|
268
|
+
throw new InputError(`Must be a File (${typeof val} received)`);
|
|
269
269
|
|
|
270
270
|
// MIME
|
|
271
271
|
if (type !== undefined) {
|
|
@@ -284,7 +284,7 @@ export const validateurFichier = async (
|
|
|
284
284
|
// Vérification
|
|
285
285
|
const mimeFichier = val.type;
|
|
286
286
|
if (!mimetypes.includes(mimeFichier))
|
|
287
|
-
throw new
|
|
287
|
+
throw new InputError('Only the following formats are allowed: ' + mimetypes.join(', ') + '. The file you gave is ' + mimeFichier + '.');
|
|
288
288
|
|
|
289
289
|
}
|
|
290
290
|
|
|
@@ -292,7 +292,7 @@ export const validateurFichier = async (
|
|
|
292
292
|
if (taille) {
|
|
293
293
|
const tailleFichier = val.size / 1024 / 1024; // Mo
|
|
294
294
|
if (tailleFichier > taille)
|
|
295
|
-
throw new
|
|
295
|
+
throw new InputError(`Le fichier ne doit pas faire plus de ${taille} Mo (taille reçue: ${tailleFichier} Mo)`);
|
|
296
296
|
}
|
|
297
297
|
|
|
298
298
|
return opts.valider ? await opts.valider(val, donneesSaisie, donneesRetour) : val;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
----------------------------------*/
|
|
4
4
|
|
|
5
5
|
// Libs
|
|
6
|
-
import {
|
|
6
|
+
import { InputError } from '@common/errors';
|
|
7
7
|
import * as basicValidators from './basic';
|
|
8
8
|
|
|
9
9
|
// Components
|
|
@@ -39,7 +39,7 @@ export const champ = <TValeur>(
|
|
|
39
39
|
return undefined;
|
|
40
40
|
// Requis
|
|
41
41
|
else
|
|
42
|
-
throw new
|
|
42
|
+
throw new InputError("Please enter a value");
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
if (opts.valider !== undefined)
|
|
@@ -66,13 +66,13 @@ export abstract class Erreur extends Error {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
export class
|
|
69
|
+
export class InputError extends Erreur {
|
|
70
70
|
public http = 400;
|
|
71
71
|
public title = "Bad Request";
|
|
72
72
|
public static msgDefaut = "Bad Request.";
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
export class
|
|
75
|
+
export class InputErrorSchema extends Erreur {
|
|
76
76
|
|
|
77
77
|
public http = 400;
|
|
78
78
|
public title = "Bad Request";
|
|
@@ -89,7 +89,7 @@ export class ErreurSaisieSchema extends Erreur {
|
|
|
89
89
|
|
|
90
90
|
public constructor(message: TListeErreursSaisie, details?: TDetailsErreur) {
|
|
91
91
|
|
|
92
|
-
super(
|
|
92
|
+
super( InputErrorSchema.listeToString(message), details );
|
|
93
93
|
|
|
94
94
|
this.erreursSaisie = message;
|
|
95
95
|
|
|
@@ -103,29 +103,33 @@ export class ErreurSaisieSchema extends Erreur {
|
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
export class
|
|
106
|
+
export class AuthRequired extends Erreur {
|
|
107
107
|
public http = 401;
|
|
108
108
|
public title = "Authentication Required";
|
|
109
109
|
public static msgDefaut = "Please Login to Continue.";
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
export class
|
|
112
|
+
export class Forbidden extends Erreur {
|
|
113
113
|
public http = 403;
|
|
114
114
|
public title = "Access Denied";
|
|
115
115
|
public static msgDefaut = "You're not allowed to access to this resource.";
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
export class
|
|
118
|
+
export class NotFound extends Erreur {
|
|
119
119
|
public http = 404;
|
|
120
120
|
public title = "Not Found";
|
|
121
121
|
public static msgDefaut = "The resource you asked for was not found.";
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
export class
|
|
124
|
+
export class Anomaly extends Erreur {
|
|
125
125
|
|
|
126
126
|
public http = 500;
|
|
127
127
|
public title = "Technical Error";
|
|
128
128
|
public static msgDefaut = "A technical error has occurred. A notification has just been sent to the admin.";
|
|
129
|
+
|
|
130
|
+
public constructor(message, public data: object) {
|
|
131
|
+
super(message);
|
|
132
|
+
}
|
|
129
133
|
}
|
|
130
134
|
|
|
131
135
|
export class NotAvailable extends Erreur {
|
|
@@ -148,13 +152,13 @@ export const instancierViaCode = (
|
|
|
148
152
|
): Erreur => {
|
|
149
153
|
|
|
150
154
|
if (typeof message === 'object')
|
|
151
|
-
return new
|
|
155
|
+
return new InputErrorSchema(message, details);
|
|
152
156
|
|
|
153
157
|
switch (code) {
|
|
154
|
-
case 400: return new
|
|
155
|
-
case 401: return new
|
|
156
|
-
case 403: return new
|
|
157
|
-
case 404: return new
|
|
158
|
-
default: return new
|
|
158
|
+
case 400: return new InputError( message, details);
|
|
159
|
+
case 401: return new AuthRequired( message, details);
|
|
160
|
+
case 403: return new Forbidden( message, details);
|
|
161
|
+
case 404: return new NotFound( message, details);
|
|
162
|
+
default: return new Anomaly( message, details);
|
|
159
163
|
}
|
|
160
164
|
}
|
|
@@ -15,7 +15,7 @@ import hInterval from 'human-interval';
|
|
|
15
15
|
|
|
16
16
|
// Core
|
|
17
17
|
import Cron, { CronTask } from '@server/services/cron';
|
|
18
|
-
import {
|
|
18
|
+
import { Forbidden } from '@common/errors';
|
|
19
19
|
|
|
20
20
|
const debug = true;
|
|
21
21
|
|
|
@@ -82,7 +82,7 @@ class Tokens {
|
|
|
82
82
|
debug && console.log("Get token", token, options);
|
|
83
83
|
if (options === undefined) {
|
|
84
84
|
if (critical)
|
|
85
|
-
throw new
|
|
85
|
+
throw new Forbidden(`Invalid token.`);
|
|
86
86
|
else
|
|
87
87
|
return undefined;
|
|
88
88
|
}
|
package/src/server/data/aes.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import crypto from 'crypto';
|
|
7
7
|
|
|
8
8
|
// Core
|
|
9
|
-
import {
|
|
9
|
+
import { Forbidden } from '@common/errors';
|
|
10
10
|
|
|
11
11
|
const debug = true;
|
|
12
12
|
|
|
@@ -43,7 +43,7 @@ class AES {
|
|
|
43
43
|
|
|
44
44
|
} catch (error) {
|
|
45
45
|
|
|
46
|
-
throw new
|
|
46
|
+
throw new Forbidden("Invalid token.");
|
|
47
47
|
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -7,7 +7,7 @@ import md5 from 'md5';
|
|
|
7
7
|
import { OAuth2Client, LoginTicket } from 'google-auth-library';
|
|
8
8
|
|
|
9
9
|
// Core libs
|
|
10
|
-
import {
|
|
10
|
+
import { Forbidden } from '@common/errors';
|
|
11
11
|
|
|
12
12
|
// App Libs
|
|
13
13
|
import { IP } from '@models';
|
|
@@ -38,7 +38,7 @@ export type AuthConfig = {
|
|
|
38
38
|
key: string,
|
|
39
39
|
expiration: string,
|
|
40
40
|
},
|
|
41
|
-
google
|
|
41
|
+
google?: {
|
|
42
42
|
web: {
|
|
43
43
|
clientId: string,
|
|
44
44
|
secret: string,
|
|
@@ -75,11 +75,13 @@ export default abstract class UserAuthBase {
|
|
|
75
75
|
public abstract beforeSignup(user: User): Promise< void >;
|
|
76
76
|
public abstract afterSignup(user: User): Promise<{ redirect: string }>;
|
|
77
77
|
|
|
78
|
-
private googleClient =
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
78
|
+
private googleClient = app.config.auth.google
|
|
79
|
+
? new OAuth2Client(
|
|
80
|
+
app.config.auth.google.web.clientId, // Google Client ID
|
|
81
|
+
app.config.auth.google.web.secret, // Private key
|
|
82
|
+
"https://" + app.env.domain + "/auth/google/response" // Redirect url
|
|
83
|
+
)
|
|
84
|
+
: undefined;
|
|
83
85
|
|
|
84
86
|
public async load() {
|
|
85
87
|
|
|
@@ -101,6 +103,9 @@ export default abstract class UserAuthBase {
|
|
|
101
103
|
|
|
102
104
|
public async FromGoogle(request: ServerRequest): Promise<string> {
|
|
103
105
|
|
|
106
|
+
if (!this.googleClient)
|
|
107
|
+
throw new Forbidden(`Authentication method disabled.`);
|
|
108
|
+
|
|
104
109
|
// Register start time, so we can determine the signup time to display
|
|
105
110
|
request.response?.cookie('signupstart', Date.now());
|
|
106
111
|
|
|
@@ -126,8 +131,11 @@ export default abstract class UserAuthBase {
|
|
|
126
131
|
request: ServerRequest,
|
|
127
132
|
): Promise<AuthResponse> {
|
|
128
133
|
|
|
134
|
+
if (!this.googleClient)
|
|
135
|
+
throw new Forbidden(`Authentication method disabled.`);
|
|
136
|
+
|
|
129
137
|
if (codeOrToken === undefined)
|
|
130
|
-
throw new
|
|
138
|
+
throw new Forbidden("Bad code / token");
|
|
131
139
|
|
|
132
140
|
if (type === 'code') {
|
|
133
141
|
const r = await this.googleClient.getToken(codeOrToken);
|
|
@@ -146,16 +154,16 @@ export default abstract class UserAuthBase {
|
|
|
146
154
|
]
|
|
147
155
|
});
|
|
148
156
|
} catch (error) {
|
|
149
|
-
throw new
|
|
157
|
+
throw new Forbidden(`Google denied your login attempt: ` + error.message + `. If you don't think it's normal, please contact us.`);
|
|
150
158
|
}
|
|
151
159
|
|
|
152
160
|
const payload = ticket.getPayload();
|
|
153
161
|
if (payload === undefined)
|
|
154
|
-
throw new
|
|
162
|
+
throw new Forbidden("Invalid payload");
|
|
155
163
|
const { email, sub: google_id } = payload;
|
|
156
164
|
|
|
157
165
|
if (email === undefined)
|
|
158
|
-
throw new
|
|
166
|
+
throw new Forbidden("Unable to get your email address from the Google sign-in.");
|
|
159
167
|
|
|
160
168
|
return await this.Auth(email, request, true);
|
|
161
169
|
|
|
@@ -180,7 +188,7 @@ export default abstract class UserAuthBase {
|
|
|
180
188
|
|
|
181
189
|
} else if (!canPass) { // Send login email
|
|
182
190
|
|
|
183
|
-
throw new
|
|
191
|
+
throw new Forbidden("This option is not available");
|
|
184
192
|
|
|
185
193
|
// If the current IP was used to connect to another account that the current
|
|
186
194
|
ip = await request.detect.botsAndMultiaccount(user.name);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
----------------------------------*/
|
|
4
4
|
|
|
5
5
|
// Core
|
|
6
|
-
import {
|
|
6
|
+
import { NotFound } from '@common/errors';
|
|
7
7
|
import app from '@server/app';
|
|
8
8
|
import context from '@server/context';
|
|
9
9
|
|
|
@@ -99,7 +99,7 @@ export class CronManager {
|
|
|
99
99
|
const tache = CronManager.taches[nom];
|
|
100
100
|
|
|
101
101
|
if (tache === undefined)
|
|
102
|
-
throw new
|
|
102
|
+
throw new NotFound("Tâche NotFound: " + nom);
|
|
103
103
|
|
|
104
104
|
await tache.run(true);
|
|
105
105
|
|
|
@@ -9,7 +9,7 @@ const safeStringify = require('fast-safe-stringify'); // remplace les référenc
|
|
|
9
9
|
|
|
10
10
|
// Core: general
|
|
11
11
|
import app, { $ } from '@server/app';
|
|
12
|
-
import {
|
|
12
|
+
import { NotFound } from '@common/errors';
|
|
13
13
|
|
|
14
14
|
// Services
|
|
15
15
|
import './connection';
|
|
@@ -113,7 +113,7 @@ export function sql<TRowData extends TObjetDonnees = {}>(strings: TemplateString
|
|
|
113
113
|
fetchStats(columns, string, periodStr, intervalStr)*/
|
|
114
114
|
|
|
115
115
|
query.mergeValues = (options: TQueryOptions = {}) =>
|
|
116
|
-
sql.query(string, options).then(queriesResult => {
|
|
116
|
+
sql.query(string, options).then( queriesResult => {
|
|
117
117
|
|
|
118
118
|
const data: TObjetDonnees = {};
|
|
119
119
|
for (const queryResult of queriesResult)
|
|
@@ -211,7 +211,8 @@ sql.query = async <TRowData extends TObjetDonnees = {}>(
|
|
|
211
211
|
time: Date.now() - startTime,
|
|
212
212
|
});
|
|
213
213
|
}
|
|
214
|
-
|
|
214
|
+
|
|
215
|
+
return rows as unknown as TRowData[];
|
|
215
216
|
|
|
216
217
|
} catch (error) {
|
|
217
218
|
|
|
@@ -251,7 +252,7 @@ sql.firstOrFail = <TRowData extends TObjetDonnees = {}>(query: string, message?:
|
|
|
251
252
|
sql.query(query, opts).then((resultatRequetes: any) => {
|
|
252
253
|
|
|
253
254
|
if (resultatRequetes.length === 0)
|
|
254
|
-
throw new
|
|
255
|
+
throw new NotFound(message);
|
|
255
256
|
|
|
256
257
|
return resultatRequetes[0];
|
|
257
258
|
|
|
@@ -359,18 +360,15 @@ sql.insert = async <TData extends TObjetDonnees>(
|
|
|
359
360
|
}).join(', ');
|
|
360
361
|
|
|
361
362
|
if (opts.upsert !== undefined)
|
|
362
|
-
query += ' ON DUPLICATE KEY UPDATE ' + opts.upsert.map(col =>
|
|
363
|
+
query += ' ON DUPLICATE KEY UPDATE ' + opts.upsert.map( col =>
|
|
363
364
|
'`' + col + '` = ' + (opts.upsertMode === 'increment' ? '`' + col + '` + ' : '') + 'VALUES(' + col + ')'
|
|
364
365
|
)
|
|
365
366
|
|
|
366
367
|
const queryResult = await sql.query(query + ';', opts);
|
|
367
368
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
data.id = queryResult.insertId;
|
|
372
|
-
return data;
|
|
373
|
-
}
|
|
369
|
+
console.log("opts.returnQuery", opts.returnQuery, "queryResult", queryResult);
|
|
370
|
+
|
|
371
|
+
return [data, queryResult.insertId, queryResult];
|
|
374
372
|
}
|
|
375
373
|
|
|
376
374
|
/*----------------------------------
|
|
@@ -135,7 +135,7 @@ export default class Email {
|
|
|
135
135
|
const template = templates[email.template];
|
|
136
136
|
|
|
137
137
|
if (template === undefined)
|
|
138
|
-
throw new Error(`Impossible de charger la template email ${email.template} depuis le cache (
|
|
138
|
+
throw new Error(`Impossible de charger la template email ${email.template} depuis le cache (NotFound).`);
|
|
139
139
|
|
|
140
140
|
const txt = template(email.data || {})
|
|
141
141
|
|
|
@@ -197,7 +197,4 @@ declare global {
|
|
|
197
197
|
email: Email;
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Register transporters
|
|
203
|
-
require("./transports/*");
|
|
200
|
+
}
|
|
@@ -22,7 +22,7 @@ import TrackingService from './request/services/tracking';
|
|
|
22
22
|
|
|
23
23
|
// Core: libs
|
|
24
24
|
import app, { $ } from '@server/app';
|
|
25
|
-
import {
|
|
25
|
+
import { NotFound } from '@common/errors';
|
|
26
26
|
|
|
27
27
|
// Core: types
|
|
28
28
|
import type { TSsrUnresolvedRoute, TRegisterPageArgs } from '@client/router';
|
|
@@ -439,7 +439,7 @@ export class Router extends BaseRouter {
|
|
|
439
439
|
return response;
|
|
440
440
|
}
|
|
441
441
|
|
|
442
|
-
throw new
|
|
442
|
+
throw new NotFound(`The requested endpoint was not found.`);
|
|
443
443
|
}
|
|
444
444
|
|
|
445
445
|
}
|