@produtype/core 0.80.0 → 0.81.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.
|
@@ -165,6 +165,26 @@ async function detectSecurity(ctx) {
|
|
|
165
165
|
/X-Frame-Options/i,
|
|
166
166
|
/SECURE_HSTS_SECONDS/,
|
|
167
167
|
/securityHeaders/i,
|
|
168
|
+
/**
|
|
169
|
+
* Django's spelling of the same decisions.
|
|
170
|
+
*
|
|
171
|
+
* The list held the HTTP header names and one Django setting, so a project that
|
|
172
|
+
* writes `X_FRAME_OPTIONS = "SAMEORIGIN"` — the setting, with underscores, which
|
|
173
|
+
* is the only way to say it in Django — matched nothing. paperless-ngx sets it
|
|
174
|
+
* and was told at `high` to add security headers.
|
|
175
|
+
*
|
|
176
|
+
* Only the settings that choose a policy. `SECURE_PROXY_SSL_HEADER` is not one
|
|
177
|
+
* of them: it tells Django how to tell it is behind HTTPS, and every deployment
|
|
178
|
+
* behind a proxy needs it whether or not anybody thought about headers. And
|
|
179
|
+
* `SecurityMiddleware` itself stays out, for the reason recorded further down —
|
|
180
|
+
* `django-admin startproject` writes it into every new project.
|
|
181
|
+
*/
|
|
182
|
+
/^\s*X_FRAME_OPTIONS\s*=/m,
|
|
183
|
+
/^\s*SECURE_CONTENT_TYPE_NOSNIFF\s*=/m,
|
|
184
|
+
/^\s*SECURE_BROWSER_XSS_FILTER\s*=/m,
|
|
185
|
+
/^\s*SECURE_REFERRER_POLICY\s*=/m,
|
|
186
|
+
/^\s*SECURE_CROSS_ORIGIN_OPENER_POLICY\s*=/m,
|
|
187
|
+
/^\s*CSP_DEFAULT_SRC\s*=/m,
|
|
168
188
|
], 20);
|
|
169
189
|
const helmet = helmetDep || headerSignals.length > 0;
|
|
170
190
|
/**
|
|
@@ -319,9 +339,30 @@ async function detectSecurity(ctx) {
|
|
|
319
339
|
if (at !== -1) {
|
|
320
340
|
const window = lines.slice(at, Math.min(lines.length, at + 12)).join('\n');
|
|
321
341
|
if (STARLETTE_CORS_CALL.test(window)) {
|
|
322
|
-
const allowList = /allow_origins\s*=\s*\[([^\]]*)\]/.exec(window);
|
|
323
342
|
const hit = { file, line: at + 1, snippet: lines[at].trim().slice(0, 200) };
|
|
324
|
-
|
|
343
|
+
const allowList = /allow_origins\s*=\s*\[([^\]]*)\]/.exec(window);
|
|
344
|
+
if (allowList) {
|
|
345
|
+
if (/^\s*["']\*["']\s*,?\s*$/.test(allowList[1]))
|
|
346
|
+
corsLoose.push(hit);
|
|
347
|
+
else
|
|
348
|
+
corsStrict.push(hit);
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* `allow_origins=allowed_origins`, which is how a real application writes it.
|
|
353
|
+
*
|
|
354
|
+
* mealie builds the list from its settings and passes the name, and calling
|
|
355
|
+
* that "no explicit origin restrictions" at `high` reads as advice to add
|
|
356
|
+
* the allowlist it has. The wildcard is written literally when it is meant —
|
|
357
|
+
* `allow_origins=["*"]` — so a name is followed to its assignment, and a
|
|
358
|
+
* value assembled somewhere this cannot see is a configuration rather than a
|
|
359
|
+
* wildcard.
|
|
360
|
+
*/
|
|
361
|
+
const named = /allow_origins\s*=\s*([A-Za-z_][\w.]*)/.exec(window);
|
|
362
|
+
const assigned = named
|
|
363
|
+
? new RegExp(`^\\s*${named[1].split('.').pop()}\\s*=\\s*\\[([^\\]]*)\\]`, 'm').exec(text)
|
|
364
|
+
: null;
|
|
365
|
+
if (assigned && /^\s*["']\*["']\s*,?\s*$/.test(assigned[1]))
|
|
325
366
|
corsLoose.push(hit);
|
|
326
367
|
else
|
|
327
368
|
corsStrict.push(hit);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@produtype/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.81.0",
|
|
4
4
|
"description": "Deterministic CLI and library that analyzes a web application repository and reports how far it is from production-ready for the kind of product it is meant to be.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|