@auth0/auth0-checkmate 1.4.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/.github/CODEOWNERS +1 -0
- package/.github/workflows/npm-release.yml +77 -0
- package/.github/workflows/sca_scan.yml +10 -0
- package/.github/workflows/test.yml +48 -0
- package/AUTHORS +5 -0
- package/LICENSE +203 -0
- package/README.md +166 -0
- package/THIRD-PARTY-NOTICES +226 -0
- package/analyzer/lib/actions/checkActionsHardCodedValues.js +151 -0
- package/analyzer/lib/actions/checkActionsRuntime.js +105 -0
- package/analyzer/lib/actions/checkDependencies.js +111 -0
- package/analyzer/lib/attack_protection/checkBotDetectionSetting.js +76 -0
- package/analyzer/lib/attack_protection/checkBreachedPassword.js +140 -0
- package/analyzer/lib/attack_protection/checkBruteForce.js +89 -0
- package/analyzer/lib/attack_protection/checkSuspiciousIPThrottling.js +89 -0
- package/analyzer/lib/canonical_domain/checkCanonicalDomain.js +63 -0
- package/analyzer/lib/clients/checkAllowedCallbacks.js +122 -0
- package/analyzer/lib/clients/checkAllowedLogoutUrl.js +124 -0
- package/analyzer/lib/clients/checkApplicationLoginUri.js +125 -0
- package/analyzer/lib/clients/checkCrossOriginAuthentication.js +91 -0
- package/analyzer/lib/clients/checkGrantTypes.js +138 -0
- package/analyzer/lib/clients/checkJWTSignAlg.js +118 -0
- package/analyzer/lib/clients/checkRefreshToken.js +108 -0
- package/analyzer/lib/clients/checkWebOrigins.js +55 -0
- package/analyzer/lib/constants.js +63 -0
- package/analyzer/lib/custom_domain/checkCustomDomain.js +53 -0
- package/analyzer/lib/databases/checkAuthenticationMethods.js +98 -0
- package/analyzer/lib/databases/checkDASHardCodedValues.js +163 -0
- package/analyzer/lib/databases/checkEmailAttributeVerification.js +114 -0
- package/analyzer/lib/databases/checkEnabledDatabaseCustomization.js +83 -0
- package/analyzer/lib/databases/checkPasswordComplexity.js +100 -0
- package/analyzer/lib/databases/checkPasswordHistory.js +92 -0
- package/analyzer/lib/databases/checkPasswordNoPersonalInfo.js +91 -0
- package/analyzer/lib/databases/checkPasswordPolicy.js +95 -0
- package/analyzer/lib/databases/checkPromotedDBConnection.js +96 -0
- package/analyzer/lib/email_provider/checkEmailProvider.js +37 -0
- package/analyzer/lib/email_templates/checkEmailTemplates.js +71 -0
- package/analyzer/lib/error_page_template/checkErrorPageTemplate.js +153 -0
- package/analyzer/lib/event_streams/checkEventStreams.js +71 -0
- package/analyzer/lib/executeCheck.js +12 -0
- package/analyzer/lib/hooks/checkHooks.js +43 -0
- package/analyzer/lib/listOfAnalyser.js +24 -0
- package/analyzer/lib/log_streams/checkLogStream.js +60 -0
- package/analyzer/lib/logger.js +16 -0
- package/analyzer/lib/multifactor/checkGuardianFactors.js +72 -0
- package/analyzer/lib/multifactor/checkGuardianPolicy.js +40 -0
- package/analyzer/lib/network_acl/checkNetworkACL.js +35 -0
- package/analyzer/lib/rules/checkRules.js +102 -0
- package/analyzer/lib/tenant_settings/checkDefaultAudience.js +53 -0
- package/analyzer/lib/tenant_settings/checkDefaultDirectory.js +48 -0
- package/analyzer/lib/tenant_settings/checkEnabledDynamicClientRegistration.js +60 -0
- package/analyzer/lib/tenant_settings/checkSandboxVersion.js +37 -0
- package/analyzer/lib/tenant_settings/checkSessionLifetime.js +95 -0
- package/analyzer/lib/tenant_settings/checkSupportEmail.js +61 -0
- package/analyzer/lib/tenant_settings/checkSupportUrl.js +61 -0
- package/analyzer/lib/tenant_settings/checkTenantLoginUrl.js +71 -0
- package/analyzer/lib/tenant_settings/checkTenantLogoutUrl.js +60 -0
- package/analyzer/report.js +404 -0
- package/analyzer/tools/auth0.js +443 -0
- package/analyzer/tools/helpers.js +71 -0
- package/analyzer/tools/summary.js +84 -0
- package/analyzer/tools/utils.js +72 -0
- package/bin/index.js +393 -0
- package/eslint.config.mjs +16 -0
- package/images/auth0.png +0 -0
- package/images/okta.png +0 -0
- package/locales/en.json +1417 -0
- package/package.json +66 -0
- package/tests/actions/checkActionsHardCodedValues.test.js +106 -0
- package/tests/actions/checkActionsRuntime.test.js +102 -0
- package/tests/actions/checkDependencies.test.js +131 -0
- package/tests/attack_protection/checkBreachedPassword.test.js +253 -0
- package/tests/attack_protection/checkBruteForce.test.js +181 -0
- package/tests/attack_protection/checkSuspiciousIPThrottling.test.js +222 -0
- package/tests/canonical_domain/checkCanonicalDomain.test.js +94 -0
- package/tests/clients/checkAllowedCallbacks.test.js +149 -0
- package/tests/clients/checkAllowedLogoutUrl.test.js +149 -0
- package/tests/clients/checkApplicationLoginUri.test.js +180 -0
- package/tests/clients/checkCrossOriginAuthentication.test.js +99 -0
- package/tests/clients/checkGrantTypes.test.js +154 -0
- package/tests/clients/checkJWTSignAlg.test.js +121 -0
- package/tests/clients/checkRefreshToken.test.js +63 -0
- package/tests/clients/checkWebOrigins.test.js +140 -0
- package/tests/custom_domain/checkCustomDomain.test.js +73 -0
- package/tests/databases/checkAuthenticationMethods.test.js +124 -0
- package/tests/databases/checkDASHardCodedValues.test.js +77 -0
- package/tests/databases/checkEmailAttributeVerification.test.js +79 -0
- package/tests/databases/checkEnabledDatabaseCustomization.test.js +68 -0
- package/tests/databases/checkPasswordComplexity.test.js +127 -0
- package/tests/databases/checkPasswordHistory.test.js +100 -0
- package/tests/databases/checkPasswordNoPersonalInfo.test.js +94 -0
- package/tests/databases/checkPasswordPolicy.test.js +161 -0
- package/tests/databases/checkPromotedDBConnection.test.js +62 -0
- package/tests/email_provider/checkEmailProvider.test.js +58 -0
- package/tests/email_templates/checkEmailTemplates.test.js +120 -0
- package/tests/error_page_template/checkErrorPageTemplate.test.js +315 -0
- package/tests/event_streams/checkEventStreams.test.js +118 -0
- package/tests/hooks/checkHooks.test.js +112 -0
- package/tests/log_streams/checkLogStream.test.js +140 -0
- package/tests/multifactor/checkGuardianFactors.test.js +94 -0
- package/tests/multifactor/checkGuardianPolicy.test.js +49 -0
- package/tests/rules/checkRules.test.js +102 -0
- package/tests/tenant_settings/checkDefaultAudience.test.js +62 -0
- package/tests/tenant_settings/checkDefaultDirectory.test.js +62 -0
- package/tests/tenant_settings/checkEnabledDynamicClientRegistration.test.js +97 -0
- package/tests/tenant_settings/checkSandboxVersion.test.js +50 -0
- package/tests/tenant_settings/checkSessionLifetime.test.js +108 -0
- package/tests/tenant_settings/checkSupportEmail.test.js +77 -0
- package/tests/tenant_settings/checkSupportUrl.test.js +77 -0
- package/tests/tenant_settings/checkTenantLoginUri.test.js +82 -0
- package/tests/tenant_settings/checkTenantLogoutUrl.test.js +108 -0
- package/tests/tools/auth0.test.js +833 -0
- package/tests/tools/helpers.test.js +692 -0
- package/views/pdf_cli_report.handlebars +571 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
const chai = require("chai");
|
|
2
|
+
const expect = chai.expect;
|
|
3
|
+
|
|
4
|
+
const checkEmailTemplates = require("../../analyzer/lib/email_templates/checkEmailTemplates");
|
|
5
|
+
const CONSTANTS = require("../../analyzer/lib/constants");
|
|
6
|
+
|
|
7
|
+
describe("checkEmailTemplates", function () {
|
|
8
|
+
it("should return fail when no email templates are provided", function () {
|
|
9
|
+
const options = {};
|
|
10
|
+
|
|
11
|
+
checkEmailTemplates(options, (report) => {
|
|
12
|
+
expect(report).to.deep.equal([
|
|
13
|
+
{
|
|
14
|
+
field: "email_templates_not_configured",
|
|
15
|
+
status: CONSTANTS.FAIL,
|
|
16
|
+
},
|
|
17
|
+
]);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("should return fail for email templates without configuration", function () {
|
|
22
|
+
const options = {
|
|
23
|
+
emailTemplates: [
|
|
24
|
+
{
|
|
25
|
+
name: "Verification Email (Link)",
|
|
26
|
+
template: { template: "verify_email", enabled: true },
|
|
27
|
+
},
|
|
28
|
+
{ name: "Verification Email (Code)", template: null },
|
|
29
|
+
{ name: "Welcome Email", template: null },
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
checkEmailTemplates(options, (report) => {
|
|
34
|
+
expect(report).to.deep.equal([
|
|
35
|
+
{
|
|
36
|
+
field: "email_template_enabled",
|
|
37
|
+
status: CONSTANTS.SUCCESS,
|
|
38
|
+
attr: "verify_email",
|
|
39
|
+
value: "verify_email",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
field: "email_template_not_configured",
|
|
43
|
+
status: CONSTANTS.FAIL,
|
|
44
|
+
attr: "Verification Email (Code)",
|
|
45
|
+
value: "Verification Email (Code)",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
field: "email_template_not_configured",
|
|
49
|
+
status: CONSTANTS.FAIL,
|
|
50
|
+
attr: "Welcome Email",
|
|
51
|
+
value: "Welcome Email",
|
|
52
|
+
},
|
|
53
|
+
]);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("should return success for enabled email templates", function () {
|
|
58
|
+
const options = {
|
|
59
|
+
emailTemplates: [
|
|
60
|
+
{
|
|
61
|
+
name: "Verification Email (Link)",
|
|
62
|
+
template: { template: "verify_email", enabled: true },
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: "Verification Email (Code)",
|
|
66
|
+
template: { template: "verify_code", enabled: true },
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
checkEmailTemplates(options, (report) => {
|
|
72
|
+
expect(report).to.deep.equal([
|
|
73
|
+
{
|
|
74
|
+
field: "email_template_enabled",
|
|
75
|
+
status: CONSTANTS.SUCCESS,
|
|
76
|
+
attr: "verify_email",
|
|
77
|
+
value: "verify_email",
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
field: "email_template_enabled",
|
|
81
|
+
status: CONSTANTS.SUCCESS,
|
|
82
|
+
attr: "verify_code",
|
|
83
|
+
value: "verify_code",
|
|
84
|
+
},
|
|
85
|
+
]);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("should return fail for disabled email templates", function () {
|
|
90
|
+
const options = {
|
|
91
|
+
emailTemplates: [
|
|
92
|
+
{
|
|
93
|
+
name: "Verification Email (Link)",
|
|
94
|
+
template: { template: "verify_email", enabled: false },
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: "Verification Email (Code)",
|
|
98
|
+
template: { template: "verify_code", enabled: false },
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
checkEmailTemplates(options, (report) => {
|
|
104
|
+
expect(report).to.deep.equal([
|
|
105
|
+
{
|
|
106
|
+
field: "email_template_not_enabled",
|
|
107
|
+
status: CONSTANTS.FAIL,
|
|
108
|
+
attr: "Verification Email (Link)",
|
|
109
|
+
value: "Verification Email (Link)",
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
field: "email_template_not_enabled",
|
|
113
|
+
status: CONSTANTS.FAIL,
|
|
114
|
+
attr: "Verification Email (Code)",
|
|
115
|
+
value: "Verification Email (Code)",
|
|
116
|
+
},
|
|
117
|
+
]);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
const chai = require("chai");
|
|
2
|
+
const expect = chai.expect;
|
|
3
|
+
|
|
4
|
+
const checkErrorPageTemplate = require("../../analyzer/lib/error_page_template/checkErrorPageTemplate");
|
|
5
|
+
const CONSTANTS = require("../../analyzer/lib/constants");
|
|
6
|
+
|
|
7
|
+
describe("checkErrorPageTemplate", function () {
|
|
8
|
+
it("should return success when no error page template is provided", function (done) {
|
|
9
|
+
const options = {};
|
|
10
|
+
|
|
11
|
+
checkErrorPageTemplate(options).then((result) => {
|
|
12
|
+
expect(result.details).to.deep.include({
|
|
13
|
+
field: "liquidjs_no_templates_to_analyze",
|
|
14
|
+
status: CONSTANTS.SUCCESS,
|
|
15
|
+
value: "No custom error page templates found to analyze for XSS"
|
|
16
|
+
});
|
|
17
|
+
done();
|
|
18
|
+
}).catch(done);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("should return success when error page template is empty", function (done) {
|
|
22
|
+
const options = {
|
|
23
|
+
errorPageTemplate: ""
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
checkErrorPageTemplate(options).then((result) => {
|
|
27
|
+
expect(result.details).to.deep.include({
|
|
28
|
+
field: "liquidjs_no_templates_to_analyze",
|
|
29
|
+
status: CONSTANTS.SUCCESS,
|
|
30
|
+
value: "No custom error page templates found to analyze for XSS"
|
|
31
|
+
});
|
|
32
|
+
done();
|
|
33
|
+
}).catch(done);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should detect unescaped variable output", function (done) {
|
|
37
|
+
const options = {
|
|
38
|
+
errorPageTemplate: `
|
|
39
|
+
<html>
|
|
40
|
+
<body>
|
|
41
|
+
<h1>Error</h1>
|
|
42
|
+
<p>Hello {{ user.name }}</p>
|
|
43
|
+
<p>Error details: {{ error.description }}</p>
|
|
44
|
+
</body>
|
|
45
|
+
</html>
|
|
46
|
+
`
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
checkErrorPageTemplate(options).then((result) => {
|
|
50
|
+
const unescapedIssue = result.details.find(d => d.field === "liquidjs_unescaped_output");
|
|
51
|
+
expect(unescapedIssue).to.exist;
|
|
52
|
+
expect(unescapedIssue.status).to.equal(CONSTANTS.FAIL);
|
|
53
|
+
expect(unescapedIssue.value).to.be.a("string");
|
|
54
|
+
done();
|
|
55
|
+
}).catch(done);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("should not flag properly escaped variables as issues", function (done) {
|
|
59
|
+
const options = {
|
|
60
|
+
errorPageTemplate: `
|
|
61
|
+
<html>
|
|
62
|
+
<body>
|
|
63
|
+
<h1>Error</h1>
|
|
64
|
+
<p>Hello {{ user.name | escape }}</p>
|
|
65
|
+
<p>Error: {{ error.description | h }}</p>
|
|
66
|
+
</body>
|
|
67
|
+
</html>
|
|
68
|
+
`
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
checkErrorPageTemplate(options).then((result) => {
|
|
72
|
+
// Should not detect unescaped output since variables are properly escaped
|
|
73
|
+
const unescapedIssue = result.details.find(d =>
|
|
74
|
+
d.field === "liquidjs_unescaped_output" && d.status === CONSTANTS.FAIL
|
|
75
|
+
);
|
|
76
|
+
expect(unescapedIssue).to.not.exist;
|
|
77
|
+
|
|
78
|
+
// Should have a success entry for unescaped output
|
|
79
|
+
const successIssue = result.details.find(d =>
|
|
80
|
+
d.field === "liquidjs_unescaped_output" && d.status === CONSTANTS.SUCCESS
|
|
81
|
+
);
|
|
82
|
+
expect(successIssue).to.exist;
|
|
83
|
+
done();
|
|
84
|
+
}).catch(done);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should detect raw filter usage", function (done) {
|
|
88
|
+
const options = {
|
|
89
|
+
errorPageTemplate: `
|
|
90
|
+
<html>
|
|
91
|
+
<body>
|
|
92
|
+
<h1>Error</h1>
|
|
93
|
+
<div>{{ error.html_content | raw }}</div>
|
|
94
|
+
</body>
|
|
95
|
+
</html>
|
|
96
|
+
`
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
checkErrorPageTemplate(options).then((result) => {
|
|
100
|
+
const rawFilterIssue = result.details.find(d => d.field === "liquidjs_raw_filter_usage");
|
|
101
|
+
expect(rawFilterIssue).to.exist;
|
|
102
|
+
expect(rawFilterIssue.status).to.equal(CONSTANTS.FAIL);
|
|
103
|
+
expect(rawFilterIssue.value).to.be.a("string");
|
|
104
|
+
done();
|
|
105
|
+
}).catch(done);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("should detect unsafe filter usage", function (done) {
|
|
109
|
+
const options = {
|
|
110
|
+
errorPageTemplate: `
|
|
111
|
+
<html>
|
|
112
|
+
<body>
|
|
113
|
+
<p>{{ user.bio | safe }}</p>
|
|
114
|
+
<p>{{ content | unescaped }}</p>
|
|
115
|
+
</body>
|
|
116
|
+
</html>
|
|
117
|
+
`
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
checkErrorPageTemplate(options).then((result) => {
|
|
121
|
+
const rawFilterIssue = result.details.find(d => d.field === "liquidjs_raw_filter_usage");
|
|
122
|
+
expect(rawFilterIssue).to.exist;
|
|
123
|
+
expect(rawFilterIssue.status).to.equal(CONSTANTS.FAIL);
|
|
124
|
+
done();
|
|
125
|
+
}).catch(done);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("should handle templates with no liquid variables", function (done) {
|
|
129
|
+
const options = {
|
|
130
|
+
errorPageTemplate: `
|
|
131
|
+
<html>
|
|
132
|
+
<body>
|
|
133
|
+
<h1>Error Page</h1>
|
|
134
|
+
<p>Something went wrong. Please try again later.</p>
|
|
135
|
+
</body>
|
|
136
|
+
</html>
|
|
137
|
+
`
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
checkErrorPageTemplate(options).then((result) => {
|
|
141
|
+
// Should not find any unescaped output issues
|
|
142
|
+
const unescapedIssue = result.details.find(d =>
|
|
143
|
+
d.field === "liquidjs_unescaped_output" && d.status === CONSTANTS.FAIL
|
|
144
|
+
);
|
|
145
|
+
expect(unescapedIssue).to.not.exist;
|
|
146
|
+
|
|
147
|
+
// Should not find any raw filter issues
|
|
148
|
+
const rawIssue = result.details.find(d =>
|
|
149
|
+
d.field === "liquidjs_raw_filter_usage" && d.status === CONSTANTS.FAIL
|
|
150
|
+
);
|
|
151
|
+
expect(rawIssue).to.not.exist;
|
|
152
|
+
|
|
153
|
+
// Should have success entries
|
|
154
|
+
const successUnescaped = result.details.find(d =>
|
|
155
|
+
d.field === "liquidjs_unescaped_output" && d.status === CONSTANTS.SUCCESS
|
|
156
|
+
);
|
|
157
|
+
expect(successUnescaped).to.exist;
|
|
158
|
+
|
|
159
|
+
const successRaw = result.details.find(d =>
|
|
160
|
+
d.field === "liquidjs_raw_filter_usage" && d.status === CONSTANTS.SUCCESS
|
|
161
|
+
);
|
|
162
|
+
expect(successRaw).to.exist;
|
|
163
|
+
done();
|
|
164
|
+
}).catch(done);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("should handle complex templates with mixed safe and unsafe patterns", function (done) {
|
|
168
|
+
const options = {
|
|
169
|
+
errorPageTemplate: `
|
|
170
|
+
<html>
|
|
171
|
+
<head>
|
|
172
|
+
<title>Error - {{ error.code | escape }}</title>
|
|
173
|
+
</head>
|
|
174
|
+
<body>
|
|
175
|
+
<h1>{{ error.title }}</h1>
|
|
176
|
+
<p>Hello {{ user.name | escape }}, an error occurred.</p>
|
|
177
|
+
<div>{{ error.html_details | raw }}</div>
|
|
178
|
+
<p>Error ID: {{ error.id }}</p>
|
|
179
|
+
</body>
|
|
180
|
+
</html>
|
|
181
|
+
`
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
checkErrorPageTemplate(options).then((result) => {
|
|
185
|
+
// Should detect unescaped variables (error.title and error.id)
|
|
186
|
+
const unescapedIssue = result.details.find(d =>
|
|
187
|
+
d.field === "liquidjs_unescaped_output" && d.status === CONSTANTS.FAIL
|
|
188
|
+
);
|
|
189
|
+
expect(unescapedIssue).to.exist;
|
|
190
|
+
|
|
191
|
+
// Should detect raw filter usage
|
|
192
|
+
const rawIssue = result.details.find(d =>
|
|
193
|
+
d.field === "liquidjs_raw_filter_usage" && d.status === CONSTANTS.FAIL
|
|
194
|
+
);
|
|
195
|
+
expect(rawIssue).to.exist;
|
|
196
|
+
done();
|
|
197
|
+
}).catch(done);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("should handle templates with various safe filters", function (done) {
|
|
201
|
+
const options = {
|
|
202
|
+
errorPageTemplate: `
|
|
203
|
+
<html>
|
|
204
|
+
<body>
|
|
205
|
+
<p>{{ user.name | escape }}</p>
|
|
206
|
+
<p>{{ user.email | h }}</p>
|
|
207
|
+
<p>{{ user.bio | html_escape }}</p>
|
|
208
|
+
<p>{{ user.url | url_encode }}</p>
|
|
209
|
+
<p>{{ user.data | escape_once }}</p>
|
|
210
|
+
</body>
|
|
211
|
+
</html>
|
|
212
|
+
`
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
checkErrorPageTemplate(options).then((result) => {
|
|
216
|
+
// Should not detect unescaped output issues since all variables use safe filters
|
|
217
|
+
const unescapedIssue = result.details.find(d =>
|
|
218
|
+
d.field === "liquidjs_unescaped_output" && d.status === CONSTANTS.FAIL
|
|
219
|
+
);
|
|
220
|
+
expect(unescapedIssue).to.not.exist;
|
|
221
|
+
|
|
222
|
+
// Should have a success entry for unescaped output
|
|
223
|
+
const successIssue = result.details.find(d =>
|
|
224
|
+
d.field === "liquidjs_unescaped_output" && d.status === CONSTANTS.SUCCESS
|
|
225
|
+
);
|
|
226
|
+
expect(successIssue).to.exist;
|
|
227
|
+
done();
|
|
228
|
+
}).catch(done);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it("should detect variables with unsafe filter combinations", function (done) {
|
|
232
|
+
const options = {
|
|
233
|
+
errorPageTemplate: `
|
|
234
|
+
<html>
|
|
235
|
+
<body>
|
|
236
|
+
<p>{{ user.name | downcase }}</p>
|
|
237
|
+
<p>{{ user.bio | truncate: 100 }}</p>
|
|
238
|
+
<p>{{ user.title | upcase | strip }}</p>
|
|
239
|
+
</body>
|
|
240
|
+
</html>
|
|
241
|
+
`
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
checkErrorPageTemplate(options).then((result) => {
|
|
245
|
+
// Should detect unescaped output since these filters don't provide XSS protection
|
|
246
|
+
const unescapedIssue = result.details.find(d =>
|
|
247
|
+
d.field === "liquidjs_unescaped_output" && d.status === CONSTANTS.FAIL
|
|
248
|
+
);
|
|
249
|
+
expect(unescapedIssue).to.exist;
|
|
250
|
+
expect(unescapedIssue.status).to.equal(CONSTANTS.FAIL);
|
|
251
|
+
done();
|
|
252
|
+
}).catch(done);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it("should handle edge cases with whitespace and formatting", function (done) {
|
|
256
|
+
const options = {
|
|
257
|
+
errorPageTemplate: `
|
|
258
|
+
<html>
|
|
259
|
+
<body>
|
|
260
|
+
<p>{{user.name}}</p>
|
|
261
|
+
<p>{{ user.email }}</p>
|
|
262
|
+
<p>{{ user.bio }}</p>
|
|
263
|
+
<p>{{ user.data|escape }}</p>
|
|
264
|
+
<p>{{ user.info | escape }}</p>
|
|
265
|
+
</body>
|
|
266
|
+
</html>
|
|
267
|
+
`
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
checkErrorPageTemplate(options).then((result) => {
|
|
271
|
+
// Should detect unescaped variables regardless of whitespace
|
|
272
|
+
const unescapedIssue = result.details.find(d =>
|
|
273
|
+
d.field === "liquidjs_unescaped_output" && d.status === CONSTANTS.FAIL
|
|
274
|
+
);
|
|
275
|
+
expect(unescapedIssue).to.exist;
|
|
276
|
+
done();
|
|
277
|
+
}).catch(done);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it("should handle malformed liquid syntax gracefully", function (done) {
|
|
281
|
+
const options = {
|
|
282
|
+
errorPageTemplate: `
|
|
283
|
+
<html>
|
|
284
|
+
<body>
|
|
285
|
+
<p>{{ user.name</p>
|
|
286
|
+
<p>user.email }}</p>
|
|
287
|
+
<p>{{ user.bio | }}</p>
|
|
288
|
+
<p>{{ | escape }}</p>
|
|
289
|
+
</body>
|
|
290
|
+
</html>
|
|
291
|
+
`
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
checkErrorPageTemplate(options).then((result) => {
|
|
295
|
+
// Should not crash and should handle malformed syntax gracefully
|
|
296
|
+
expect(result).to.exist;
|
|
297
|
+
expect(result.details).to.be.an("array");
|
|
298
|
+
done();
|
|
299
|
+
}).catch(done);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it("should return proper structure with checkName and timestamp", function (done) {
|
|
303
|
+
const options = {
|
|
304
|
+
errorPageTemplate: "<p>{{ user.name }}</p>"
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
checkErrorPageTemplate(options).then((result) => {
|
|
308
|
+
expect(result).to.have.property("checkName", "checkErrorPageTemplate");
|
|
309
|
+
expect(result).to.have.property("timestamp");
|
|
310
|
+
expect(result).to.have.property("details");
|
|
311
|
+
expect(result.details).to.be.an("array");
|
|
312
|
+
done();
|
|
313
|
+
}).catch(done);
|
|
314
|
+
});
|
|
315
|
+
});
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const chai = require("chai");
|
|
2
|
+
const expect = chai.expect;
|
|
3
|
+
|
|
4
|
+
const checkEventStreams = require("../../analyzer/lib/event_streams/checkEventStreams");
|
|
5
|
+
const CONSTANTS = require("../../analyzer/lib/constants");
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
describe("checkEventStreams", function () {
|
|
9
|
+
it("should return fail when eventStreams is empty", function () {
|
|
10
|
+
const options = { eventStreams: [] };
|
|
11
|
+
|
|
12
|
+
checkEventStreams(options, (report) => {
|
|
13
|
+
expect(report).to.deep.equal([
|
|
14
|
+
{
|
|
15
|
+
field: "event_stream_not_configured",
|
|
16
|
+
status: CONSTANTS.FAIL,
|
|
17
|
+
},
|
|
18
|
+
]);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("should return empty when a event stream is enabled", function () {
|
|
23
|
+
const options = {
|
|
24
|
+
eventStreams: [
|
|
25
|
+
{
|
|
26
|
+
id: "lst_0001",
|
|
27
|
+
name: "Auth0 Eventstream",
|
|
28
|
+
destination: {
|
|
29
|
+
type: "webhook",
|
|
30
|
+
},
|
|
31
|
+
status: "enabled"
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
checkEventStreams(options, (report) => {
|
|
37
|
+
expect(report).to.deep.equal([]);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("should return fail when a event stream is disabled", function () {
|
|
42
|
+
const options = {
|
|
43
|
+
eventStreams: [
|
|
44
|
+
{
|
|
45
|
+
id: "lst_0001",
|
|
46
|
+
name: "Auth0 Eventstream",
|
|
47
|
+
destination: {
|
|
48
|
+
type: "webhook",
|
|
49
|
+
},
|
|
50
|
+
status: "disabled"
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
checkEventStreams(options, (report) => {
|
|
56
|
+
expect(report).to.deep.equal([
|
|
57
|
+
{
|
|
58
|
+
field: "event_stream_disabled",
|
|
59
|
+
name: "Auth0 Eventstream",
|
|
60
|
+
type: "http",
|
|
61
|
+
stream_status: "disabled",
|
|
62
|
+
status: CONSTANTS.FAIL,
|
|
63
|
+
},
|
|
64
|
+
]);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should return an empty report if errorCode "insufficient_scope" is present', function () {
|
|
69
|
+
const options = {
|
|
70
|
+
eventStreams: [
|
|
71
|
+
{
|
|
72
|
+
id: "lst_0001",
|
|
73
|
+
name: "Auth0 Eventstream",
|
|
74
|
+
errorCode: "insufficient_scope"
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
checkEventStreams(options, (report) => {
|
|
80
|
+
expect(report).to.deep.equal([]); // The report should be empty for insufficient scope
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("should handle multiple log streams with mixed statuses", function () {
|
|
85
|
+
const options = {
|
|
86
|
+
eventStreams: [
|
|
87
|
+
{
|
|
88
|
+
id: "lst_0001",
|
|
89
|
+
name: "Auth0 Eventstream",
|
|
90
|
+
destination: {
|
|
91
|
+
type: "webhook",
|
|
92
|
+
},
|
|
93
|
+
status: "enabled"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: "lst_0000000000014672",
|
|
97
|
+
name: "Another Eventstream",
|
|
98
|
+
destination: {
|
|
99
|
+
type: "aws",
|
|
100
|
+
},
|
|
101
|
+
status: "disabled"
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
checkEventStreams(options, (report) => {
|
|
107
|
+
expect(report).to.deep.equal([
|
|
108
|
+
{
|
|
109
|
+
field: "event_stream_disabled",
|
|
110
|
+
name: "Another Eventstream",
|
|
111
|
+
type: "aws",
|
|
112
|
+
stream_status: "disabled",
|
|
113
|
+
status: CONSTANTS.FAIL,
|
|
114
|
+
},
|
|
115
|
+
]);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
const chai = require("chai");
|
|
2
|
+
const expect = chai.expect;
|
|
3
|
+
|
|
4
|
+
const checkHooks = require("../../analyzer/lib/hooks/checkHooks");
|
|
5
|
+
const CONSTANTS = require("../../analyzer/lib/constants");
|
|
6
|
+
|
|
7
|
+
describe("checkHooks", function () {
|
|
8
|
+
it("should return success when no hooks are provided", function () {
|
|
9
|
+
const options = {};
|
|
10
|
+
|
|
11
|
+
checkHooks(options, (report) => {
|
|
12
|
+
expect(report).to.deep.equal([
|
|
13
|
+
{
|
|
14
|
+
field: "no_enabled_hooks",
|
|
15
|
+
status: CONSTANTS.SUCCESS,
|
|
16
|
+
},
|
|
17
|
+
]);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("should return fail for an enabled hook", function () {
|
|
22
|
+
const options = {
|
|
23
|
+
hooks: [
|
|
24
|
+
{
|
|
25
|
+
id: "test",
|
|
26
|
+
name: "test",
|
|
27
|
+
script: "",
|
|
28
|
+
dependencies: {},
|
|
29
|
+
enabled: true,
|
|
30
|
+
triggerId: "post-user-registration",
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
checkHooks(options, (report) => {
|
|
36
|
+
expect(report).to.deep.equal([
|
|
37
|
+
{
|
|
38
|
+
name: "test",
|
|
39
|
+
value: "post-user-registration",
|
|
40
|
+
field: "enabled_hooks",
|
|
41
|
+
status: CONSTANTS.FAIL,
|
|
42
|
+
},
|
|
43
|
+
]);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should return success for a disabled hook", function () {
|
|
48
|
+
const options = {
|
|
49
|
+
hooks: [
|
|
50
|
+
{
|
|
51
|
+
id: "test",
|
|
52
|
+
name: "test",
|
|
53
|
+
script: "",
|
|
54
|
+
dependencies: {},
|
|
55
|
+
enabled: false,
|
|
56
|
+
triggerId: "post-user-registration",
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
checkHooks(options, (report) => {
|
|
62
|
+
expect(report).to.deep.equal([
|
|
63
|
+
{
|
|
64
|
+
name: "test",
|
|
65
|
+
value: "post-user-registration",
|
|
66
|
+
field: "enabled_hooks",
|
|
67
|
+
status: CONSTANTS.SUCCESS,
|
|
68
|
+
},
|
|
69
|
+
]);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("should handle multiple hooks with mixed enabled/disabled states", function () {
|
|
74
|
+
const options = {
|
|
75
|
+
hooks: [
|
|
76
|
+
{
|
|
77
|
+
id: "test1",
|
|
78
|
+
name: "test1",
|
|
79
|
+
script: "",
|
|
80
|
+
dependencies: {},
|
|
81
|
+
enabled: true,
|
|
82
|
+
triggerId: "post-user-registration",
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: "test2",
|
|
86
|
+
name: "test2",
|
|
87
|
+
script: "",
|
|
88
|
+
dependencies: {},
|
|
89
|
+
enabled: false,
|
|
90
|
+
triggerId: "pre-user-registration",
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
checkHooks(options, (report) => {
|
|
96
|
+
expect(report).to.deep.equal([
|
|
97
|
+
{
|
|
98
|
+
name: "test1",
|
|
99
|
+
value: "post-user-registration",
|
|
100
|
+
field: "enabled_hooks",
|
|
101
|
+
status: CONSTANTS.FAIL,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: "test2",
|
|
105
|
+
value: "pre-user-registration",
|
|
106
|
+
field: "enabled_hooks",
|
|
107
|
+
status: CONSTANTS.SUCCESS,
|
|
108
|
+
},
|
|
109
|
+
]);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
});
|