@produtype/core 1.13.0 → 1.15.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.
|
@@ -726,6 +726,74 @@ async function detectSecurity(ctx) {
|
|
|
726
726
|
* `CORS_ORIGIN_ALLOW_ALL`, which is what it was called before version 3.5 — is the
|
|
727
727
|
* one line that opens it.
|
|
728
728
|
*/
|
|
729
|
+
/**
|
|
730
|
+
* Rails' answer, which is a gem with a small language of its own.
|
|
731
|
+
*
|
|
732
|
+
* chatwoot scored 98 and `production_ready` with its cross-origin policy reported
|
|
733
|
+
* as "not detected". It installs `rack-cors`, mounts `Rack::Cors` as the first
|
|
734
|
+
* middleware in `config/initializers/cors.rb`, and writes `origins '*'` — which
|
|
735
|
+
* opens `/packs/*`, `/audio/*`, `/public/api/*`, and everything else when
|
|
736
|
+
* `CW_API_ONLY_SERVER` is set. Not one of the words this check looked for appears
|
|
737
|
+
* in that file: the gem's DSL says `origins`, not `Access-Control-Allow-Origin`.
|
|
738
|
+
*
|
|
739
|
+
* `rack-cors`, `Rack::Cors` and `origins` are the gem's; the values are the
|
|
740
|
+
* author's. Every `origins` line is read, because the block lists one per rule and
|
|
741
|
+
* a permissive one beside a restricted one is still permissive.
|
|
742
|
+
*/
|
|
743
|
+
for (const file of ctx.files.all.filter((f) => /\.rb$/.test(f))) {
|
|
744
|
+
const text = await (0, readTextFileSafe_1.readTextFileSafe)(ctx.root, file);
|
|
745
|
+
if (!text || !/\bRack::Cors\b/.test(text))
|
|
746
|
+
continue;
|
|
747
|
+
const lines = text.split(/\r?\n/);
|
|
748
|
+
for (let i = 0; i < lines.length; i++) {
|
|
749
|
+
const origins = /^\s*origins\s+(.+)$/.exec(lines[i]);
|
|
750
|
+
if (!origins || !(0, textSearch_1.isCitableLine)(lines[i].trim()))
|
|
751
|
+
continue;
|
|
752
|
+
const hit = { file, line: i + 1, snippet: lines[i].trim().slice(0, 200) };
|
|
753
|
+
if (/^['"]\*['"]/.test(origins[1].trim()))
|
|
754
|
+
corsLoose.push(hit);
|
|
755
|
+
else
|
|
756
|
+
corsStrict.push(hit);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Symfony's answer, which is a bundle and the file it reads.
|
|
761
|
+
*
|
|
762
|
+
* kimai scored 93 and `production_ready` while its API answered every origin on
|
|
763
|
+
* earth: `config/packages/nelmio_cors.yaml` sets `allow_origin: []` in its defaults
|
|
764
|
+
* — the bundle's own comment says "for security reasons we do not allow CORS by
|
|
765
|
+
* default" — and then `allow_origin: ['*']` under `^/api/`. The report said "CORS
|
|
766
|
+
* configuration not detected" and gave no verdict at all.
|
|
767
|
+
*
|
|
768
|
+
* `nelmio/cors-bundle` is what a Symfony project installs for this, `nelmio_cors` is
|
|
769
|
+
* the configuration key the bundle defines and `allow_origin` is its setting. None
|
|
770
|
+
* of the three is the author's to choose; the values are.
|
|
771
|
+
*
|
|
772
|
+
* Every `allow_origin` in the file is read, not the first. A bundle configures
|
|
773
|
+
* defaults and then overrides them per path, and it is the override that is
|
|
774
|
+
* reachable — the same reason the ASP.NET branch above reports the open one where a
|
|
775
|
+
* project ships both.
|
|
776
|
+
*/
|
|
777
|
+
for (const file of ctx.files.all.filter((f) => /(^|\/)config\/packages\/[\w.-]*nelmio_cors[\w.-]*\.ya?ml$/i.test(f))) {
|
|
778
|
+
const text = await (0, readTextFileSafe_1.readTextFileSafe)(ctx.root, file);
|
|
779
|
+
if (!text)
|
|
780
|
+
continue;
|
|
781
|
+
const lines = text.split(/\r?\n/);
|
|
782
|
+
for (let i = 0; i < lines.length; i++) {
|
|
783
|
+
const origins = /^\s*allow_origin\s*:\s*(.*)$/.exec(lines[i]);
|
|
784
|
+
if (!origins)
|
|
785
|
+
continue;
|
|
786
|
+
const value = origins[1].trim();
|
|
787
|
+
/** An empty list is the bundle refusing every cross-origin request. */
|
|
788
|
+
if (value === '[]' || value === '')
|
|
789
|
+
continue;
|
|
790
|
+
const hit = { file, line: i + 1, snippet: lines[i].trim().slice(0, 200) };
|
|
791
|
+
if (/\[\s*['"]\*['"]\s*\]/.test(value) || value === "'*'" || value === '"*"')
|
|
792
|
+
corsLoose.push(hit);
|
|
793
|
+
else
|
|
794
|
+
corsStrict.push(hit);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
729
797
|
/**
|
|
730
798
|
* Laravel's answer, which is a file with a name the framework chose.
|
|
731
799
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@produtype/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.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": {
|