header-generator 1.1.2 → 2.0.0-beta.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/README.md +12 -1
- package/package.json +2 -1
- package/src/constants.js +5 -0
- package/src/header-generator.js +44 -37
- package/src/main.js +5 -1
- package/src/presets.js +62 -0
- package/src/utils.js +54 -0
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@ NodeJs package for generating browser-like headers.
|
|
|
5
5
|
|
|
6
6
|
- [Installation](#installation)
|
|
7
7
|
- [Usage](#usage)
|
|
8
|
+
- [Presets](#presets)
|
|
8
9
|
- [Result example](#result-example)
|
|
9
10
|
- [API Reference](#api-reference)
|
|
10
11
|
|
|
@@ -15,7 +16,7 @@ Run the `npm install header-generator` command. No further setup is needed after
|
|
|
15
16
|
## Usage
|
|
16
17
|
To use the generator, you need to create an instance of the `HeaderGenerator` class which is exported from this package. Constructor of this class accepts a `HeaderGeneratorOptions` object, which can be used to globally specify what kind of headers you are looking for:
|
|
17
18
|
```js
|
|
18
|
-
const HeaderGenerator = require('header-generator');
|
|
19
|
+
const { HeaderGenerator } = require('header-generator');
|
|
19
20
|
let headerGenerator = new HeaderGenerator({
|
|
20
21
|
browsers: [
|
|
21
22
|
{name: "firefox", minVersion: 80},
|
|
@@ -40,6 +41,15 @@ let headers = headersGenerator.getHeaders({
|
|
|
40
41
|
});
|
|
41
42
|
```
|
|
42
43
|
This method always generates a random realistic set of headers, excluding the request dependant headers, which need to be filled in afterwards. Since the generation is randomized, multiple calls to this method with the same parameters can generate multiple different outputs.
|
|
44
|
+
|
|
45
|
+
## Presets
|
|
46
|
+
Presets are setting templates for common use cases. It saves time writing the same configuration over and over.
|
|
47
|
+
```js
|
|
48
|
+
const { HeaderGenerator, PRESETS } = require('header-generator');
|
|
49
|
+
let headerGenerator = new HeaderGenerator(PRESETS.MODERN_WINDOWS_CHROME);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
This preset will fill the configuration for the latest five versions of chrome for windows desktops. Checkout the available presets list here @TODO: LINK.
|
|
43
53
|
## Result example
|
|
44
54
|
A result that can be generated for the usage example above:
|
|
45
55
|
```json
|
|
@@ -134,6 +144,7 @@ Returns a new object that contains ordered headers.
|
|
|
134
144
|
| Param | Type | Description |
|
|
135
145
|
| --- | --- | --- |
|
|
136
146
|
| browsers | <code>Array.<(BrowserSpecification\|string)></code> | List of BrowserSpecifications to generate the headers for, or one of `chrome`, `firefox` and `safari`. |
|
|
147
|
+
| browserListQuery | <code>string</code> | Browser generation query based on the real world data. For more info see the [query docs](https://github.com/browserslist/browserslist#full-list). If `browserListQuery` is passed the `browsers` array is ignored. |
|
|
137
148
|
| operatingSystems | <code>Array.<string></code> | List of operating systems to generate the headers for. The options are `windows`, `macos`, `linux`, `android` and `ios`. |
|
|
138
149
|
| devices | <code>Array.<string></code> | List of devices to generate the headers for. Options are `desktop` and `mobile`. |
|
|
139
150
|
| locales | <code>Array.<string></code> | List of at most 10 languages to include in the [Accept-Language](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language) request header in the language format accepted by that header, for example `en`, `en-US` or `de`. |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "header-generator",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-beta.0",
|
|
4
4
|
"description": "NodeJs package for generating browser-like headers.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Apify",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"src"
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
|
+
"browserslist": "^4.19.1",
|
|
17
18
|
"generative-bayesian-network": "0.1.0-beta.1",
|
|
18
19
|
"ow": "^0.23.0"
|
|
19
20
|
},
|
package/src/constants.js
ADDED
package/src/header-generator.js
CHANGED
|
@@ -11,7 +11,8 @@ const headerNetworkDefinition = require('./data_files/header-network-definition.
|
|
|
11
11
|
const inputNetworkDefinition = require('./data_files/input-network-definition.json');
|
|
12
12
|
const headersOrder = require('./data_files/headers-order.json');
|
|
13
13
|
const uniqueBrowserStrings = require('./data_files/browser-helper-file.json');
|
|
14
|
-
const { getBrowser, getUserAgent } = require('./utils');
|
|
14
|
+
const { getBrowser, getUserAgent, getBrowsersFromQuery } = require('./utils');
|
|
15
|
+
const { SUPPORTED_BROWSERS } = require('./constants');
|
|
15
16
|
|
|
16
17
|
const uniqueBrowsers = [];
|
|
17
18
|
for (const browserString of uniqueBrowserStrings) {
|
|
@@ -104,6 +105,7 @@ const headerGeneratorOptionsShape = {
|
|
|
104
105
|
devices: ow.optional.array.ofType(ow.string),
|
|
105
106
|
locales: ow.optional.array.ofType(ow.string),
|
|
106
107
|
httpVersion: ow.optional.string,
|
|
108
|
+
browserListQuery: ow.optional.string,
|
|
107
109
|
};
|
|
108
110
|
|
|
109
111
|
/**
|
|
@@ -130,10 +132,14 @@ function getOrderFromUserAgent(headers) {
|
|
|
130
132
|
* @param {string} httpVersion - Http version to be used to generate headers (the headers differ depending on the version).
|
|
131
133
|
* Either 1 or 2. If none specified the httpVersion specified in `HeaderGeneratorOptions` is used.
|
|
132
134
|
*/
|
|
135
|
+
|
|
133
136
|
/**
|
|
134
137
|
* @typedef HeaderGeneratorOptions
|
|
135
138
|
* @param {Array<BrowserSpecification|string>} browsers - List of BrowserSpecifications to generate the headers for,
|
|
136
139
|
* or one of `chrome`, `firefox` and `safari`.
|
|
140
|
+
* @param {string} browserListQuery - Browser generation query based on the real world data.
|
|
141
|
+
* For more info see the [query docs](https://github.com/browserslist/browserslist#full-list).
|
|
142
|
+
* If `browserListQuery` is passed the `browsers` array is ignored.
|
|
137
143
|
* @param {Array<string>} operatingSystems - List of operating systems to generate the headers for.
|
|
138
144
|
* The options are `windows`, `macos`, `linux`, `android` and `ios`.
|
|
139
145
|
* @param {Array<string>} devices - List of devices to generate the headers for. Options are `desktop` and `mobile`.
|
|
@@ -153,30 +159,23 @@ class HeaderGenerator {
|
|
|
153
159
|
*/
|
|
154
160
|
constructor(options = {}) {
|
|
155
161
|
ow(options, 'HeaderGeneratorOptions', ow.object.exactShape(headerGeneratorOptionsShape));
|
|
156
|
-
this.defaultOptions = JSON.parse(JSON.stringify(options));
|
|
157
162
|
// Use a default setup when the necessary values are not provided
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
'macos',
|
|
175
|
-
'linux',
|
|
176
|
-
'android',
|
|
177
|
-
'ios',
|
|
178
|
-
];
|
|
179
|
-
}
|
|
163
|
+
const {
|
|
164
|
+
browsers = SUPPORTED_BROWSERS,
|
|
165
|
+
operatingSystems = ['windows', 'macos', 'linux', 'android', 'ios'],
|
|
166
|
+
devices = ['desktop'],
|
|
167
|
+
locales = ['en-US'],
|
|
168
|
+
httpVersion = '2',
|
|
169
|
+
browserListQuery,
|
|
170
|
+
} = options;
|
|
171
|
+
this.browserListQuery = browserListQuery;
|
|
172
|
+
this.globalOptions = {
|
|
173
|
+
browsers: this._prepareBrowsersConfig(browsers, browserListQuery, httpVersion),
|
|
174
|
+
operatingSystems,
|
|
175
|
+
devices,
|
|
176
|
+
locales,
|
|
177
|
+
httpVersion,
|
|
178
|
+
};
|
|
180
179
|
|
|
181
180
|
this.inputGeneratorNetwork = new BayesianNetwork(inputNetworkDefinition);
|
|
182
181
|
this.headerGeneratorNetwork = new BayesianNetwork(headerNetworkDefinition);
|
|
@@ -190,17 +189,8 @@ class HeaderGenerator {
|
|
|
190
189
|
*/
|
|
191
190
|
getHeaders(options = {}, requestDependentHeaders = {}) {
|
|
192
191
|
ow(options, 'HeaderGeneratorOptions', ow.object.exactShape(headerGeneratorOptionsShape));
|
|
193
|
-
const headerOptions = JSON.parse(JSON.stringify({ ...this.
|
|
194
|
-
headerOptions.browsers = headerOptions.browsers.
|
|
195
|
-
if (typeof browserObject === 'string') {
|
|
196
|
-
browserObject = { name: browserObject };
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
if (!browserObject.httpVersion) {
|
|
200
|
-
browserObject.httpVersion = headerOptions.httpVersion;
|
|
201
|
-
}
|
|
202
|
-
return browserObject;
|
|
203
|
-
});
|
|
192
|
+
const headerOptions = JSON.parse(JSON.stringify({ ...this.globalOptions, ...options }));
|
|
193
|
+
headerOptions.browsers = this._prepareBrowsersConfig(headerOptions.browsers, headerOptions.browserListQuery, headerOptions.httpVersion);
|
|
204
194
|
|
|
205
195
|
const possibleAttributeValues = {};
|
|
206
196
|
|
|
@@ -248,7 +238,7 @@ class HeaderGenerator {
|
|
|
248
238
|
let highLevelLocales = [];
|
|
249
239
|
for (const locale of headerOptions.locales) {
|
|
250
240
|
if (!locale.includes('-')) {
|
|
251
|
-
highLevelLocales.push();
|
|
241
|
+
highLevelLocales.push(locale);
|
|
252
242
|
}
|
|
253
243
|
}
|
|
254
244
|
|
|
@@ -279,7 +269,7 @@ class HeaderGenerator {
|
|
|
279
269
|
|
|
280
270
|
let acceptLanguageFieldValue = localesInAddingOrder[0];
|
|
281
271
|
for (let x = 1; x < localesInAddingOrder.length; x++) {
|
|
282
|
-
acceptLanguageFieldValue += `,${localesInAddingOrder[x]}
|
|
272
|
+
acceptLanguageFieldValue += `,${localesInAddingOrder[x]};q=${1 - x * 0.1}`;
|
|
283
273
|
}
|
|
284
274
|
|
|
285
275
|
generatedSample[acceptLanguageFieldName] = acceptLanguageFieldValue;
|
|
@@ -329,6 +319,23 @@ class HeaderGenerator {
|
|
|
329
319
|
|
|
330
320
|
return orderedSample;
|
|
331
321
|
}
|
|
322
|
+
|
|
323
|
+
_prepareBrowsersConfig(browsers, browserListQuery, httpVersion) {
|
|
324
|
+
let finalBrowsers = browsers;
|
|
325
|
+
|
|
326
|
+
if (browserListQuery) {
|
|
327
|
+
finalBrowsers = getBrowsersFromQuery(browserListQuery);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return finalBrowsers.map((browser) => {
|
|
331
|
+
if (typeof browser === 'string') {
|
|
332
|
+
return { name: browser, httpVersion };
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
browser.httpVersion = httpVersion;
|
|
336
|
+
return browser;
|
|
337
|
+
});
|
|
338
|
+
}
|
|
332
339
|
}
|
|
333
340
|
|
|
334
341
|
module.exports = HeaderGenerator;
|
package/src/main.js
CHANGED
package/src/presets.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const MODERN_DESKTOP = {
|
|
2
|
+
browserListQuery: 'last 5 versions',
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
const MODERN_MOBILE = {
|
|
6
|
+
...MODERN_DESKTOP,
|
|
7
|
+
devices: ['mobile'],
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
exports.MODERN_DESKTOP = MODERN_DESKTOP;
|
|
11
|
+
exports.MODERN_MOBILE = MODERN_MOBILE;
|
|
12
|
+
|
|
13
|
+
exports.MODERN_LINUX = {
|
|
14
|
+
...MODERN_DESKTOP,
|
|
15
|
+
operatingSystems: ['linux'],
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
exports.MODERN_LINUX_FIREFOX = {
|
|
19
|
+
browserListQuery: 'last 5 firefox versions',
|
|
20
|
+
operatingSystems: ['linux'],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
exports.MODERN_LINUX_CHROME = {
|
|
24
|
+
browserListQuery: 'last 5 chrome versions',
|
|
25
|
+
operatingSystems: ['linux'],
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
exports.MODERN_WINDOWS = {
|
|
29
|
+
...MODERN_DESKTOP,
|
|
30
|
+
operatingSystems: ['windows'],
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
exports.MODERN_WINDOWS_FIREFOX = {
|
|
34
|
+
browserListQuery: 'last 5 firefox versions',
|
|
35
|
+
operatingSystems: ['windows'],
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
exports.MODERN_WINDOWS_CHROME = {
|
|
39
|
+
browserListQuery: 'last 5 chrome versions',
|
|
40
|
+
operatingSystems: ['windows'],
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
exports.MODERN_MACOS = {
|
|
44
|
+
...MODERN_DESKTOP,
|
|
45
|
+
operatingSystems: ['macos'],
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
exports.MODERN_MACOS_FIREFOX = {
|
|
49
|
+
browserListQuery: 'last 5 firefox versions',
|
|
50
|
+
operatingSystems: ['macos'],
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
exports.MODERN_MACOS_CHROME = {
|
|
54
|
+
browserListQuery: 'last 5 chrome versions',
|
|
55
|
+
operatingSystems: ['macos'],
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
exports.MODERN_ANDROID = {
|
|
59
|
+
...MODERN_MOBILE,
|
|
60
|
+
operatingSystems: ['android'],
|
|
61
|
+
|
|
62
|
+
};
|
package/src/utils.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
const browsersList = require('browserslist');
|
|
2
|
+
const { SUPPORTED_BROWSERS } = require('./constants');
|
|
3
|
+
|
|
1
4
|
const getUserAgent = (headers) => {
|
|
2
5
|
let userAgent;
|
|
3
6
|
for (const [header, value] of Object.entries(headers)) {
|
|
@@ -27,7 +30,58 @@ const getBrowser = (userAgent) => {
|
|
|
27
30
|
return browser;
|
|
28
31
|
};
|
|
29
32
|
|
|
33
|
+
const getBrowsersWithVersions = (browserList) => {
|
|
34
|
+
const browsersWithVersions = {};
|
|
35
|
+
|
|
36
|
+
for (const browserDefinition of browserList) {
|
|
37
|
+
const [browser, versionString] = browserDefinition.split(' ');
|
|
38
|
+
const version = parseInt(versionString, 10);
|
|
39
|
+
if (!SUPPORTED_BROWSERS.includes(browser)) {
|
|
40
|
+
// eslint-disable-next-line no-continue
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (browsersWithVersions[browser]) {
|
|
45
|
+
browsersWithVersions[browser].push(version);
|
|
46
|
+
} else {
|
|
47
|
+
browsersWithVersions[browser] = [version];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return browsersWithVersions;
|
|
51
|
+
};
|
|
52
|
+
const getOptimizedVersionDistribution = (browsersWithVersions) => {
|
|
53
|
+
const finalOptimizedBrowsers = [];
|
|
54
|
+
|
|
55
|
+
Object.entries(browsersWithVersions).forEach(([browser, versions]) => {
|
|
56
|
+
const sortedVersions = versions.sort((a, b) => a - b);
|
|
57
|
+
let lowestVersionSoFar = sortedVersions[0];
|
|
58
|
+
|
|
59
|
+
sortedVersions.forEach((version, index) => {
|
|
60
|
+
const nextVersion = sortedVersions[index + 1];
|
|
61
|
+
const isLast = index === sortedVersions.length - 1;
|
|
62
|
+
const isNextVersionGap = nextVersion - version > 1;
|
|
63
|
+
|
|
64
|
+
if (isNextVersionGap || isLast) {
|
|
65
|
+
finalOptimizedBrowsers.push({
|
|
66
|
+
name: browser,
|
|
67
|
+
minVersion: lowestVersionSoFar,
|
|
68
|
+
maxVersion: version,
|
|
69
|
+
});
|
|
70
|
+
lowestVersionSoFar = nextVersion;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
return finalOptimizedBrowsers;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const getBrowsersFromQuery = (browserListQuery) => {
|
|
78
|
+
const browserList = browsersList(browserListQuery);
|
|
79
|
+
const browsersWithVersions = getBrowsersWithVersions(browserList);
|
|
80
|
+
return getOptimizedVersionDistribution(browsersWithVersions);
|
|
81
|
+
};
|
|
82
|
+
|
|
30
83
|
module.exports = {
|
|
31
84
|
getUserAgent,
|
|
32
85
|
getBrowser,
|
|
86
|
+
getBrowsersFromQuery,
|
|
33
87
|
};
|