proteum 1.0.0-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/.dockerignore +10 -0
- package/Rte.zip +0 -0
- package/cli/app/config.ts +54 -0
- package/cli/app/index.ts +195 -0
- package/cli/bin.js +11 -0
- package/cli/commands/build.ts +34 -0
- package/cli/commands/deploy/app.ts +29 -0
- package/cli/commands/deploy/web.ts +60 -0
- package/cli/commands/dev.ts +109 -0
- package/cli/commands/init.ts +85 -0
- package/cli/compiler/client/identite.ts +72 -0
- package/cli/compiler/client/index.ts +334 -0
- package/cli/compiler/common/babel/index.ts +170 -0
- package/cli/compiler/common/babel/plugins/index.ts +0 -0
- package/cli/compiler/common/babel/plugins/services.ts +579 -0
- package/cli/compiler/common/babel/routes/imports.ts +127 -0
- package/cli/compiler/common/babel/routes/routes.ts +1130 -0
- package/cli/compiler/common/files/autres.ts +39 -0
- package/cli/compiler/common/files/images.ts +35 -0
- package/cli/compiler/common/files/style.ts +78 -0
- package/cli/compiler/common/index.ts +154 -0
- package/cli/compiler/index.ts +532 -0
- package/cli/compiler/server/index.ts +211 -0
- package/cli/index.ts +189 -0
- package/cli/paths.ts +165 -0
- package/cli/print.ts +12 -0
- package/cli/tsconfig.json +38 -0
- package/cli/utils/index.ts +22 -0
- package/cli/utils/keyboard.ts +78 -0
- package/client/app/component.tsx +54 -0
- package/client/app/index.ts +142 -0
- package/client/app/service.ts +34 -0
- package/client/app.tsconfig.json +28 -0
- package/client/components/Button.tsx +298 -0
- package/client/components/Dialog/Manager.tsx +309 -0
- package/client/components/Dialog/card.tsx +208 -0
- package/client/components/Dialog/index.less +151 -0
- package/client/components/Dialog/status.less +176 -0
- package/client/components/Dialog/status.tsx +48 -0
- package/client/components/index.ts +2 -0
- package/client/components/types.d.ts +3 -0
- package/client/data/input.ts +32 -0
- package/client/global.d.ts +5 -0
- package/client/hooks.ts +22 -0
- package/client/index.ts +6 -0
- package/client/pages/_layout/index.less +6 -0
- package/client/pages/_layout/index.tsx +43 -0
- package/client/pages/bug.tsx.old +60 -0
- package/client/pages/useHeader.tsx +50 -0
- package/client/services/captcha/index.ts +67 -0
- package/client/services/router/components/Link.tsx +46 -0
- package/client/services/router/components/Page.tsx +55 -0
- package/client/services/router/components/router.tsx +218 -0
- package/client/services/router/index.tsx +521 -0
- package/client/services/router/request/api.ts +267 -0
- package/client/services/router/request/history.ts +5 -0
- package/client/services/router/request/index.ts +53 -0
- package/client/services/router/request/multipart.ts +147 -0
- package/client/services/router/response/index.tsx +128 -0
- package/client/services/router/response/page.ts +86 -0
- package/client/services/socket/index.ts +147 -0
- package/client/utils/dom.ts +77 -0
- package/common/app/index.ts +9 -0
- package/common/data/chaines/index.ts +54 -0
- package/common/data/dates.ts +179 -0
- package/common/data/markdown.ts +73 -0
- package/common/data/rte/nodes.ts +83 -0
- package/common/data/stats.ts +90 -0
- package/common/errors/index.tsx +326 -0
- package/common/router/index.ts +213 -0
- package/common/router/layouts.ts +93 -0
- package/common/router/register.ts +55 -0
- package/common/router/request/api.ts +77 -0
- package/common/router/request/index.ts +35 -0
- package/common/router/response/index.ts +45 -0
- package/common/router/response/page.ts +128 -0
- package/common/utils/rte.ts +183 -0
- package/common/utils.ts +7 -0
- package/doc/TODO.md +71 -0
- package/doc/front/router.md +27 -0
- package/doc/workspace/workspace.png +0 -0
- package/doc/workspace/workspace2.png +0 -0
- package/doc/workspace/workspace_26.01.22.png +0 -0
- package/package.json +171 -0
- package/server/app/commands.ts +141 -0
- package/server/app/container/config.ts +203 -0
- package/server/app/container/console/index.ts +550 -0
- package/server/app/container/index.ts +137 -0
- package/server/app/index.ts +273 -0
- package/server/app/service/container.ts +88 -0
- package/server/app/service/index.ts +235 -0
- package/server/app.tsconfig.json +28 -0
- package/server/context.ts +4 -0
- package/server/index.ts +4 -0
- package/server/services/auth/index.ts +250 -0
- package/server/services/auth/old.ts +277 -0
- package/server/services/auth/router/index.ts +95 -0
- package/server/services/auth/router/request.ts +54 -0
- package/server/services/auth/router/service.json +6 -0
- package/server/services/auth/service.json +6 -0
- package/server/services/cache/commands.ts +41 -0
- package/server/services/cache/index.ts +297 -0
- package/server/services/cache/service.json +6 -0
- package/server/services/cron/CronTask.ts +86 -0
- package/server/services/cron/index.ts +112 -0
- package/server/services/cron/service.json +6 -0
- package/server/services/disks/driver.ts +103 -0
- package/server/services/disks/drivers/local/index.ts +188 -0
- package/server/services/disks/drivers/local/service.json +6 -0
- package/server/services/disks/drivers/s3/index.ts +301 -0
- package/server/services/disks/drivers/s3/service.json +6 -0
- package/server/services/disks/index.ts +90 -0
- package/server/services/disks/service.json +6 -0
- package/server/services/email/index.ts +188 -0
- package/server/services/email/utils.ts +53 -0
- package/server/services/fetch/index.ts +201 -0
- package/server/services/fetch/service.json +7 -0
- package/server/services/models.7z +0 -0
- package/server/services/prisma/Facet.ts +142 -0
- package/server/services/prisma/index.ts +201 -0
- package/server/services/prisma/service.json +6 -0
- package/server/services/router/http/index.ts +217 -0
- package/server/services/router/http/multipart.ts +102 -0
- package/server/services/router/http/session.ts.old +40 -0
- package/server/services/router/index.ts +801 -0
- package/server/services/router/request/api.ts +87 -0
- package/server/services/router/request/index.ts +184 -0
- package/server/services/router/request/service.ts +21 -0
- package/server/services/router/request/validation/zod.ts +180 -0
- package/server/services/router/response/index.ts +338 -0
- package/server/services/router/response/mask/Filter.ts +323 -0
- package/server/services/router/response/mask/index.ts +60 -0
- package/server/services/router/response/mask/selecteurs.ts +92 -0
- package/server/services/router/response/page/document.tsx +160 -0
- package/server/services/router/response/page/index.tsx +196 -0
- package/server/services/router/service.json +6 -0
- package/server/services/router/service.ts +36 -0
- package/server/services/schema/index.ts +44 -0
- package/server/services/schema/request.ts +49 -0
- package/server/services/schema/router/index.ts +28 -0
- package/server/services/schema/router/service.json +6 -0
- package/server/services/schema/service.json +6 -0
- package/server/services/security/encrypt/aes/index.ts +85 -0
- package/server/services/security/encrypt/aes/service.json +6 -0
- package/server/services/socket/index.ts +162 -0
- package/server/services/socket/scope.ts +226 -0
- package/server/services/socket/service.json +6 -0
- package/server/services_old/SocketClient.ts +92 -0
- package/server/services_old/Token.old.ts +97 -0
- package/server/utils/slug.ts +79 -0
- package/tsconfig.common.json +45 -0
- package/tsconfig.json +3 -0
- package/types/aliases.d.ts +54 -0
- package/types/global/modules.d.ts +49 -0
- package/types/global/utils.d.ts +103 -0
- package/types/icons.d.ts +1 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Npm
|
|
6
|
+
import { PrismaClient } from '@/var/prisma';
|
|
7
|
+
import mysql from 'mysql2/promise';
|
|
8
|
+
import type PrismaClientType from '@prisma/client';
|
|
9
|
+
const safeStringify = require('fast-safe-stringify'); // remplace les références circulairs par un [Circular]
|
|
10
|
+
|
|
11
|
+
// Core
|
|
12
|
+
import type { Application } from '@server/app';
|
|
13
|
+
import Service from '@server/app/service';
|
|
14
|
+
|
|
15
|
+
// Specific
|
|
16
|
+
import Facet, { TDelegate, TSubset, Transform } from './Facet';
|
|
17
|
+
import { NotFound } from '@common/errors';
|
|
18
|
+
|
|
19
|
+
/*----------------------------------
|
|
20
|
+
- TYPES
|
|
21
|
+
----------------------------------*/
|
|
22
|
+
|
|
23
|
+
export type SqlQuery = ReturnType<ModelsManager["SQL"]>
|
|
24
|
+
|
|
25
|
+
/*----------------------------------
|
|
26
|
+
- SERVICE CONFIG
|
|
27
|
+
----------------------------------*/
|
|
28
|
+
|
|
29
|
+
export type Config = {
|
|
30
|
+
debug?: boolean
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type Hooks = {
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type Services = {
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/*----------------------------------
|
|
42
|
+
- CLASSE
|
|
43
|
+
----------------------------------*/
|
|
44
|
+
|
|
45
|
+
export default class ModelsManager extends Service<Config, Hooks, Application, Application> {
|
|
46
|
+
|
|
47
|
+
public client = new PrismaClient() as PrismaClientType.PrismaClient;
|
|
48
|
+
|
|
49
|
+
public async ready() {
|
|
50
|
+
|
|
51
|
+
await this.client.$executeRaw`SET time_zone = '+00:00'`;
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public async shutdown() {
|
|
56
|
+
await this.client.$disconnect()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public Facet<
|
|
60
|
+
D extends TDelegate<R>,
|
|
61
|
+
S extends TSubset,
|
|
62
|
+
R,
|
|
63
|
+
RT
|
|
64
|
+
>(...args: [D, S, Transform<S, R, RT>]) {
|
|
65
|
+
|
|
66
|
+
return new Facet(
|
|
67
|
+
this.client,
|
|
68
|
+
...args
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/*----------------------------------
|
|
73
|
+
- OPERATIONS: PARSING
|
|
74
|
+
----------------------------------*/
|
|
75
|
+
public SQL<TRowData extends {}|number|string>( strings: TemplateStringsArray, ...data: any[] ) {
|
|
76
|
+
|
|
77
|
+
const string = this.string(strings, ...data);
|
|
78
|
+
|
|
79
|
+
const query = () => {
|
|
80
|
+
return this.client.$queryRawUnsafe(string) as Promise<TRowData[]>;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
query.all = query;
|
|
84
|
+
query.value = <TValue extends any = number>() => query().then((resultatRequetes: any) => {
|
|
85
|
+
|
|
86
|
+
const resultat = resultatRequetes[0];
|
|
87
|
+
|
|
88
|
+
if (!resultat)
|
|
89
|
+
return null;
|
|
90
|
+
|
|
91
|
+
return Object.values(resultat)[0] as TValue;
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
query.first = () => query().then((resultatRequetes: any) => {
|
|
95
|
+
return resultatRequetes[0] || null;
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
query.firstOrFail = (message: string) => query().then((resultatRequetes: any) => {
|
|
99
|
+
|
|
100
|
+
if (resultatRequetes.length === 0)
|
|
101
|
+
throw new NotFound(message);
|
|
102
|
+
|
|
103
|
+
return resultatRequetes[0];
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
query.string = string;
|
|
107
|
+
|
|
108
|
+
return query;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
public esc( data: any, forStorage: boolean = false ) {
|
|
112
|
+
|
|
113
|
+
// JSON object
|
|
114
|
+
// TODO: do it via datatypes.ts
|
|
115
|
+
if (typeof data === 'object' && data !== null) {
|
|
116
|
+
|
|
117
|
+
// Object: stringify in JSON
|
|
118
|
+
if (data.constructor.name === "Object")
|
|
119
|
+
data = safeStringify(data);
|
|
120
|
+
// Array: if for storage, reparate items with a comma
|
|
121
|
+
else if (forStorage && Array.isArray( data )) {
|
|
122
|
+
data = data.join(',')
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return mysql.escape(data);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public string = (strings: TemplateStringsArray, ...data: any[]) => {
|
|
130
|
+
const iMax = data.length - 1;
|
|
131
|
+
|
|
132
|
+
if (typeof data === 'function')
|
|
133
|
+
throw new Error(`A function has been passed into the sql string template: ` + data);
|
|
134
|
+
|
|
135
|
+
return strings.map((stringBefore, i) => {
|
|
136
|
+
|
|
137
|
+
if (i <= iMax) {
|
|
138
|
+
|
|
139
|
+
let value = data[i];
|
|
140
|
+
stringBefore = stringBefore.trim();
|
|
141
|
+
const prefix = stringBefore[stringBefore.length - 1];
|
|
142
|
+
|
|
143
|
+
// Null
|
|
144
|
+
if (value === undefined || value === null) {
|
|
145
|
+
|
|
146
|
+
value = 'NULL';
|
|
147
|
+
|
|
148
|
+
// Replace ""= NULL" by "IS NULL"
|
|
149
|
+
if (prefix === '=')
|
|
150
|
+
stringBefore = stringBefore.substring(0, stringBefore.length - 1) + 'IS ';
|
|
151
|
+
|
|
152
|
+
// Prefix = special parse
|
|
153
|
+
} else if (prefix === ':' || prefix === '&') {
|
|
154
|
+
|
|
155
|
+
// Remove the prefix
|
|
156
|
+
stringBefore = stringBefore.substring(0, stringBefore.length - 1);
|
|
157
|
+
|
|
158
|
+
// Object: `WHERE :${filters}` => `SET requestId = "" AND col = 3`
|
|
159
|
+
if (typeof value === 'object') {
|
|
160
|
+
|
|
161
|
+
const keyword = prefix === '&' ? ' AND ' : ', '
|
|
162
|
+
|
|
163
|
+
value = Object.keys(value).length === 0 ? '1' : this.equalities(value).join( keyword );
|
|
164
|
+
|
|
165
|
+
// String: `SET :${column} = ${data}` => `SET balance = 10`
|
|
166
|
+
} else {
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// SQL query
|
|
172
|
+
} else if (typeof value === 'function' && value.string !== undefined)
|
|
173
|
+
value = ' ' + value.string;
|
|
174
|
+
// Escape value
|
|
175
|
+
else {
|
|
176
|
+
|
|
177
|
+
const lastKeyword = stringBefore.trim().split(' ').pop();
|
|
178
|
+
|
|
179
|
+
// Escape table name
|
|
180
|
+
if (lastKeyword === 'FROM')
|
|
181
|
+
value = '`' + value + '`';
|
|
182
|
+
else
|
|
183
|
+
value = mysql.escape(value);
|
|
184
|
+
|
|
185
|
+
value = ' ' + value;
|
|
186
|
+
}
|
|
187
|
+
stringBefore += value;
|
|
188
|
+
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return stringBefore;
|
|
192
|
+
|
|
193
|
+
}).join(' ').trim();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
public equalities = (data: TObjetDonnees, forStorage: boolean = false) => {
|
|
197
|
+
return Object.keys(data).map(k => '' + k + ' = ' + this.esc( data[k], forStorage ))
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Npm: Serveurs
|
|
6
|
+
import bytes from 'bytes';
|
|
7
|
+
import express from 'express';
|
|
8
|
+
import http from 'http';
|
|
9
|
+
import https from 'https';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import cors, { CorsOptions } from 'cors';
|
|
12
|
+
|
|
13
|
+
// Middlewares (npm)
|
|
14
|
+
import morgan from 'morgan';
|
|
15
|
+
import hpp from 'hpp'; // Protection contre la pollution des reuqtees http
|
|
16
|
+
import helmet from 'helmet'; // Diverses protections
|
|
17
|
+
import compression from 'compression';
|
|
18
|
+
import fileUpload from 'express-fileupload';
|
|
19
|
+
import cookieParser from 'cookie-parser';
|
|
20
|
+
import * as csp from 'express-csp-header';
|
|
21
|
+
|
|
22
|
+
// Core
|
|
23
|
+
import Container from '@server/app/container';
|
|
24
|
+
import type Router from '..';
|
|
25
|
+
|
|
26
|
+
// Middlewaees (core)
|
|
27
|
+
import { MiddlewareFormData } from './multipart';
|
|
28
|
+
|
|
29
|
+
/*----------------------------------
|
|
30
|
+
- CONFIG
|
|
31
|
+
----------------------------------*/
|
|
32
|
+
|
|
33
|
+
export type Config = {
|
|
34
|
+
|
|
35
|
+
debug?: boolean,
|
|
36
|
+
|
|
37
|
+
// Access
|
|
38
|
+
domain: string,
|
|
39
|
+
port: number,
|
|
40
|
+
ssl: boolean,
|
|
41
|
+
|
|
42
|
+
// Limitations / Load restriction
|
|
43
|
+
upload: {
|
|
44
|
+
maxSize: string // Expression package bytes
|
|
45
|
+
},
|
|
46
|
+
csp: {
|
|
47
|
+
default?: string[],
|
|
48
|
+
styles?: string[],
|
|
49
|
+
images?: string[],
|
|
50
|
+
scripts: string[],
|
|
51
|
+
},
|
|
52
|
+
cors?: CorsOptions,
|
|
53
|
+
helmet?: Parameters<typeof helmet>[0]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export type Hooks = {
|
|
57
|
+
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/*----------------------------------
|
|
61
|
+
- FUNCTION
|
|
62
|
+
----------------------------------*/
|
|
63
|
+
export default class HttpServer {
|
|
64
|
+
|
|
65
|
+
public http: http.Server | https.Server;
|
|
66
|
+
public express: express.Express;
|
|
67
|
+
|
|
68
|
+
public publicUrl: string;
|
|
69
|
+
|
|
70
|
+
public constructor(
|
|
71
|
+
public config: Config,
|
|
72
|
+
public router: Router,
|
|
73
|
+
public app = router.app
|
|
74
|
+
) {
|
|
75
|
+
|
|
76
|
+
// Init
|
|
77
|
+
this.publicUrl = this.app.env.name === 'local'
|
|
78
|
+
? 'http://localhost:' + this.config.port
|
|
79
|
+
: ((this.config.ssl ? 'https' : 'http') + '://' + this.config.domain);
|
|
80
|
+
|
|
81
|
+
// Configure HTTP server
|
|
82
|
+
this.express = express();
|
|
83
|
+
this.http = http.createServer(this.express);
|
|
84
|
+
|
|
85
|
+
// Start HTTP Server
|
|
86
|
+
this.app.on('cleanup', () => this.cleanup());
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/*----------------------------------
|
|
90
|
+
- HOOKS
|
|
91
|
+
----------------------------------*/
|
|
92
|
+
|
|
93
|
+
public async start() {
|
|
94
|
+
|
|
95
|
+
const routes = this.express
|
|
96
|
+
|
|
97
|
+
/*----------------------------------
|
|
98
|
+
- SECURITÉ DE BASE
|
|
99
|
+
----------------------------------*/
|
|
100
|
+
|
|
101
|
+
// Config
|
|
102
|
+
routes.set('trust proxy', 1); // Indique qu'on est sous le proxy apache
|
|
103
|
+
// Diverses protections (dont le disable x-powered-by)
|
|
104
|
+
routes.use( helmet(this.config.helmet) );
|
|
105
|
+
|
|
106
|
+
/*----------------------------------
|
|
107
|
+
- FICHIERS STATIQUES
|
|
108
|
+
----------------------------------*/
|
|
109
|
+
|
|
110
|
+
// Fichiers statiques: Eviter un maximum de middlewares inutiles
|
|
111
|
+
// Normalement, seulement utile pour le mode production,
|
|
112
|
+
// Quand mode debug, les ressources client semblent servies par le dev middlewae
|
|
113
|
+
// Sauf que les ressources serveur ne semblent pas trouvées par le dev-middleware
|
|
114
|
+
routes.use(compression());
|
|
115
|
+
routes.use('/public', cors());
|
|
116
|
+
routes.use(
|
|
117
|
+
'/public',
|
|
118
|
+
express.static( Container.path.root + '/bin/public', {
|
|
119
|
+
dotfiles: 'deny',
|
|
120
|
+
setHeaders: function setCustomCacheControl(res, path) {
|
|
121
|
+
|
|
122
|
+
const dontCache = [
|
|
123
|
+
'/public/icons',
|
|
124
|
+
'/public/client'
|
|
125
|
+
]
|
|
126
|
+
|
|
127
|
+
res.setHeader('Cache-Control', 'public, max-age=0');
|
|
128
|
+
|
|
129
|
+
// Set long term cache, except for non-hashed filenames
|
|
130
|
+
/*if (dontCache.some( p => path.startsWith( p ))) {
|
|
131
|
+
res.setHeader('Cache-Control', 'public, max-age=0');
|
|
132
|
+
} else {
|
|
133
|
+
res.setHeader('Cache-Control', 'public, max-age=604800000'); // 7 Days
|
|
134
|
+
}*/
|
|
135
|
+
|
|
136
|
+
}
|
|
137
|
+
}),
|
|
138
|
+
(req, res) => {
|
|
139
|
+
res.status(404).send();
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
routes.use('/robots.txt', express.static( path.resolve(__dirname, 'public/robots.txt')) );
|
|
144
|
+
|
|
145
|
+
routes.get("/ping", (req, res) => res.send("pong"));
|
|
146
|
+
|
|
147
|
+
/*----------------------------------
|
|
148
|
+
- SESSION & SECURITE
|
|
149
|
+
----------------------------------*/
|
|
150
|
+
// https://expressjs.com/fr/advanced/best-practice-security.html
|
|
151
|
+
// Protection contre la pollution des reuqtees http
|
|
152
|
+
routes.use(hpp());
|
|
153
|
+
|
|
154
|
+
// Init de req.cookies
|
|
155
|
+
routes.use(cookieParser())
|
|
156
|
+
|
|
157
|
+
/*----------------------------------
|
|
158
|
+
- DÉCODEURS
|
|
159
|
+
----------------------------------*/
|
|
160
|
+
routes.use(
|
|
161
|
+
|
|
162
|
+
// Décodage des données post
|
|
163
|
+
express.json({
|
|
164
|
+
// TODO: prendre en considération les upload de fichiers
|
|
165
|
+
limit: bytes(this.config.upload.maxSize),
|
|
166
|
+
verify: (req, res, buf, encoding) => {
|
|
167
|
+
// Store the raw request body so we can access it later
|
|
168
|
+
req.rawBody = buf;
|
|
169
|
+
}
|
|
170
|
+
}),
|
|
171
|
+
|
|
172
|
+
// Permet de receptionner les données multipart (req.body + req.files)
|
|
173
|
+
// A mettre avant les services, car l'assignement de req.socket fait planter les uploads
|
|
174
|
+
fileUpload({
|
|
175
|
+
debug: false,
|
|
176
|
+
limits: {
|
|
177
|
+
fileSize: bytes(this.config.upload.maxSize),
|
|
178
|
+
abortOnLimit: true
|
|
179
|
+
},
|
|
180
|
+
}),
|
|
181
|
+
|
|
182
|
+
// Décodage des requetes multipart
|
|
183
|
+
// Peut-être requis par le résolver api
|
|
184
|
+
MiddlewareFormData
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
/*----------------------------------
|
|
188
|
+
- PAGES / API
|
|
189
|
+
----------------------------------*/
|
|
190
|
+
|
|
191
|
+
if (this.config.cors !== undefined)
|
|
192
|
+
routes.use( cors( this.config.cors ));
|
|
193
|
+
|
|
194
|
+
routes.use( csp.expressCspHeader({
|
|
195
|
+
directives: {
|
|
196
|
+
'script-src': [csp.INLINE, csp.SELF,
|
|
197
|
+
...this.config.csp.scripts
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
}));
|
|
201
|
+
|
|
202
|
+
routes.use( this.router.middleware.bind( this.router ) );
|
|
203
|
+
|
|
204
|
+
/*----------------------------------
|
|
205
|
+
- BOOT SERVICES
|
|
206
|
+
----------------------------------*/
|
|
207
|
+
console.info("Lancement du serveur web");
|
|
208
|
+
this.http.listen(this.config.port, () => {
|
|
209
|
+
console.info(`Web server ready on ${this.publicUrl}`);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
public async cleanup() {
|
|
215
|
+
this.http.close();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Npm
|
|
6
|
+
import mime from 'mime-types';
|
|
7
|
+
|
|
8
|
+
// Core
|
|
9
|
+
import { InputError } from '@common/errors';
|
|
10
|
+
|
|
11
|
+
/*----------------------------------
|
|
12
|
+
- TYPES
|
|
13
|
+
----------------------------------*/
|
|
14
|
+
|
|
15
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
16
|
+
import type { FileArray, UploadedFile } from 'express-fileupload';
|
|
17
|
+
|
|
18
|
+
/*----------------------------------
|
|
19
|
+
- CONFIG
|
|
20
|
+
----------------------------------*/
|
|
21
|
+
const reMultipart = /^multipart\/(?:form-data|related)(?:;|$)/i;
|
|
22
|
+
|
|
23
|
+
/*----------------------------------
|
|
24
|
+
- MIDDLEWARE
|
|
25
|
+
----------------------------------*/
|
|
26
|
+
export const MiddlewareFormData = (req: Request, res: Response, next: NextFunction) => {
|
|
27
|
+
|
|
28
|
+
// Verif si multipart
|
|
29
|
+
if (!isMutipart( req ))
|
|
30
|
+
return next();
|
|
31
|
+
|
|
32
|
+
// Données body + fichiers
|
|
33
|
+
// NOTE: Les données devant obligatoirement passer par le validateur de schema,
|
|
34
|
+
// On peut mélanger le body et les files sans risque de sécurité
|
|
35
|
+
req.body = traiterMultipart(req.body, req['files']);
|
|
36
|
+
//req.files = traiterMultipart(req.files);
|
|
37
|
+
|
|
38
|
+
next();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/*----------------------------------
|
|
42
|
+
- FUNCTIONS
|
|
43
|
+
----------------------------------*/
|
|
44
|
+
export const isMutipart = (req: Request) => req.headers['content-type'] && reMultipart.exec( req.headers['content-type'] );
|
|
45
|
+
|
|
46
|
+
export const traiterMultipart = (...canaux: any[]) => {
|
|
47
|
+
|
|
48
|
+
let sortie: {[nom: string]: any} = {};
|
|
49
|
+
|
|
50
|
+
for (const donnees of canaux) {
|
|
51
|
+
|
|
52
|
+
if (!donnees)
|
|
53
|
+
continue;
|
|
54
|
+
|
|
55
|
+
for (const fieldPath in donnees) {
|
|
56
|
+
let donnee = donnees[fieldPath];
|
|
57
|
+
|
|
58
|
+
let brancheA = sortie;
|
|
59
|
+
const results = [...fieldPath.matchAll(/[^\[\]]+/g)];
|
|
60
|
+
for (let iCle = 0; iCle < results.length; iCle++) {
|
|
61
|
+
|
|
62
|
+
const [cle] = results[ iCle ];
|
|
63
|
+
|
|
64
|
+
// Need to go deeper to find data
|
|
65
|
+
if (iCle !== results.length - 1) {
|
|
66
|
+
|
|
67
|
+
if (brancheA[ cle ] === undefined) {
|
|
68
|
+
const tableau = !isNaN( results[ iCle + 1 ][0] as any )
|
|
69
|
+
brancheA[ cle ] = tableau ? [] : {};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
brancheA = brancheA[ cle ];
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Data reached
|
|
77
|
+
if (
|
|
78
|
+
typeof donnee === 'object'
|
|
79
|
+
&&
|
|
80
|
+
donnee.data !== undefined
|
|
81
|
+
&&
|
|
82
|
+
donnee.data instanceof Buffer
|
|
83
|
+
){
|
|
84
|
+
const md5 = donnee.md5;
|
|
85
|
+
const data = donnee.data;
|
|
86
|
+
donnee = new File(donnee.data, donnee.name, {
|
|
87
|
+
type: donnee.mimetype,
|
|
88
|
+
lastModified: Date.now(),
|
|
89
|
+
//size: donnee.size,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
donnee.md5 = md5;
|
|
93
|
+
donnee.data = data;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
brancheA[ cle ] = donnee;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return sortie;
|
|
102
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Npm
|
|
2
|
+
import session from 'express-session';
|
|
3
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
4
|
+
import redisConnector from 'connect-redis';
|
|
5
|
+
const RedisStore = redisConnector(session);
|
|
6
|
+
|
|
7
|
+
// Services
|
|
8
|
+
import type { THttpConfig } from '@server/services/http';
|
|
9
|
+
import Redis from '@server/services/redis';
|
|
10
|
+
|
|
11
|
+
// Middleware
|
|
12
|
+
export const createSessionMiddleware = (httpConfig: THttpConfig) => {
|
|
13
|
+
return session({
|
|
14
|
+
|
|
15
|
+
genid: (req) => {
|
|
16
|
+
return /*req.id;*/uuidv4(); // ID session via UUID
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
name: httpConfig.session.name,
|
|
20
|
+
store: new RedisStore({
|
|
21
|
+
client: Redis.instance,
|
|
22
|
+
ttl: httpConfig.session.duration // secondes
|
|
23
|
+
}),
|
|
24
|
+
secret: httpConfig.session.secret,
|
|
25
|
+
|
|
26
|
+
// Ces deux valeurs sont recommandes avec session filestore
|
|
27
|
+
// https://github.com/valery-barysok/session-file-store/blob/master/examples/express-example/app.js
|
|
28
|
+
resave: true, // Quand false, /admin/console réinitialise la session
|
|
29
|
+
saveUninitialized: true,
|
|
30
|
+
|
|
31
|
+
cookie: {
|
|
32
|
+
maxAge: httpConfig.session.duration * 1000, // millisecondes
|
|
33
|
+
//sameSite: true,
|
|
34
|
+
httpOnly: true,
|
|
35
|
+
// Les variables d'environnement sont des chaines
|
|
36
|
+
secure: httpConfig.ssl,
|
|
37
|
+
path: '/',
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
}
|