Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ulixee
GitHub Repository: ulixee/secret-agent
Path: blob/main/plugins/default-browser-emulator/index.ts
1028 views
1
import BrowserEmulator from '@secret-agent/plugin-utils/lib/BrowserEmulator';
2
import IHttpResourceLoadDetails from '@secret-agent/interfaces/IHttpResourceLoadDetails';
3
import IDnsSettings from '@secret-agent/interfaces/IDnsSettings';
4
import ITcpSettings from '@secret-agent/interfaces/ITcpSettings';
5
import ITlsSettings from '@secret-agent/interfaces/ITlsSettings';
6
import { IPuppetPage } from '@secret-agent/interfaces/IPuppetPage';
7
import {
8
BrowserEmulatorClassDecorator,
9
IBrowserEmulatorConfig,
10
} from '@secret-agent/interfaces/ICorePlugin';
11
import { IPuppetWorker } from '@secret-agent/interfaces/IPuppetWorker';
12
import IViewport from '@secret-agent/interfaces/IViewport';
13
import ICorePluginCreateOptions from '@secret-agent/interfaces/ICorePluginCreateOptions';
14
import IUserAgentOption from '@secret-agent/interfaces/IUserAgentOption';
15
import BrowserEngine from '@secret-agent/plugin-utils/lib/BrowserEngine';
16
import IGeolocation from '@secret-agent/interfaces/IGeolocation';
17
import IHttp2ConnectSettings from '@secret-agent/interfaces/IHttp2ConnectSettings';
18
import IHttpSocketAgent from '@secret-agent/interfaces/IHttpSocketAgent';
19
import Viewports from './lib/Viewports';
20
import setWorkerDomOverrides from './lib/setWorkerDomOverrides';
21
import setPageDomOverrides from './lib/setPageDomOverrides';
22
import setUserAgent from './lib/helpers/setUserAgent';
23
import setScreensize from './lib/helpers/setScreensize';
24
import setTimezone from './lib/helpers/setTimezone';
25
import setLocale from './lib/helpers/setLocale';
26
import setActiveAndFocused from './lib/helpers/setActiveAndFocused';
27
import selectUserAgentOption from './lib/helpers/selectUserAgentOption';
28
import modifyHeaders from './lib/helpers/modifyHeaders';
29
import configureSessionDns from './lib/helpers/configureSessionDns';
30
import configureSessionTcp from './lib/helpers/configureSessionTcp';
31
import configureSessionTls from './lib/helpers/configureSessionTls';
32
import FirstPartyCookiesPlugin from './lib/plugins/FirstPartyCookiesPlugin';
33
import DataLoader from './lib/DataLoader';
34
import IBrowserData from './interfaces/IBrowserData';
35
import selectBrowserEngineOption from './lib/helpers/selectBrowserEngineOption';
36
import setGeolocation from './lib/helpers/setGeolocation';
37
import { configureBrowserLaunchArgs } from './lib/helpers/configureBrowserLaunchArgs';
38
import loadDomOverrides from './lib/loadDomOverrides';
39
import DomOverridesBuilder from './lib/DomOverridesBuilder';
40
import configureDeviceProfile from './lib/helpers/configureDeviceProfile';
41
import configureHttp2Session from './lib/helpers/configureHttp2Session';
42
import lookupPublicIp, { IpLookupServices } from './lib/helpers/lookupPublicIp';
43
44
const dataLoader = new DataLoader(__dirname);
45
export const latestBrowserEngineId = 'chrome-88-0';
46
export const latestChromeBrowserVersion = { major: '88', minor: '0' };
47
48
@BrowserEmulatorClassDecorator
49
export default class DefaultBrowserEmulator extends BrowserEmulator {
50
public static id = dataLoader.pkg.name.replace('@secret-agent/', '');
51
52
public timezoneId: string;
53
public locale: string;
54
public viewport: IViewport;
55
public geolocation: IGeolocation;
56
public upstreamProxyIpMask: IBrowserEmulatorConfig['upstreamProxyIpMask'];
57
public upstreamProxyUrl: string;
58
59
protected readonly data: IBrowserData;
60
private readonly domOverridesBuilder: DomOverridesBuilder;
61
62
constructor(createOptions: ICorePluginCreateOptions) {
63
super(createOptions);
64
this.data = dataLoader.as(createOptions.userAgentOption) as any;
65
66
// set default device profile options
67
configureDeviceProfile(this.deviceProfile);
68
69
if (this.data.browserConfig.features.includes('FirstPartyCookies')) {
70
createOptions.corePlugins.use(FirstPartyCookiesPlugin);
71
}
72
this.domOverridesBuilder = loadDomOverrides(this, this.data);
73
}
74
75
configure(config: IBrowserEmulatorConfig): void {
76
if (!config) return;
77
78
config.locale = config.locale || this.locale || this.data.browserConfig.defaultLocale;
79
config.viewport =
80
config.viewport ||
81
this.viewport ||
82
Viewports.getDefault(this.data.windowBaseFraming, this.data.windowFraming);
83
config.timezoneId =
84
config.timezoneId || this.timezoneId || Intl.DateTimeFormat().resolvedOptions().timeZone;
85
config.geolocation = config.geolocation || this.geolocation;
86
87
if (config.upstreamProxyUrl) {
88
config.upstreamProxyIpMask ??= {};
89
config.upstreamProxyIpMask.ipLookupService ??= IpLookupServices.ipify;
90
}
91
92
this.locale = config.locale;
93
this.viewport = config.viewport;
94
this.timezoneId = config.timezoneId;
95
this.geolocation = config.geolocation;
96
this.upstreamProxyIpMask = config.upstreamProxyIpMask;
97
this.upstreamProxyUrl = config.upstreamProxyUrl;
98
}
99
100
public onDnsConfiguration(settings: IDnsSettings): void {
101
configureSessionDns(this, settings);
102
}
103
104
public onTcpConfiguration(settings: ITcpSettings): void {
105
configureSessionTcp(this, settings);
106
}
107
108
public onTlsConfiguration(settings: ITlsSettings): void {
109
configureSessionTls(this, settings);
110
}
111
112
public beforeHttpRequest(resource: IHttpResourceLoadDetails): void {
113
modifyHeaders(this, this.data, resource);
114
}
115
116
public async onHttpAgentInitialized(agent: IHttpSocketAgent): Promise<void> {
117
if (this.upstreamProxyIpMask) {
118
this.upstreamProxyIpMask.publicIp ??= await lookupPublicIp(
119
this.upstreamProxyIpMask.ipLookupService,
120
);
121
this.upstreamProxyIpMask.proxyIp ??= await lookupPublicIp(
122
this.upstreamProxyIpMask.ipLookupService,
123
agent,
124
this.upstreamProxyUrl,
125
);
126
this.logger.info('PublicIp Lookup', {
127
...this.upstreamProxyIpMask,
128
});
129
this.domOverridesBuilder.add('webrtc', {
130
localIp: this.upstreamProxyIpMask.publicIp,
131
proxyIp: this.upstreamProxyIpMask.proxyIp,
132
});
133
}
134
}
135
136
public onHttp2SessionConnect(
137
request: IHttpResourceLoadDetails,
138
settings: IHttp2ConnectSettings,
139
): void {
140
configureHttp2Session(this, this.data, request, settings);
141
}
142
143
public onNewPuppetPage(page: IPuppetPage): Promise<any> {
144
// Don't await here! we want to queue all these up to run before the debugger resumes
145
const devtools = page.devtoolsSession;
146
return Promise.all([
147
setUserAgent(this, devtools),
148
setTimezone(this, devtools),
149
setLocale(this, devtools),
150
setScreensize(this, page, devtools),
151
setActiveAndFocused(this, devtools),
152
setPageDomOverrides(this.domOverridesBuilder, this.data, page),
153
setGeolocation(this, page),
154
]);
155
}
156
157
public onNewPuppetWorker(worker: IPuppetWorker): Promise<any> {
158
const devtools = worker.devtoolsSession;
159
return Promise.all([
160
setUserAgent(this, devtools),
161
setWorkerDomOverrides(this.domOverridesBuilder, this.data, worker),
162
]);
163
}
164
165
public static selectBrowserMeta(
166
userAgentSelector?: string,
167
): { browserEngine: BrowserEngine; userAgentOption: IUserAgentOption } {
168
const userAgentOption = selectUserAgentOption(userAgentSelector, dataLoader.userAgentOptions);
169
170
const { browserName, browserVersion } = userAgentOption;
171
const browserEngineId = `${browserName}-${browserVersion.major}-${browserVersion.minor}`;
172
const browserEngineOption = selectBrowserEngineOption(
173
browserEngineId,
174
dataLoader.browserEngineOptions,
175
);
176
const browserEngine = new BrowserEngine(this, browserEngineOption);
177
return { browserEngine, userAgentOption };
178
}
179
180
public static onBrowserWillLaunch(
181
browserEngine: BrowserEngine,
182
options: {
183
showBrowser?: boolean;
184
disableGpu?: boolean;
185
disableDevtools?: boolean;
186
},
187
): void {
188
configureBrowserLaunchArgs(browserEngine, options);
189
}
190
}
191
192