@govtechsg/oobee 0.10.20
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/.dockerignore +22 -0
- package/.github/pull_request_template.md +11 -0
- package/.github/workflows/docker-test.yml +54 -0
- package/.github/workflows/image.yml +107 -0
- package/.github/workflows/publish.yml +18 -0
- package/.idea/modules.xml +8 -0
- package/.idea/purple-a11y.iml +9 -0
- package/.idea/vcs.xml +6 -0
- package/.prettierrc.json +12 -0
- package/.vscode/extensions.json +5 -0
- package/.vscode/settings.json +10 -0
- package/CODE_OF_CONDUCT.md +128 -0
- package/DETAILS.md +163 -0
- package/Dockerfile +60 -0
- package/INSTALLATION.md +146 -0
- package/INTEGRATION.md +785 -0
- package/LICENSE +22 -0
- package/README.md +587 -0
- package/SECURITY.md +5 -0
- package/__mocks__/mock-report.html +1431 -0
- package/__mocks__/mockFunctions.ts +32 -0
- package/__mocks__/mockIssues.ts +64 -0
- package/__mocks__/mock_all_issues/000000001.json +64 -0
- package/__mocks__/mock_all_issues/000000002.json +53 -0
- package/__mocks__/mock_all_issues/fake-file.txt +0 -0
- package/__tests__/logs.test.ts +25 -0
- package/__tests__/mergeAxeResults.test.ts +278 -0
- package/__tests__/utils.test.ts +118 -0
- package/a11y-scan-results.zip +0 -0
- package/eslint.config.js +53 -0
- package/exclusions.txt +2 -0
- package/gitlab-pipeline-template.yml +54 -0
- package/jest.config.js +1 -0
- package/package.json +96 -0
- package/scripts/copyFiles.js +44 -0
- package/scripts/install_oobee_dependencies.cmd +13 -0
- package/scripts/install_oobee_dependencies.command +101 -0
- package/scripts/install_oobee_dependencies.ps1 +110 -0
- package/scripts/oobee_shell.cmd +13 -0
- package/scripts/oobee_shell.command +11 -0
- package/scripts/oobee_shell.sh +55 -0
- package/scripts/oobee_shell_ps.ps1 +54 -0
- package/src/cli.ts +401 -0
- package/src/combine.ts +240 -0
- package/src/constants/__tests__/common.test.ts +44 -0
- package/src/constants/cliFunctions.ts +305 -0
- package/src/constants/common.ts +1840 -0
- package/src/constants/constants.ts +443 -0
- package/src/constants/errorMeta.json +319 -0
- package/src/constants/itemTypeDescription.ts +11 -0
- package/src/constants/oobeeAi.ts +141 -0
- package/src/constants/questions.ts +181 -0
- package/src/constants/sampleData.ts +187 -0
- package/src/crawlers/__tests__/commonCrawlerFunc.test.ts +51 -0
- package/src/crawlers/commonCrawlerFunc.ts +656 -0
- package/src/crawlers/crawlDomain.ts +877 -0
- package/src/crawlers/crawlIntelligentSitemap.ts +156 -0
- package/src/crawlers/crawlLocalFile.ts +193 -0
- package/src/crawlers/crawlSitemap.ts +356 -0
- package/src/crawlers/custom/extractAndGradeText.ts +57 -0
- package/src/crawlers/custom/flagUnlabelledClickableElements.ts +964 -0
- package/src/crawlers/custom/utils.ts +486 -0
- package/src/crawlers/customAxeFunctions.ts +82 -0
- package/src/crawlers/pdfScanFunc.ts +468 -0
- package/src/crawlers/runCustom.ts +117 -0
- package/src/index.ts +173 -0
- package/src/logs.ts +66 -0
- package/src/mergeAxeResults.ts +964 -0
- package/src/npmIndex.ts +284 -0
- package/src/screenshotFunc/htmlScreenshotFunc.ts +411 -0
- package/src/screenshotFunc/pdfScreenshotFunc.ts +762 -0
- package/src/static/ejs/partials/components/categorySelector.ejs +4 -0
- package/src/static/ejs/partials/components/categorySelectorDropdown.ejs +57 -0
- package/src/static/ejs/partials/components/pagesScannedModal.ejs +70 -0
- package/src/static/ejs/partials/components/reportSearch.ejs +47 -0
- package/src/static/ejs/partials/components/ruleOffcanvas.ejs +105 -0
- package/src/static/ejs/partials/components/scanAbout.ejs +263 -0
- package/src/static/ejs/partials/components/screenshotLightbox.ejs +13 -0
- package/src/static/ejs/partials/components/summaryScanAbout.ejs +141 -0
- package/src/static/ejs/partials/components/summaryScanResults.ejs +16 -0
- package/src/static/ejs/partials/components/summaryTable.ejs +20 -0
- package/src/static/ejs/partials/components/summaryWcagCompliance.ejs +94 -0
- package/src/static/ejs/partials/components/topFive.ejs +6 -0
- package/src/static/ejs/partials/components/wcagCompliance.ejs +70 -0
- package/src/static/ejs/partials/footer.ejs +21 -0
- package/src/static/ejs/partials/header.ejs +230 -0
- package/src/static/ejs/partials/main.ejs +40 -0
- package/src/static/ejs/partials/scripts/bootstrap.ejs +8 -0
- package/src/static/ejs/partials/scripts/categorySelectorDropdownScript.ejs +190 -0
- package/src/static/ejs/partials/scripts/categorySummary.ejs +141 -0
- package/src/static/ejs/partials/scripts/highlightjs.ejs +335 -0
- package/src/static/ejs/partials/scripts/popper.ejs +7 -0
- package/src/static/ejs/partials/scripts/reportSearch.ejs +248 -0
- package/src/static/ejs/partials/scripts/ruleOffcanvas.ejs +801 -0
- package/src/static/ejs/partials/scripts/screenshotLightbox.ejs +71 -0
- package/src/static/ejs/partials/scripts/summaryScanResults.ejs +14 -0
- package/src/static/ejs/partials/scripts/summaryTable.ejs +78 -0
- package/src/static/ejs/partials/scripts/utils.ejs +441 -0
- package/src/static/ejs/partials/styles/bootstrap.ejs +12375 -0
- package/src/static/ejs/partials/styles/highlightjs.ejs +54 -0
- package/src/static/ejs/partials/styles/styles.ejs +1843 -0
- package/src/static/ejs/partials/styles/summaryBootstrap.ejs +12458 -0
- package/src/static/ejs/partials/summaryHeader.ejs +70 -0
- package/src/static/ejs/partials/summaryMain.ejs +75 -0
- package/src/static/ejs/report.ejs +420 -0
- package/src/static/ejs/summary.ejs +47 -0
- package/src/static/mustache/.prettierrc +4 -0
- package/src/static/mustache/Attention Deficit.mustache +11 -0
- package/src/static/mustache/Blind.mustache +11 -0
- package/src/static/mustache/Cognitive.mustache +7 -0
- package/src/static/mustache/Colorblindness.mustache +20 -0
- package/src/static/mustache/Deaf.mustache +12 -0
- package/src/static/mustache/Deafblind.mustache +7 -0
- package/src/static/mustache/Dyslexia.mustache +14 -0
- package/src/static/mustache/Low Vision.mustache +7 -0
- package/src/static/mustache/Mobility.mustache +15 -0
- package/src/static/mustache/Sighted Keyboard Users.mustache +42 -0
- package/src/static/mustache/report.mustache +1709 -0
- package/src/types/print-message.d.ts +28 -0
- package/src/types/types.ts +46 -0
- package/src/types/xpath-to-css.d.ts +3 -0
- package/src/utils.ts +332 -0
- package/tsconfig.json +15 -0
@@ -0,0 +1,443 @@
|
|
1
|
+
import path from 'path';
|
2
|
+
import { fileURLToPath } from 'url';
|
3
|
+
import fs from 'fs-extra';
|
4
|
+
import { globSync } from 'glob';
|
5
|
+
import which from 'which';
|
6
|
+
import os from 'os';
|
7
|
+
import { spawnSync, execSync } from 'child_process';
|
8
|
+
import { chromium } from 'playwright';
|
9
|
+
import { silentLogger } from '../logs.js';
|
10
|
+
|
11
|
+
const filename = fileURLToPath(import.meta.url);
|
12
|
+
const dirname = path.dirname(filename);
|
13
|
+
|
14
|
+
const maxRequestsPerCrawl = 100;
|
15
|
+
|
16
|
+
export const blackListedFileExtensions = [
|
17
|
+
'css',
|
18
|
+
'js',
|
19
|
+
'txt',
|
20
|
+
'mp3',
|
21
|
+
'mp4',
|
22
|
+
'jpg',
|
23
|
+
'jpeg',
|
24
|
+
'png',
|
25
|
+
'svg',
|
26
|
+
'gif',
|
27
|
+
'woff',
|
28
|
+
'zip',
|
29
|
+
'webp',
|
30
|
+
'json',
|
31
|
+
];
|
32
|
+
|
33
|
+
export const getIntermediateScreenshotsPath = (datasetsPath: string): string =>
|
34
|
+
`${datasetsPath}/screenshots`;
|
35
|
+
export const destinationPath = (storagePath: string): string => `${storagePath}/screenshots`;
|
36
|
+
|
37
|
+
/** Get the path to Default Profile in the Chrome Data Directory
|
38
|
+
* as per https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md
|
39
|
+
* @returns path to Default Profile in the Chrome Data Directory
|
40
|
+
*/
|
41
|
+
export const getDefaultChromeDataDir = (): string => {
|
42
|
+
try {
|
43
|
+
let defaultChromeDataDir = null;
|
44
|
+
if (os.platform() === 'win32') {
|
45
|
+
defaultChromeDataDir = path.join(
|
46
|
+
os.homedir(),
|
47
|
+
'AppData',
|
48
|
+
'Local',
|
49
|
+
'Google',
|
50
|
+
'Chrome',
|
51
|
+
'User Data',
|
52
|
+
);
|
53
|
+
} else if (os.platform() === 'darwin') {
|
54
|
+
defaultChromeDataDir = path.join(
|
55
|
+
os.homedir(),
|
56
|
+
'Library',
|
57
|
+
'Application Support',
|
58
|
+
'Google',
|
59
|
+
'Chrome',
|
60
|
+
);
|
61
|
+
}
|
62
|
+
|
63
|
+
if (defaultChromeDataDir && fs.existsSync(defaultChromeDataDir)) {
|
64
|
+
return defaultChromeDataDir;
|
65
|
+
}
|
66
|
+
return null;
|
67
|
+
} catch (error) {
|
68
|
+
console.error(`Error in getDefaultChromeDataDir(): ${error}`);
|
69
|
+
}
|
70
|
+
};
|
71
|
+
|
72
|
+
/**
|
73
|
+
* Get the path to Default Profile in the Edge Data Directory
|
74
|
+
* @returns path to Default Profile in the Edge Data Directory
|
75
|
+
*/
|
76
|
+
export const getDefaultEdgeDataDir = (): string => {
|
77
|
+
try {
|
78
|
+
let defaultEdgeDataDir = null;
|
79
|
+
if (os.platform() === 'win32') {
|
80
|
+
defaultEdgeDataDir = path.join(
|
81
|
+
os.homedir(),
|
82
|
+
'AppData',
|
83
|
+
'Local',
|
84
|
+
'Microsoft',
|
85
|
+
'Edge',
|
86
|
+
'User Data',
|
87
|
+
);
|
88
|
+
} else if (os.platform() === 'darwin') {
|
89
|
+
defaultEdgeDataDir = path.join(
|
90
|
+
os.homedir(),
|
91
|
+
'Library',
|
92
|
+
'Application Support',
|
93
|
+
'Microsoft Edge',
|
94
|
+
);
|
95
|
+
}
|
96
|
+
|
97
|
+
if (defaultEdgeDataDir && fs.existsSync(defaultEdgeDataDir)) {
|
98
|
+
return defaultEdgeDataDir;
|
99
|
+
}
|
100
|
+
return null;
|
101
|
+
} catch (error) {
|
102
|
+
console.error(`Error in getDefaultEdgeDataDir(): ${error}`);
|
103
|
+
}
|
104
|
+
};
|
105
|
+
|
106
|
+
export const getDefaultChromiumDataDir = () => {
|
107
|
+
try {
|
108
|
+
let defaultChromiumDataDir = null;
|
109
|
+
|
110
|
+
if (os.platform() === 'win32') {
|
111
|
+
defaultChromiumDataDir = path.join(os.homedir(), 'AppData', 'Local', 'Chromium', 'User Data');
|
112
|
+
} else if (os.platform() === 'darwin') {
|
113
|
+
defaultChromiumDataDir = path.join(
|
114
|
+
os.homedir(),
|
115
|
+
'Library',
|
116
|
+
'Application Support',
|
117
|
+
'Chromium',
|
118
|
+
);
|
119
|
+
} else {
|
120
|
+
defaultChromiumDataDir = path.join(process.cwd(), 'Chromium Support');
|
121
|
+
|
122
|
+
try {
|
123
|
+
fs.mkdirSync(defaultChromiumDataDir, { recursive: true }); // Use { recursive: true } to create parent directories if they don't exist
|
124
|
+
} catch {
|
125
|
+
defaultChromiumDataDir = '/tmp';
|
126
|
+
}
|
127
|
+
|
128
|
+
silentLogger.warn(`Using Chromium support directory at ${defaultChromiumDataDir}`);
|
129
|
+
}
|
130
|
+
|
131
|
+
if (defaultChromiumDataDir && fs.existsSync(defaultChromiumDataDir)) {
|
132
|
+
return defaultChromiumDataDir;
|
133
|
+
}
|
134
|
+
return null;
|
135
|
+
} catch (error) {
|
136
|
+
silentLogger.error(`Error in getDefaultChromiumDataDir(): ${error}`);
|
137
|
+
}
|
138
|
+
};
|
139
|
+
|
140
|
+
export const removeQuarantineFlag = function (searchPath: string) {
|
141
|
+
if (os.platform() === 'darwin') {
|
142
|
+
const execPaths = globSync(searchPath, { absolute: true, nodir: true });
|
143
|
+
if (execPaths.length > 0) {
|
144
|
+
execPaths.forEach(filePath => spawnSync('xattr', ['-d', 'com.apple.quarantine', filePath]));
|
145
|
+
}
|
146
|
+
}
|
147
|
+
};
|
148
|
+
|
149
|
+
export const getExecutablePath = function (dir: string, file: string): string {
|
150
|
+
let execPaths = globSync(`${dir}/${file}`, { absolute: true, nodir: true });
|
151
|
+
|
152
|
+
if (execPaths.length === 0) {
|
153
|
+
const execInPATH = which.sync(file, { nothrow: true });
|
154
|
+
|
155
|
+
if (execInPATH) {
|
156
|
+
return fs.realpathSync(execInPATH);
|
157
|
+
}
|
158
|
+
const splitPath =
|
159
|
+
os.platform() === 'win32' ? process.env.PATH.split(';') : process.env.PATH.split(':');
|
160
|
+
|
161
|
+
for (const path in splitPath) {
|
162
|
+
execPaths = globSync(`${path}/${file}`, { absolute: true, nodir: true });
|
163
|
+
if (execPaths.length !== 0) return fs.realpathSync(execPaths[0]);
|
164
|
+
}
|
165
|
+
return null;
|
166
|
+
}
|
167
|
+
removeQuarantineFlag(execPaths[0]);
|
168
|
+
return execPaths[0];
|
169
|
+
};
|
170
|
+
|
171
|
+
/**
|
172
|
+
* Matches the pattern user:password@domain.com
|
173
|
+
*/
|
174
|
+
export const basicAuthRegex = /^.*\/\/.*:.*@.*$/i;
|
175
|
+
|
176
|
+
// for crawlers
|
177
|
+
export const axeScript = path.join(dirname, '../../node_modules/axe-core/axe.min.js');
|
178
|
+
export class UrlsCrawled {
|
179
|
+
toScan: string[] = [];
|
180
|
+
scanned: { url: string; actualUrl: string; pageTitle: string }[] = [];
|
181
|
+
invalid: string[] = [];
|
182
|
+
scannedRedirects: { fromUrl: string; toUrl: string }[] = [];
|
183
|
+
notScannedRedirects: { fromUrl: string; toUrl: string }[] = [];
|
184
|
+
outOfDomain: string[] = [];
|
185
|
+
blacklisted: string[] = [];
|
186
|
+
error: { url: string }[] = [];
|
187
|
+
exceededRequests: string[] = [];
|
188
|
+
forbidden: string[] = [];
|
189
|
+
userExcluded: string[] = [];
|
190
|
+
everything: string[] = [];
|
191
|
+
|
192
|
+
constructor(urlsCrawled?: Partial<UrlsCrawled>) {
|
193
|
+
if (urlsCrawled) {
|
194
|
+
Object.assign(this, urlsCrawled);
|
195
|
+
}
|
196
|
+
}
|
197
|
+
}
|
198
|
+
|
199
|
+
const urlsCrawledObj = new UrlsCrawled();
|
200
|
+
|
201
|
+
/* eslint-disable no-unused-vars */
|
202
|
+
export enum ScannerTypes {
|
203
|
+
SITEMAP = 'Sitemap',
|
204
|
+
WEBSITE = 'Website',
|
205
|
+
CUSTOM = 'Custom',
|
206
|
+
INTELLIGENT = 'Intelligent',
|
207
|
+
LOCALFILE = 'LocalFile',
|
208
|
+
}
|
209
|
+
/* eslint-enable no-unused-vars */
|
210
|
+
|
211
|
+
export const guiInfoStatusTypes = {
|
212
|
+
SCANNED: 'scanned',
|
213
|
+
SKIPPED: 'skipped',
|
214
|
+
COMPLETED: 'completed',
|
215
|
+
ERROR: 'error',
|
216
|
+
DUPLICATE: 'duplicate',
|
217
|
+
};
|
218
|
+
|
219
|
+
let launchOptionsArgs = [];
|
220
|
+
|
221
|
+
// Check if running in docker container
|
222
|
+
if (fs.existsSync('/.dockerenv')) {
|
223
|
+
launchOptionsArgs = ['--disable-gpu', '--no-sandbox', '--disable-dev-shm-usage'];
|
224
|
+
}
|
225
|
+
|
226
|
+
export const getProxy = (): { type: string; url: string } | null => {
|
227
|
+
if (os.platform() === 'win32') {
|
228
|
+
let internetSettings: string[];
|
229
|
+
try {
|
230
|
+
internetSettings = execSync(
|
231
|
+
'Get-ItemProperty -Path "Registry::HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"',
|
232
|
+
{ shell: 'powershell.exe' },
|
233
|
+
)
|
234
|
+
.toString()
|
235
|
+
.split('\n');
|
236
|
+
} catch (e) {
|
237
|
+
console.log(e.toString());
|
238
|
+
silentLogger.error(e.toString());
|
239
|
+
}
|
240
|
+
|
241
|
+
const getSettingValue = (settingName: string) =>
|
242
|
+
internetSettings
|
243
|
+
.find(s => s.startsWith(settingName))
|
244
|
+
// split only once at with ':' as the delimiter
|
245
|
+
?.split(/:(.*)/s)[1]
|
246
|
+
?.trim();
|
247
|
+
|
248
|
+
if (getSettingValue('AutoConfigURL')) {
|
249
|
+
return { type: 'autoConfig', url: getSettingValue('AutoConfigURL') };
|
250
|
+
}
|
251
|
+
if (getSettingValue('ProxyEnable') === '1') {
|
252
|
+
return { type: 'manualProxy', url: getSettingValue('ProxyServer') };
|
253
|
+
}
|
254
|
+
return null;
|
255
|
+
}
|
256
|
+
// develop for mac
|
257
|
+
return null;
|
258
|
+
};
|
259
|
+
|
260
|
+
export const proxy = getProxy();
|
261
|
+
|
262
|
+
if (proxy && proxy.type === 'autoConfig') {
|
263
|
+
launchOptionsArgs.push(`--proxy-pac-url=${proxy.url}`);
|
264
|
+
} else if (proxy && proxy.type === 'manualProxy') {
|
265
|
+
launchOptionsArgs.push(`--proxy-server=${proxy.url}`);
|
266
|
+
}
|
267
|
+
|
268
|
+
export const impactOrder = {
|
269
|
+
minor: 0,
|
270
|
+
moderate: 1,
|
271
|
+
serious: 2,
|
272
|
+
critical: 3,
|
273
|
+
};
|
274
|
+
|
275
|
+
export const formDataFields = {
|
276
|
+
formUrl: `https://docs.google.com/forms/d/e/1FAIpQLSem5C8fyNs5TiU5Vv2Y63-SH7CHN86f-LEPxeN_1u_ldUbgUA/formResponse`, // prod
|
277
|
+
entryUrlField: 'entry.1562345227',
|
278
|
+
redirectUrlField: 'entry.473072563',
|
279
|
+
scanTypeField: 'entry.1148680657',
|
280
|
+
emailField: 'entry.52161304',
|
281
|
+
nameField: 'entry.1787318910',
|
282
|
+
resultsField: 'entry.904051439',
|
283
|
+
numberOfPagesScannedField: 'entry.238043773',
|
284
|
+
additionalPageDataField: 'entry.2090887881',
|
285
|
+
metadataField: 'entry.1027769131',
|
286
|
+
};
|
287
|
+
|
288
|
+
export const sitemapPaths = [
|
289
|
+
'/sitemap.xml',
|
290
|
+
'/sitemap/sitemap.xml',
|
291
|
+
'/sitemap-index.xml',
|
292
|
+
'/sitemap_index.xml',
|
293
|
+
'/sitemapindex.xml',
|
294
|
+
'/sitemap/index.xml',
|
295
|
+
'/sitemap1.xml',
|
296
|
+
'/sitemap/',
|
297
|
+
'/post-sitemap',
|
298
|
+
'/page-sitemap',
|
299
|
+
'/sitemap.txt',
|
300
|
+
'/sitemap.php',
|
301
|
+
'/sitemap.xml.bz2',
|
302
|
+
'/sitemap.xml.xz',
|
303
|
+
'/sitemap_index.xml.bz2',
|
304
|
+
'/sitemap_index.xml.xz',
|
305
|
+
];
|
306
|
+
|
307
|
+
const wcagLinks = {
|
308
|
+
'WCAG 1.1.1': 'https://www.w3.org/TR/WCAG21/#non-text-content',
|
309
|
+
'WCAG 1.2.2': 'https://www.w3.org/TR/WCAG21/#captions-prerecorded',
|
310
|
+
'WCAG 1.3.1': 'https://www.w3.org/TR/WCAG21/#info-and-relationships',
|
311
|
+
// 'WCAG 1.3.4': 'https://www.w3.org/TR/WCAG21/#orientation', - TODO: review for veraPDF
|
312
|
+
'WCAG 1.3.5': 'https://www.w3.org/TR/WCAG21/#use-of-color',
|
313
|
+
'WCAG 1.4.1': 'https://www.w3.org/TR/WCAG21/#use-of-color',
|
314
|
+
'WCAG 1.4.2': 'https://www.w3.org/TR/WCAG21/#audio-control',
|
315
|
+
'WCAG 1.4.3': 'https://www.w3.org/TR/WCAG21/#contrast-minimum',
|
316
|
+
'WCAG 1.4.4': 'https://www.w3.org/TR/WCAG21/#resize-text',
|
317
|
+
'WCAG 1.4.6': 'https://www.w3.org/TR/WCAG21/#contrast-enhanced',
|
318
|
+
// 'WCAG 1.4.10': 'https://www.w3.org/TR/WCAG21/#reflow', - TODO: review for veraPDF
|
319
|
+
'WCAG 1.4.12': 'https://www.w3.org/TR/WCAG21/#text-spacing',
|
320
|
+
'WCAG 2.1.1': 'https://www.w3.org/TR/WCAG21/#pause-stop-hide',
|
321
|
+
'WCAG 2.2.1': 'https://www.w3.org/TR/WCAG21/#timing-adjustable',
|
322
|
+
'WCAG 2.2.2': 'https://www.w3.org/TR/WCAG21/#pause-stop-hide',
|
323
|
+
'WCAG 2.2.4': 'https://www.w3.org/TR/WCAG21/#interruptions',
|
324
|
+
'WCAG 2.4.1': 'https://www.w3.org/TR/WCAG21/#bypass-blocks',
|
325
|
+
'WCAG 2.4.2': 'https://www.w3.org/TR/WCAG21/#page-titled',
|
326
|
+
'WCAG 2.4.3': 'https://www.w3.org/TR/WCAG21/#focus-order',
|
327
|
+
'WCAG 2.4.4': 'https://www.w3.org/TR/WCAG21/#link-purpose-in-context',
|
328
|
+
'WCAG 2.4.9': 'https://www.w3.org/TR/WCAG21/#link-purpose-link-only',
|
329
|
+
'WCAG 2.5.8': 'https://www.w3.org/TR/WCAG22/#target-size-minimum',
|
330
|
+
'WCAG 3.1.1': 'https://www.w3.org/TR/WCAG21/#language-of-page',
|
331
|
+
'WCAG 3.1.2': 'https://www.w3.org/TR/WCAG21/#labels-or-instructions',
|
332
|
+
'WCAG 3.2.5': 'https://www.w3.org/TR/WCAG21/#change-on-request',
|
333
|
+
'WCAG 4.1.2': 'https://www.w3.org/TR/WCAG21/#name-role-value',
|
334
|
+
};
|
335
|
+
|
336
|
+
const urlCheckStatuses = {
|
337
|
+
success: { code: 0 },
|
338
|
+
invalidUrl: { code: 11, message: 'Invalid URL or URL is not using http or https.' },
|
339
|
+
cannotBeResolved: {
|
340
|
+
code: 12,
|
341
|
+
message:
|
342
|
+
'Provided URL cannot be accessed. Please verify your internet connectivity and the correctness of the domain.',
|
343
|
+
},
|
344
|
+
errorStatusReceived: {
|
345
|
+
// unused for now
|
346
|
+
code: 13,
|
347
|
+
message: 'Provided URL cannot be accessed. Server responded with code ', // append it with the response code received,
|
348
|
+
},
|
349
|
+
systemError: {
|
350
|
+
code: 14,
|
351
|
+
message: 'Something went wrong when verifying the URL. Please try again later.',
|
352
|
+
},
|
353
|
+
notASitemap: { code: 15, message: 'Provided URL is not a sitemap.' },
|
354
|
+
unauthorised: { code: 16, message: 'Provided URL needs basic authorisation.' },
|
355
|
+
browserError: {
|
356
|
+
code: 17,
|
357
|
+
message:
|
358
|
+
'No browser available to run scans. Please ensure you have Chrome or Edge (for Windows only) installed.',
|
359
|
+
},
|
360
|
+
axiosTimeout: { code: 18, message: 'Axios timeout exceeded. Falling back on browser checks.' },
|
361
|
+
notALocalFile: { code: 19, message: 'Provided filepath is not a local html or sitemap file.' },
|
362
|
+
};
|
363
|
+
|
364
|
+
/* eslint-disable no-unused-vars */
|
365
|
+
export enum BrowserTypes {
|
366
|
+
CHROMIUM = 'chromium',
|
367
|
+
CHROME = 'chrome',
|
368
|
+
EDGE = 'msedge',
|
369
|
+
}
|
370
|
+
/* eslint-enable no-unused-vars */
|
371
|
+
|
372
|
+
const xmlSitemapTypes = {
|
373
|
+
xml: 0,
|
374
|
+
xmlIndex: 1,
|
375
|
+
rss: 2,
|
376
|
+
atom: 3,
|
377
|
+
unknown: 4,
|
378
|
+
};
|
379
|
+
|
380
|
+
const forbiddenCharactersInDirPath = ['<', '>', ':', '"', '\\', '/', '|', '?', '*'];
|
381
|
+
|
382
|
+
const reserveFileNameKeywords = [
|
383
|
+
'CON',
|
384
|
+
'PRN',
|
385
|
+
'AUX',
|
386
|
+
'NUL',
|
387
|
+
'COM1',
|
388
|
+
'COM2',
|
389
|
+
'COM3',
|
390
|
+
'COM4',
|
391
|
+
'COM5',
|
392
|
+
'COM6',
|
393
|
+
'COM7',
|
394
|
+
'COM8',
|
395
|
+
'COM9',
|
396
|
+
'LPT1',
|
397
|
+
'LPT2',
|
398
|
+
'LPT3',
|
399
|
+
'LPT4',
|
400
|
+
'LPT5',
|
401
|
+
'LPT6',
|
402
|
+
'LPT7',
|
403
|
+
'LPT8',
|
404
|
+
'LPT9',
|
405
|
+
];
|
406
|
+
|
407
|
+
export default {
|
408
|
+
cliZipFileName: 'oobee-scan-results.zip',
|
409
|
+
exportDirectory: `${process.cwd()}`,
|
410
|
+
maxRequestsPerCrawl,
|
411
|
+
maxConcurrency: 25,
|
412
|
+
urlsCrawledObj,
|
413
|
+
impactOrder,
|
414
|
+
launchOptionsArgs,
|
415
|
+
xmlSitemapTypes,
|
416
|
+
urlCheckStatuses,
|
417
|
+
launcher: chromium,
|
418
|
+
pdfScanResultFileName: 'pdf-scan-results.json',
|
419
|
+
forbiddenCharactersInDirPath,
|
420
|
+
reserveFileNameKeywords,
|
421
|
+
wcagLinks,
|
422
|
+
robotsTxtUrls: null,
|
423
|
+
};
|
424
|
+
|
425
|
+
export const rootPath = dirname;
|
426
|
+
export const wcagWebPage = 'https://www.w3.org/TR/WCAG21/';
|
427
|
+
const latestAxeVersion = '4.9';
|
428
|
+
export const axeVersion = latestAxeVersion;
|
429
|
+
export const axeWebPage = `https://dequeuniversity.com/rules/axe/${latestAxeVersion}/`;
|
430
|
+
|
431
|
+
export const saflyIconSelector = `#__safly_icon`;
|
432
|
+
export const cssQuerySelectors = [
|
433
|
+
':not(a):is([role="link"]',
|
434
|
+
'button[onclick])',
|
435
|
+
'a:not([href])',
|
436
|
+
'[role="button"]:not(a[href])', // Add this line to select elements with role="button" where it is not <a> with href
|
437
|
+
];
|
438
|
+
|
439
|
+
export enum RuleFlags {
|
440
|
+
DEFAULT = 'default',
|
441
|
+
DISABLE_OOBEE = 'disable-oobee',
|
442
|
+
ENABLE_WCAG_AAA = 'enable-wcag-aaa',
|
443
|
+
}
|