outlet-orm 4.2.0 → 4.2.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.
Files changed (3) hide show
  1. package/README.md +39 -26
  2. package/bin/init.js +166 -8
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -32,56 +32,69 @@ Si aucun driver n'est installé, un message d'erreur explicite vous indiquera le
32
32
 
33
33
  Organisez votre projet utilisant Outlet ORM comme suit :
34
34
 
35
+ > 🔐 **Sécurité** : Voir le [Guide de Sécurité](./docs/SECURITY.md) pour les bonnes pratiques.
36
+
35
37
  ```
36
38
  mon-projet/
37
- ├── .env # Configuration de la base de données
39
+ ├── .env # ⚠️ JAMAIS commité (dans .gitignore)
40
+ ├── .env.example # Template sans secrets
41
+ ├── .gitignore # Exclure .env, node_modules, logs
38
42
  ├── package.json
43
+ ├── config/ # 🔒 Configuration centralisée
44
+ │ ├── app.js # Config générale
45
+ │ ├── database.js # Config DB (lit .env)
46
+ │ └── security.js # Rate limit, helmet, CORS...
39
47
  ├── database/
40
48
  │ ├── config.js # Config migrations (généré par outlet-init)
41
49
  │ └── migrations/ # Vos fichiers de migration
42
- │ ├── 20240101_create_users_table.js
43
- │ └── 20240102_create_posts_table.js
44
50
  ├── models/ # Vos classes Model
45
51
  │ ├── User.js
46
52
  │ ├── Post.js
47
53
  │ └── Comment.js
48
54
  ├── controllers/ # Vos contrôleurs (logique métier)
49
55
  │ ├── UserController.js
50
- ├── PostController.js
51
- │ └── CommentController.js
56
+ └── PostController.js
52
57
  ├── routes/ # Vos fichiers de routes
53
58
  │ ├── index.js
54
- ├── userRoutes.js
55
- │ └── postRoutes.js
56
- ├── middlewares/ # Vos middlewares
57
- │ ├── auth.js
58
- └── validation.js
59
+ └── userRoutes.js
60
+ ├── middlewares/ # 🔒 Middlewares de sécurité
61
+ ├── auth.js # Authentification JWT
62
+ │ ├── authorization.js # Contrôle des permissions (RBAC)
63
+ ├── rateLimiter.js # Protection anti-DDoS
64
+ │ ├── validator.js # Validation des entrées
65
+ │ └── errorHandler.js # Gestion centralisée des erreurs
59
66
  ├── services/ # Vos services (logique réutilisable)
60
67
  │ ├── AuthService.js
61
68
  │ └── EmailService.js
62
- ├── assets/ # Ressources statiques
63
- │ ├── images/ # Images (png, jpg, svg...)
64
- ├── videos/ # Fichiers vidéo
65
- ├── icons/ # Icônes
66
- ├── fonts/ # Polices personnalisées
67
- ├── css/ # Feuilles de style
68
- └── js/ # Scripts front-end
69
+ ├── utils/ # 🔒 Utilitaires sécurité
70
+ │ ├── hash.js # Hachage mots de passe (bcrypt)
71
+ └── token.js # Génération tokens sécurisés
72
+ ├── validators/ # 🔒 Schémas de validation
73
+ └── userValidator.js
74
+ ├── public/ # Seul dossier accessible publiquement
75
+ ├── images/
76
+ │ ├── css/
77
+ │ └── js/
78
+ ├── uploads/ # ⚠️ Fichiers uploadés (validés)
79
+ ├── logs/ # 📋 Journaux (non versionnés)
69
80
  ├── src/ # Votre code applicatif
70
81
  │ └── index.js
71
82
  └── tests/ # Vos tests
72
83
  └── models.test.js
73
84
  ```
74
85
 
75
- | Dossier | Rôle | Créé par |
86
+ | Dossier | Rôle | Sécurité |
76
87
  |---------|------|----------|
