vg-coder-cli 1.0.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/README.md +179 -0
- package/bin/vg-coder.js +11 -0
- package/package.json +64 -0
- package/src/detectors/project-detector.js +333 -0
- package/src/exporter/html-exporter.js +1026 -0
- package/src/ignore/ignore-manager.js +298 -0
- package/src/index.js +282 -0
- package/src/scanner/file-scanner.js +592 -0
- package/src/tokenizer/token-manager.js +389 -0
- package/src/utils/helpers.js +128 -0
- package/test-project/package.json +21 -0
- package/test-project/src/controllers/userController.js +129 -0
- package/test-project/src/index.js +46 -0
- package/test-project/src/middleware/auth.js +142 -0
- package/test-project/styles/main.css +287 -0
- package/vg-coder-cli-1.0.0.tgz +0 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
const jwt = require('jsonwebtoken');
|
|
2
|
+
const User = require('../models/User');
|
|
3
|
+
|
|
4
|
+
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Authentication middleware
|
|
8
|
+
* Verifies JWT token and attaches user to request
|
|
9
|
+
*/
|
|
10
|
+
const authMiddleware = async (req, res, next) => {
|
|
11
|
+
try {
|
|
12
|
+
const authHeader = req.headers.authorization;
|
|
13
|
+
|
|
14
|
+
if (!authHeader) {
|
|
15
|
+
return res.status(401).json({
|
|
16
|
+
error: 'Access denied. No token provided.'
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const token = authHeader.startsWith('Bearer ')
|
|
21
|
+
? authHeader.slice(7)
|
|
22
|
+
: authHeader;
|
|
23
|
+
|
|
24
|
+
if (!token) {
|
|
25
|
+
return res.status(401).json({
|
|
26
|
+
error: 'Access denied. Invalid token format.'
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Verify token
|
|
31
|
+
const decoded = jwt.verify(token, JWT_SECRET);
|
|
32
|
+
|
|
33
|
+
// Get user from database
|
|
34
|
+
const user = await User.findByPk(decoded.userId);
|
|
35
|
+
if (!user) {
|
|
36
|
+
return res.status(401).json({
|
|
37
|
+
error: 'Access denied. User not found.'
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Check if user is active
|
|
42
|
+
if (!user.isActive) {
|
|
43
|
+
return res.status(401).json({
|
|
44
|
+
error: 'Access denied. User account is disabled.'
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Attach user to request
|
|
49
|
+
req.user = user;
|
|
50
|
+
next();
|
|
51
|
+
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (error.name === 'JsonWebTokenError') {
|
|
54
|
+
return res.status(401).json({
|
|
55
|
+
error: 'Access denied. Invalid token.'
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (error.name === 'TokenExpiredError') {
|
|
60
|
+
return res.status(401).json({
|
|
61
|
+
error: 'Access denied. Token expired.'
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.error('Auth middleware error:', error);
|
|
66
|
+
res.status(500).json({
|
|
67
|
+
error: 'Internal server error during authentication.'
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Role-based authorization middleware
|
|
74
|
+
*/
|
|
75
|
+
const requireRole = (roles) => {
|
|
76
|
+
return (req, res, next) => {
|
|
77
|
+
if (!req.user) {
|
|
78
|
+
return res.status(401).json({
|
|
79
|
+
error: 'Access denied. User not authenticated.'
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const userRoles = Array.isArray(req.user.roles)
|
|
84
|
+
? req.user.roles
|
|
85
|
+
: [req.user.role];
|
|
86
|
+
|
|
87
|
+
const hasRequiredRole = roles.some(role =>
|
|
88
|
+
userRoles.includes(role)
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (!hasRequiredRole) {
|
|
92
|
+
return res.status(403).json({
|
|
93
|
+
error: 'Access denied. Insufficient permissions.',
|
|
94
|
+
required: roles,
|
|
95
|
+
current: userRoles
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
next();
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Optional authentication middleware
|
|
105
|
+
* Attaches user if token is valid, but doesn't require it
|
|
106
|
+
*/
|
|
107
|
+
const optionalAuth = async (req, res, next) => {
|
|
108
|
+
try {
|
|
109
|
+
const authHeader = req.headers.authorization;
|
|
110
|
+
|
|
111
|
+
if (!authHeader) {
|
|
112
|
+
return next();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const token = authHeader.startsWith('Bearer ')
|
|
116
|
+
? authHeader.slice(7)
|
|
117
|
+
: authHeader;
|
|
118
|
+
|
|
119
|
+
if (!token) {
|
|
120
|
+
return next();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const decoded = jwt.verify(token, JWT_SECRET);
|
|
124
|
+
const user = await User.findByPk(decoded.userId);
|
|
125
|
+
|
|
126
|
+
if (user && user.isActive) {
|
|
127
|
+
req.user = user;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
next();
|
|
131
|
+
|
|
132
|
+
} catch (error) {
|
|
133
|
+
// Ignore auth errors in optional auth
|
|
134
|
+
next();
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
module.exports = {
|
|
139
|
+
authMiddleware,
|
|
140
|
+
requireRole,
|
|
141
|
+
optionalAuth
|
|
142
|
+
};
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/* Main stylesheet for test project */
|
|
2
|
+
|
|
3
|
+
:root {
|
|
4
|
+
--primary-color: #007bff;
|
|
5
|
+
--secondary-color: #6c757d;
|
|
6
|
+
--success-color: #28a745;
|
|
7
|
+
--danger-color: #dc3545;
|
|
8
|
+
--warning-color: #ffc107;
|
|
9
|
+
--info-color: #17a2b8;
|
|
10
|
+
--light-color: #f8f9fa;
|
|
11
|
+
--dark-color: #343a40;
|
|
12
|
+
|
|
13
|
+
--font-family-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
14
|
+
--font-family-mono: SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
15
|
+
|
|
16
|
+
--border-radius: 0.375rem;
|
|
17
|
+
--box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
|
18
|
+
--transition: all 0.15s ease-in-out;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
* {
|
|
22
|
+
box-sizing: border-box;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
body {
|
|
26
|
+
font-family: var(--font-family-sans);
|
|
27
|
+
line-height: 1.6;
|
|
28
|
+
color: var(--dark-color);
|
|
29
|
+
background-color: #fff;
|
|
30
|
+
margin: 0;
|
|
31
|
+
padding: 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.container {
|
|
35
|
+
max-width: 1200px;
|
|
36
|
+
margin: 0 auto;
|
|
37
|
+
padding: 0 1rem;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.header {
|
|
41
|
+
background-color: var(--primary-color);
|
|
42
|
+
color: white;
|
|
43
|
+
padding: 1rem 0;
|
|
44
|
+
box-shadow: var(--box-shadow);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.header h1 {
|
|
48
|
+
margin: 0;
|
|
49
|
+
font-size: 1.75rem;
|
|
50
|
+
font-weight: 600;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.nav {
|
|
54
|
+
background-color: var(--light-color);
|
|
55
|
+
border-bottom: 1px solid #dee2e6;
|
|
56
|
+
padding: 0.5rem 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.nav ul {
|
|
60
|
+
list-style: none;
|
|
61
|
+
margin: 0;
|
|
62
|
+
padding: 0;
|
|
63
|
+
display: flex;
|
|
64
|
+
gap: 2rem;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.nav a {
|
|
68
|
+
color: var(--dark-color);
|
|
69
|
+
text-decoration: none;
|
|
70
|
+
padding: 0.5rem 1rem;
|
|
71
|
+
border-radius: var(--border-radius);
|
|
72
|
+
transition: var(--transition);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.nav a:hover,
|
|
76
|
+
.nav a.active {
|
|
77
|
+
background-color: var(--primary-color);
|
|
78
|
+
color: white;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.main {
|
|
82
|
+
padding: 2rem 0;
|
|
83
|
+
min-height: calc(100vh - 200px);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.card {
|
|
87
|
+
background: white;
|
|
88
|
+
border: 1px solid #dee2e6;
|
|
89
|
+
border-radius: var(--border-radius);
|
|
90
|
+
box-shadow: var(--box-shadow);
|
|
91
|
+
margin-bottom: 1.5rem;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.card-header {
|
|
95
|
+
padding: 1rem 1.25rem;
|
|
96
|
+
background-color: var(--light-color);
|
|
97
|
+
border-bottom: 1px solid #dee2e6;
|
|
98
|
+
font-weight: 600;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.card-body {
|
|
102
|
+
padding: 1.25rem;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.btn {
|
|
106
|
+
display: inline-block;
|
|
107
|
+
padding: 0.5rem 1rem;
|
|
108
|
+
font-size: 1rem;
|
|
109
|
+
font-weight: 400;
|
|
110
|
+
line-height: 1.5;
|
|
111
|
+
text-align: center;
|
|
112
|
+
text-decoration: none;
|
|
113
|
+
vertical-align: middle;
|
|
114
|
+
cursor: pointer;
|
|
115
|
+
border: 1px solid transparent;
|
|
116
|
+
border-radius: var(--border-radius);
|
|
117
|
+
transition: var(--transition);
|
|
118
|
+
user-select: none;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.btn-primary {
|
|
122
|
+
color: white;
|
|
123
|
+
background-color: var(--primary-color);
|
|
124
|
+
border-color: var(--primary-color);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.btn-primary:hover {
|
|
128
|
+
background-color: #0056b3;
|
|
129
|
+
border-color: #004085;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.btn-secondary {
|
|
133
|
+
color: white;
|
|
134
|
+
background-color: var(--secondary-color);
|
|
135
|
+
border-color: var(--secondary-color);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.btn-success {
|
|
139
|
+
color: white;
|
|
140
|
+
background-color: var(--success-color);
|
|
141
|
+
border-color: var(--success-color);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.btn-danger {
|
|
145
|
+
color: white;
|
|
146
|
+
background-color: var(--danger-color);
|
|
147
|
+
border-color: var(--danger-color);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.form-group {
|
|
151
|
+
margin-bottom: 1rem;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.form-label {
|
|
155
|
+
display: block;
|
|
156
|
+
margin-bottom: 0.5rem;
|
|
157
|
+
font-weight: 500;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.form-control {
|
|
161
|
+
display: block;
|
|
162
|
+
width: 100%;
|
|
163
|
+
padding: 0.5rem 0.75rem;
|
|
164
|
+
font-size: 1rem;
|
|
165
|
+
line-height: 1.5;
|
|
166
|
+
color: var(--dark-color);
|
|
167
|
+
background-color: white;
|
|
168
|
+
border: 1px solid #ced4da;
|
|
169
|
+
border-radius: var(--border-radius);
|
|
170
|
+
transition: var(--transition);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.form-control:focus {
|
|
174
|
+
outline: 0;
|
|
175
|
+
border-color: #80bdff;
|
|
176
|
+
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.table {
|
|
180
|
+
width: 100%;
|
|
181
|
+
margin-bottom: 1rem;
|
|
182
|
+
border-collapse: collapse;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.table th,
|
|
186
|
+
.table td {
|
|
187
|
+
padding: 0.75rem;
|
|
188
|
+
vertical-align: top;
|
|
189
|
+
border-top: 1px solid #dee2e6;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.table thead th {
|
|
193
|
+
vertical-align: bottom;
|
|
194
|
+
border-bottom: 2px solid #dee2e6;
|
|
195
|
+
background-color: var(--light-color);
|
|
196
|
+
font-weight: 600;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.table tbody tr:hover {
|
|
200
|
+
background-color: rgba(0, 0, 0, 0.075);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.alert {
|
|
204
|
+
position: relative;
|
|
205
|
+
padding: 0.75rem 1.25rem;
|
|
206
|
+
margin-bottom: 1rem;
|
|
207
|
+
border: 1px solid transparent;
|
|
208
|
+
border-radius: var(--border-radius);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.alert-success {
|
|
212
|
+
color: #155724;
|
|
213
|
+
background-color: #d4edda;
|
|
214
|
+
border-color: #c3e6cb;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.alert-danger {
|
|
218
|
+
color: #721c24;
|
|
219
|
+
background-color: #f8d7da;
|
|
220
|
+
border-color: #f5c6cb;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.alert-warning {
|
|
224
|
+
color: #856404;
|
|
225
|
+
background-color: #fff3cd;
|
|
226
|
+
border-color: #ffeaa7;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.footer {
|
|
230
|
+
background-color: var(--dark-color);
|
|
231
|
+
color: white;
|
|
232
|
+
text-align: center;
|
|
233
|
+
padding: 1rem 0;
|
|
234
|
+
margin-top: auto;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/* Responsive design */
|
|
238
|
+
@media (max-width: 768px) {
|
|
239
|
+
.container {
|
|
240
|
+
padding: 0 0.5rem;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.nav ul {
|
|
244
|
+
flex-direction: column;
|
|
245
|
+
gap: 0;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.nav a {
|
|
249
|
+
display: block;
|
|
250
|
+
border-radius: 0;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.main {
|
|
254
|
+
padding: 1rem 0;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.card-body {
|
|
258
|
+
padding: 1rem;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/* Utility classes */
|
|
263
|
+
.text-center { text-align: center; }
|
|
264
|
+
.text-left { text-align: left; }
|
|
265
|
+
.text-right { text-align: right; }
|
|
266
|
+
|
|
267
|
+
.mt-1 { margin-top: 0.25rem; }
|
|
268
|
+
.mt-2 { margin-top: 0.5rem; }
|
|
269
|
+
.mt-3 { margin-top: 1rem; }
|
|
270
|
+
.mt-4 { margin-top: 1.5rem; }
|
|
271
|
+
.mt-5 { margin-top: 3rem; }
|
|
272
|
+
|
|
273
|
+
.mb-1 { margin-bottom: 0.25rem; }
|
|
274
|
+
.mb-2 { margin-bottom: 0.5rem; }
|
|
275
|
+
.mb-3 { margin-bottom: 1rem; }
|
|
276
|
+
.mb-4 { margin-bottom: 1.5rem; }
|
|
277
|
+
.mb-5 { margin-bottom: 3rem; }
|
|
278
|
+
|
|
279
|
+
.d-none { display: none; }
|
|
280
|
+
.d-block { display: block; }
|
|
281
|
+
.d-inline { display: inline; }
|
|
282
|
+
.d-inline-block { display: inline-block; }
|
|
283
|
+
.d-flex { display: flex; }
|
|
284
|
+
|
|
285
|
+
.justify-content-center { justify-content: center; }
|
|
286
|
+
.justify-content-between { justify-content: space-between; }
|
|
287
|
+
.align-items-center { align-items: center; }
|
|
Binary file
|