Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ulixee
GitHub Repository: ulixee/secret-agent
Path: blob/main/core/lib/UserProfile.ts
1029 views
1
import IUserProfile from '@secret-agent/interfaces/IUserProfile';
2
import IDomStorage from '@secret-agent/interfaces/IDomStorage';
3
import Log from '@secret-agent/commons/Logger';
4
import { IPuppetPage } from '@secret-agent/interfaces/IPuppetPage';
5
import { assert } from '@secret-agent/commons/utils';
6
import Session from './Session';
7
import InjectedScripts from './InjectedScripts';
8
9
const { log } = Log(module);
10
11
export default class UserProfile {
12
public static async export(session: Session) {
13
const cookies = await session.browserContext.getCookies();
14
15
// start with previous storage
16
const storage: IDomStorage = session.options.userProfile?.storage ?? {};
17
18
for (const tab of session.tabsById.values()) {
19
const page = tab.puppetPage;
20
21
const dbs = await page.getIndexedDbDatabaseNames();
22
const frames = page.frames;
23
for (const { origin, frameId, databases } of dbs) {
24
const frame = frames.find(x => x.id === frameId);
25
storage[origin] = await frame?.evaluate(
26
`window.exportDomStorage(${JSON.stringify(databases)})`,
27
true,
28
);
29
}
30
}
31
32
return {
33
cookies,
34
storage,
35
userAgentString: session.plugins.browserEmulator.userAgentString,
36
deviceProfile: session.plugins.browserEmulator.deviceProfile,
37
} as IUserProfile;
38
}
39
40
public static async installCookies(session: Session) {
41
const { userProfile } = session;
42
assert(userProfile, 'UserProfile exists');
43
44
const { storage, cookies } = userProfile;
45
const origins = Object.keys(storage ?? {});
46
47
if (cookies && cookies.length) {
48
await session.browserContext.addCookies(cookies, origins);
49
}
50
return this;
51
}
52
53
public static async installStorage(session: Session, page: IPuppetPage) {
54
const { userProfile } = session;
55
const storage = userProfile.storage;
56
if (!storage) return;
57
58
const startMitm = { ...session.mitmRequestSession.blockedResources };
59
try {
60
session.mitmRequestSession.blockedResources = {
61
types: [],
62
urls: Object.keys(storage),
63
handlerFn(req, res, ctx) {
64
let script = '';
65
const originStorage = storage[ctx.url.origin];
66
const sessionStorage = originStorage?.sessionStorage;
67
if (sessionStorage) {
68
script += `
69
for (const [key,value] of ${JSON.stringify(sessionStorage)}) {
70
sessionStorage.setItem(key,value);
71
}\n`;
72
}
73
const localStorage = originStorage?.localStorage;
74
if (localStorage) {
75
script += `\n
76
for (const [key,value] of ${JSON.stringify(localStorage)}) {
77
localStorage.setItem(key,value);
78
}\n`;
79
}
80
81
if (originStorage?.indexedDB) {
82
script += `\n\n
83
${InjectedScripts.getIndexedDbStorageRestoreScript(originStorage.indexedDB)}`;
84
}
85
86
res.end(`<html><body>
87
<h5>${ctx.url.origin}</h5>
88
<script>
89
${script}
90
</script>
91
</body></html>`);
92
93
return true;
94
},
95
};
96
// reinstall session storage for the
97
await page.devtoolsSession.send('Page.setDocumentContent', {
98
frameId: page.mainFrame.id,
99
html: `<html>
100
<body>
101
<h1>Restoring Dom Storage</h1>
102
${Object.keys(storage)
103
.map(x => `<iframe src="${x}"></iframe>`)
104
.join('\n')}
105
</body>
106
</html>`,
107
});
108
109
for (const frame of page.frames) {
110
if (frame === page.mainFrame) {
111
// no loader is set, so need to have special handling
112
if (!page.mainFrame.activeLoader.lifecycle.load) {
113
await page.mainFrame.waitOn('frame-lifecycle', x => x.name === 'load');
114
}
115
continue;
116
}
117
await frame.waitForLifecycleEvent('load');
118
}
119
} finally {
120
session.mitmRequestSession.blockedResources = startMitm;
121
}
122
}
123
}
124
125