77
- | `database/config.js` | Configuration des migrations | `outlet-init` |
78
- | `database/migrations/` | Fichiers de migration | `outlet-migrate make` |
79
- | `models/` | Vos classes Model | Vous (recommandé) |
80
- | `controllers/` | Vos contrôleurs (logique métier) | Vous (recommandé) |
81
- | `routes/` | Définition des routes API/Web | Vous (recommandé) |
82
- | `middlewares/` | Middlewares d'authentification, validation, etc. | Vous (recommandé) |
83
- | `services/` | Services réutilisables (email, auth, etc.) | Vous (recommandé) |
84
- | `assets/` | Ressources statiques (images, vidéos, icônes, fonts, css, js) | Vous (recommandé) |
88
+ | `config/` | Configuration centralisée | 🔒 Lit les secrets depuis .env |
89
+ | `database/` | Migrations et config DB | `outlet-init` |
90
+ | `models/` | Classes Model avec `hidden` et `fillable` | 🔒 Mass assignment protection |
91
+ | `controllers/` | Logique métier | Valider les entrées |
92
+ | `routes/` | Définition des routes API/Web | 🔒 Appliquer middlewares auth |
93
+ | `middlewares/` | Auth, validation, rate limiting | 🔒 **Critique pour la sécurité** |
94
+ | `services/` | Services réutilisables | Isoler la logique sensible |
95
+ | `utils/` | Hash, tokens, encryption | 🔒 Ne jamais exposer |
96
+ | `public/` | Seul dossier accessible | ✅ Fichiers statiques sûrs |
97
+ | `logs/` | Journaux d'accès/erreurs | 📋 Dans .gitignore |
85
98
 
86
99
  ## ✨ Fonctionnalités clés
87
100
 
package/bin/init.js CHANGED
@@ -95,6 +95,7 @@ module.exports = db;
95
95
 
96
96
  // Create project structure directories
97
97
  const directories = [
98
+ 'config',
98
99
  'database',
99
100
  'database/migrations',
100
101
  'models',
@@ -102,13 +103,14 @@ module.exports = db;
102
103
  'routes',
103
104
  'middlewares',
104
105
  'services',
105
- 'assets',
106
- 'assets/images',
107
- 'assets/videos',
108
- 'assets/icons',
109
- 'assets/fonts',
110
- 'assets/css',
111
- 'assets/js',
106
+ 'utils',
107
+ 'validators',
108
+ 'public',
109
+ 'public/images',
110
+ 'public/css',
111
+ 'public/js',
112
+ 'uploads',
113
+ 'logs',
112
114
  'src',
113
115
  'tests'
114
116
  ];
@@ -124,6 +126,157 @@ module.exports = db;
124
126
  }
125
127
  }
126
128
 
