-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathccc.js
220 lines (176 loc) · 9.36 KB
/
ccc.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
#!/usr/bin/env node
const debug = require('debug');//('cdn-cache-check');
// Command line options parser
const argv = require('yargs')
.help(false)
.argv;
// Check if "debug" mode is enabled via the command line
if (argv.debug) {
debug.enable('*');
}
debug('Entry: [%s]', __filename);
debug('Command line arguments: %O', process.argv);
// Global Constants
const constants = require('./ccc-constants');
constants.init();
// Initialise configuration
const config = require('./ccc-configuration');
// Populate the settings object
const settings = config.getSettings();
debug('Using settings: %O', settings);
// cdn-cache-check's DNS library
const cccDNS = require('./ccc-dns');
// cdn-cache-check's DNS library
const cccHTTP = require('./ccc-http');
// cdn-cache-check's DNS library
const cccRender = require('./ccc-render-results');
// cdn-cache-check's library
const cdn_cache_check = require('./ccc-lib');
// HTTP Archive Parsers
const harParser = require('./harparser');
// Initialise console colours
const chalk = require('chalk');
// Initialise File System object
const fs = require('fs');
// File path parsing object
const path = require('path');
// Platform independent new line character and path separator
const EOL = require('os').EOL;
// Initialise URL validation object
const validUrl = require('valid-url');
// Initialise Domain validation object
const isValidDomain = require('is-valid-domain');
// Import terminal spinner library
const ora = require('ora');
const cloudServices = require('./ccc-service-detection');
try {
// Check for '--help' command line parameters
if (argv.help) {
debug('--help detected. Showing help screen.');
// Show help screen
let help = require('./help');
help.helpScreen(argv.verbose);
//Exit to terminal
process.exit();
}
// '--header-collections' command line parameter is not valid. Suggest possible correction
if (argv.headerCollections) {
console.log(`--header-collections is not valid. Did you mean ${chalk.cyan('--list-header-collections')} ?`);
}
// Check for '--list-header-collections' command line parameters
if (argv.listHeaderCollections) {
debug('--list-header-collections detected. Retrieving all Headers Collections....');
// Get an array of Header Collections and render them to the console
config.displayHeaderCollections(config.getHeaderCollections());
// Display config file location
config.displayConfigFileLocation();
// Exit to terminal
process.exit();
}
debug('Looking for URLs to check...');
console.info('Looking for URLs to check...');
// Initialise array of URLs to check
let urls = [];
// Iterate through all parameters looking for ones that are URLs or files
for (let i = 2; i < process.argv.length; ++i) {
let currentArgument = process.argv[i];
// Check if it's a valid file
try {
debug('Checking if [%s] is a file, URL or bare domain ...', currentArgument);
if (fs.existsSync(currentArgument)) { // File exists. Extract URLs from it
try {
if (path.extname(currentArgument).toLowerCase() === '.har') {
debug('It\'s a HTTP Archive (.har) file. Reading its contents ...');
let harURLs = harParser.getURLs(currentArgument); // Parse HAR file for a list of URLs
debug('The HAR file referenced %s URLs', harURLs.length);
urls.push(...harURLs); // Append the HAR's URLs to the global URL array
} else {
// Read the text file
debug('It\'s a text file. Reading its contents ...');
let data = fs.readFileSync(currentArgument, 'UTF-8');
// Split the contents by new line
let lines = data.split(EOL);
// Examine each line
debug('Examining %i lines looking for URLs...', lines.length);
for (let i = 0; i < lines.length; ++i) {
if (validUrl.isWebUri(lines[i])) {
debug('Found a URL [%s]', lines[i]);
urls.push(lines[i]);
} else if (isValidDomain(lines[i], { subdomain: true, wildcard: false })) {
debug('Found a bare domain [%s]', lines[i]);
urls.push(`https://${lines[i]}`);
} else if (lines[i].length > 0) {
// This line didn't pass any tests so log it to debug output, but only if it's not a blank line
debug('Ignoring [%s]', lines[i]);
}
}
}
} catch (error) {
debug('An error occurred when parsing the file [%s]: %O', currentArgument, error);
}
} else if (validUrl.isWebUri(currentArgument)) {
// It's a valid URL. Add it to the urls array
debug('It\'s a valid URL');
urls.push(currentArgument);
} else if (isValidDomain(currentArgument, { subdomain: true, wildcard: false })) {
// It's a bare domain (i.e. there's no protocol)
debug('It\'s a valid domain but not a URL. Adding "https://" to it');
urls.push(`https://${currentArgument}`);
} else {
// It doesn't pass any tests. Ignore it
debug('Ignoring [%s]', currentArgument);
}
} catch (error) {
console.error(`An error occurred - ${error.message}`);
debug(error);
}
}
// We've parsed the URLs into an array
if (urls.length === 0) {
console.log(chalk.red('Error: No URL(s) provided.'));
// Show some advice
console.log(chalk.grey(`Try ${chalk.grey.italic('ccc --help')} for syntax.`));
} else {
// The main work starts here
// Extract a list of each distinct FQDN from the list of URLs
let uniqueDomains = cccDNS.getUniqueDomains(urls);
debug('Unique Domains: %O', uniqueDomains);
// Calculate how many requests we're going to make and display a notification if it exceeds the threshold
debug('Checking these %s URLs across %s domain(s): %O', urls.length, uniqueDomains.count, urls);
if (urls.length > global.CCC_REQUEST.WARNING_THRESHOLD) {
// Display how many requests we're about to make, but only if it's a *lot* (there's no point saying we're about to make 2 requests)
cdn_cache_check.displayRequestSummary(urls.length, uniqueDomains.count);
}
// Create and start the HTTP requests activity spinner
const spinnerHTTPRequests = ora('Issuing HTTP requests ...').start();
cccHTTP.issueRequests(urls, settings).then((responses) => { // Issue HTTP requests for each URL
debug('Received %i responses from %i URLs', responses.length, urls.length);
spinnerHTTPRequests.succeed(chalk.green(`Completed ${urls.length} HTTP requests`)); // Stop the HTTP Requests spinner
cccRender.renderHTTPResponses(responses, settings).then((columns) => { // Format HTTP responses into tabulated output
console.log(columns); // Display HTTP response results in console
if (settings.listResponseHeaders) { // Check if switch to list unique response headers is enabled
cccRender.renderHTTPResponseHeaders(responses); // Display all unique HTTP response headers
}
});
if (settings.serviceDetection) { // Check if Service Detection is enabled
// Create and start the Service Detection activity spinner
let spinnerServiceDetection = ora(`Service detection being performed on ${uniqueDomains.domains.length} unique domains ...`).start();
cloudServices.serviceDetection(uniqueDomains, settings).then(() => {
// Stop the Service Detection spinner
spinnerServiceDetection.succeed(chalk.green(`Service inspection complete on ${uniqueDomains.domains.length} unique domains`));
}).catch((error) => {
// Stop the Service Detection spinner and report the error
spinnerServiceDetection.succeed(chalk.green(`Service inspection completed, albeit with errors, on ${uniqueDomains.domains.length} unique domains`));
if (settings.verbose) { // Report the error if --verbose is supplied
console.error(`${chalk.bgRed.whiteBright('Service Detection error')}: ${error}`);
} else {
console.log(`${chalk.grey('Use')} ${chalk.grey.bold('--verbose')} ${chalk.grey('to show the error')}`);
}
});
}
});
}
} catch (error) {
console.error(`An error occurred - ${error.message}`);
debug(error);
}