@produtype/core 1.17.1 → 1.18.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.
|
@@ -854,10 +854,26 @@ async function detectSecurity(ctx) {
|
|
|
854
854
|
const text = await (0, readTextFileSafe_1.readTextFileSafe)(ctx.root, file);
|
|
855
855
|
if (!text)
|
|
856
856
|
continue;
|
|
857
|
+
/**
|
|
858
|
+
* The key has to be there, and "not found" is not "wide open".
|
|
859
|
+
*
|
|
860
|
+
* This read a missing `allowed_origins` as the permissive case, which is
|
|
861
|
+
* blindness turned into the loudest verdict there is. appwrite is not a Laravel
|
|
862
|
+
* application — it keeps its own `app/config/cors.php` holding methods and
|
|
863
|
+
* headers, with origins decided in `src/Appwrite/Network/Cors.php`, where they
|
|
864
|
+
* are matched by hostname and echoed back one at a time, never as a wildcard.
|
|
865
|
+
* The path matched, the key did not, and a product with a careful allowlist was
|
|
866
|
+
* reported at `high` as having opened itself to everybody.
|
|
867
|
+
*
|
|
868
|
+
* Laravel publishes that key with the file, so a `config/cors.php` without it is
|
|
869
|
+
* somebody else's file at the same path. This branch now says nothing about it.
|
|
870
|
+
*/
|
|
857
871
|
const origins = /'allowed_origins'\s*=>\s*\[([^\]]*)\]/.exec(text);
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
872
|
+
if (!origins)
|
|
873
|
+
continue;
|
|
874
|
+
const line = text.slice(0, origins.index).split('\n').length;
|
|
875
|
+
const hit = { file, line, snippet: origins[0].replace(/\s+/g, ' ').trim().slice(0, 200) };
|
|
876
|
+
if (/^\s*'\*'\s*,?\s*$/.test(origins[1]))
|
|
861
877
|
corsLoose.push(hit);
|
|
862
878
|
else
|
|
863
879
|
corsStrict.push(hit);
|
package/dist/utils/textSearch.js
CHANGED
|
@@ -26,6 +26,24 @@ const blockComments_1 = require("../analyzer/blockComments");
|
|
|
26
26
|
* and is left alone.
|
|
27
27
|
*/
|
|
28
28
|
const PATTERN_DECLARATION = /^(?:const\s+\w+(?:\s*:[^=]+)?\s*=\s*)?\/(?:[^/\\]|\\.)+\/[gimsuy]*\s*[,;]?$/;
|
|
29
|
+
/**
|
|
30
|
+
* An entry that says what something is called.
|
|
31
|
+
*
|
|
32
|
+
* appwrite ships a catalogue of function templates, and one line of it is
|
|
33
|
+
* `'name' => 'ALLOWED_ORIGINS',` — an environment variable *the user's* function may
|
|
34
|
+
* set, described in a table beside its placeholder and its help text. After the other
|
|
35
|
+
* two citations were withdrawn it was carrying appwrite's whole `high` cross-origin
|
|
36
|
+
* finding on its own, about a product whose real policy matches origins by hostname
|
|
37
|
+
* and never answers with a wildcard.
|
|
38
|
+
*
|
|
39
|
+
* A string bound to `name`, `key`, `label` or `id` is what a thing is called. That is
|
|
40
|
+
* not the same as a bare string in a list, which this file deliberately still reads —
|
|
41
|
+
* `'django.contrib.auth',` in an INSTALLED_APPS array *is* the behaviour, and the
|
|
42
|
+
* measurement that established it cost a real Django project eight points for being
|
|
43
|
+
* legible. The difference is the key: one line says "this is called X", the other says
|
|
44
|
+
* "X".
|
|
45
|
+
*/
|
|
46
|
+
const NAMES_SOMETHING = /^["']?(?:name|key|label|id|title|field|env|variable)["']?\s*(?:=>|:)\s*["'`][^"'`]+["'`],?$/i;
|
|
29
47
|
/**
|
|
30
48
|
* A constant that spells its own name.
|
|
31
49
|
*
|
|
@@ -99,7 +117,7 @@ function spellsItsOwnName(trimmed) {
|
|
|
99
117
|
* those really do introduce a declaration.
|
|
100
118
|
*/
|
|
101
119
|
const STATEMENT_KEYWORD = /^(?:import|package|from|export|return|case|new|type|class|struct|interface|enum|func|fun|def|public|private|protected|internal|throw|throws|extends|implements|use|using|namespace|module|require|await|yield|delete|typeof|instanceof|in|is|as|if|else|for|while|switch|do|try|catch|finally|with|assert|raise|lambda|val|const)\b/;
|
|
102
|
-
const TYPE_DECLARATION = /^(?:var\s+|let\s+|readonly\s+)?\w+\??\s*(?::\s*|\s+)(?:\[\]|\*|Array<|Map<|\bstring\b|\bnumber\b|\bboolean\b|\bbool\b|\bany\b|\bunknown\b|\bvoid\b|[A-Z])[\w.<>[\]
|
|
120
|
+
const TYPE_DECLARATION = /^(?:var\s+|let\s+|readonly\s+)?\w+\??\s*(?::\s*|\s+)(?:\[\]|\*|Array<|Map<|\bstring\b|\bnumber\b|\bboolean\b|\bbool\b|\bany\b|\bunknown\b|\bvoid\b|[A-Z])[\w.<>[\]|&*\s]*;?$/;
|
|
103
121
|
/**
|
|
104
122
|
* Prose about the code, rather than the code.
|
|
105
123
|
*
|
|
@@ -130,13 +148,26 @@ const COMMENT_LINE = /^(?:\/\/|\/\*|\*\/?|#(?![![])(?!!)|<!--|--\s)/;
|
|
|
130
148
|
*
|
|
131
149
|
* Nothing in the shape of the line tells the two apart, so the rule is not made.
|
|
132
150
|
*/
|
|
151
|
+
/**
|
|
152
|
+
* Two shapes the first version of this let through, both found in caddy.
|
|
153
|
+
*
|
|
154
|
+
* `allowedOrigins []*url.URL` is a struct field and the type is a pointer, which the
|
|
155
|
+
* character class did not allow — so a declaration was cited as a cross-origin
|
|
156
|
+
* decision. `AllowDomain []string // FIXME: this option is from legacy` is the same
|
|
157
|
+
* thing with gitea's note after it, and the rule required the line to end at the
|
|
158
|
+
* type.
|
|
159
|
+
*
|
|
160
|
+
* A trailing comment is dropped before the test, exactly as the self-naming rule
|
|
161
|
+
* drops it, and `*` and `&` join the characters a type may be written with.
|
|
162
|
+
*/
|
|
133
163
|
function declaresAType(trimmed) {
|
|
134
|
-
const
|
|
135
|
-
|
|
164
|
+
const withoutComment = trimmed.replace(/\s*(?:\/\/|#).*$/, '').trimEnd();
|
|
165
|
+
const withoutDeclarator = withoutComment.replace(/^(?:var|let|readonly)\s+/, '');
|
|
166
|
+
return !STATEMENT_KEYWORD.test(withoutDeclarator) && TYPE_DECLARATION.test(withoutComment);
|
|
136
167
|
}
|
|
137
168
|
function declaresRatherThanDoes(line) {
|
|
138
169
|
const trimmed = line.trim();
|
|
139
|
-
return COMMENT_LINE.test(trimmed) || PATTERN_DECLARATION.test(trimmed) || declaresAType(trimmed) || spellsItsOwnName(trimmed);
|
|
170
|
+
return COMMENT_LINE.test(trimmed) || PATTERN_DECLARATION.test(trimmed) || declaresAType(trimmed) || spellsItsOwnName(trimmed) || NAMES_SOMETHING.test(trimmed);
|
|
140
171
|
}
|
|
141
172
|
/**
|
|
142
173
|
* Whether this line may be quoted back to the reader as something the code does.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@produtype/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.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": {
|