129
+ // Generate .gitignore
130
+ const gitignoreContent = `# Secrets
131
+ .env
132
+ .env.local
133
+ .env.production
134
+
135
+ # Logs
136
+ logs/
137
+ *.log
138
+
139
+ # Uploads
140
+ uploads/
141
+
142
+ # Dependencies
143
+ node_modules/
144
+
145
+ # Build
146
+ dist/
147
+ build/
148
+
149
+ # IDE
150
+ .vscode/
151
+ .idea/
152
+ `;
153
+
154
+ const gitignorePath = path.join(process.cwd(), '.gitignore');
155
+ if (!fs.existsSync(gitignorePath)) {
156
+ fs.writeFileSync(gitignorePath, gitignoreContent);
157
+ console.log(`\n✅ .gitignore créé`);
158
+ }
159
+
160
+ // Generate .env.example
161
+ const envExampleContent = `# Base de données
162
+ DB_DRIVER=mysql
163
+ DB_HOST=localhost
164
+ DB_PORT=3306
165
+ DB_DATABASE=myapp
166
+ DB_USER=your_user
167
+ DB_PASSWORD=your_password
168
+
169
+ # Sécurité
170
+ JWT_SECRET=your_jwt_secret_here
171
+ JWT_EXPIRES_IN=15m
172
+
173
+ # Application
174
+ NODE_ENV=development
175
+ PORT=3000
176
+
177
+ # CORS
178
+ CORS_ORIGIN=http://localhost:3000
179
+ `;
180
+
181
+ const envExamplePath = path.join(process.cwd(), '.env.example');
182
+ if (!fs.existsSync(envExamplePath)) {
183
+ fs.writeFileSync(envExamplePath, envExampleContent);
184
+ console.log(`✅ .env.example créé`);
185
+ }
186
+
187
+ // Generate config/security.js
188
+ const securityConfigContent = `/**
189
+ * Configuration de sécurité
190
+ * npm install helmet express-rate-limit xss-clean hpp
191
+ */
192
+
193
+ module.exports = {
194
+ // Rate limiting (100 requêtes/15min par IP)
195
+ rateLimit: {
196
+ windowMs: 15 * 60 * 1000,
197
+ max: 100,
198
+ message: { error: 'Trop de requêtes, réessayez plus tard' }
199
+ },
200
+
201
+ // Rate limiting strict pour auth (5 tentatives/15min)
202
+ authRateLimit: {
203
+ windowMs: 15 * 60 * 1000,
204
+ max: 5,
205
+ message: { error: 'Trop de tentatives de connexion' }
206
+ },
207
+
208
+ // CORS
209
+ cors: {
210
+ origin: process.env.CORS_ORIGIN || 'http://localhost:3000',
211
+ credentials: true,
212
+ methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
213
+ allowedHeaders: ['Content-Type', 'Authorization']
214
+ },
215
+
216
+ // JWT
217
+ jwt: {
218
+ secret: process.env.JWT_SECRET,
219
+ expiresIn: process.env.JWT_EXPIRES_IN || '15m'
220
+ }
221
+ };
222
+ `;
223
+
224
+ const securityConfigPath = path.join(process.cwd(), 'config', 'security.js');
225
+ if (!fs.existsSync(securityConfigPath)) {
226
+ fs.writeFileSync(securityConfigPath, securityConfigContent);
227
+ console.log(`✅ config/security.js créé`);
228
+ }
229
+
230
+ // Generate middlewares/errorHandler.js
231
+ const errorHandlerContent = `/**
232
+ * Gestionnaire d'erreurs centralisé
233
+ */
234
+ const errorHandler = (err, req, res, next) => {
235
+ console.error(\`[\${new Date().toISOString()}] Error:\`, err);
236
+
237
+ const isDev = process.env.NODE_ENV === 'development';
238
+
239
+ res.status(err.status || 500).json({
240
+ error: isDev ? err.message : 'Erreur serveur',
241
+ stack: isDev ? err.stack : undefined
242
+ });
243
+ };
244
+
245
+ module.exports = errorHandler;
246
+ `;
247
+
248
+ const errorHandlerPath = path.join(process.cwd(), 'middlewares', 'errorHandler.js');
249
+ if (!fs.existsSync(errorHandlerPath)) {
250
+ fs.writeFileSync(errorHandlerPath, errorHandlerContent);
251
+ console.log(`✅ middlewares/errorHandler.js créé`);
252
+ }
253
+
254
+ // Generate utils/hash.js
255
+ const hashUtilContent = `/**
256
+ * Utilitaires de hachage
257
+ * npm install bcrypt
258
+ */
259
+ const bcrypt = require('bcrypt');
260
+
261
+ const SALT_ROUNDS = 12;
262
+
263
+ const hashPassword = async (password) => {
264
+ return bcrypt.hash(password, SALT_ROUNDS);
265
+ };
266
+
267
+ const verifyPassword = async (password, hash) => {
268
+ return bcrypt.compare(password, hash);
269
+ };
270
+
271
+ module.exports = { hashPassword, verifyPassword };
272
+ `;
273
+
274
+ const hashUtilPath = path.join(process.cwd(), 'utils', 'hash.js');
275
+ if (!fs.existsSync(hashUtilPath)) {
276
+ fs.writeFileSync(hashUtilPath, hashUtilContent);
277
+ console.log(`✅ utils/hash.js créé`);
278
+ }
279
+
127
280
  // Generate example model
128
281
  const modelContent = `const { Model } = require('outlet-orm');
129
282
  const db = require('./database');
@@ -131,11 +284,16 @@ const db = require('./database');
131
284
  class User extends Model {
132
285
  static table = 'users';
133
286
  static fillable = ['name', 'email', 'password'];
134
- static hidden = ['password'];
287
+ static hidden = ['password', 'refresh_token']; // 🔒 Ne jamais exposer
135
288
  static casts = {
136
289
  id: 'int',
137
290
  email_verified: 'boolean'
138
291
  };
292
+ static rules = {
293
+ name: 'required|string|min:2|max:100',
294
+ email: 'required|email',
295
+ password: 'required|min:8'
296
+ };
139
297
  static connection = db;
140
298
 
141
299
  // Définissez vos relations ici
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "outlet-orm",
3
- "version": "4.2.0",
3
+ "version": "4.2.1",
4
4
  "description": "A Laravel Eloquent-inspired ORM for Node.js with support for MySQL, PostgreSQL, and SQLite",
5
5
  "main": "src/index.js",
6
6
  "types": "types/index.d.ts",