Permalink
Newer
100644
156 lines (125 sloc)
4.58 KB
5
import { parse as parseSetCookie, splitCookiesString } from 'set-cookie-parser';
6
import * as cluster from '../../misc/cluster.js';
7
import { isCluster } from '../../config.js';
8
9
const WRITE_INTERVAL = 60000;
10
const VALID_SERVICES = new Set([
11
'instagram',
12
'instagram_bearer',
13
'reddit',
14
'twitter',
15
'youtube',
16
]);
17
18
const invalidCookies = {};
19
let cookies = {}, dirty = false, intervalId;
20
21
function writeChanges(cookiePath) {
22
if (!dirty) return;
23
dirty = false;
25
const cookieData = JSON.stringify({ ...cookies, ...invalidCookies }, null, 4);
26
writeFile(cookiePath, cookieData).catch((e) => {
27
console.warn(`${Yellow('[!]')} failed writing updated cookies to storage`);
28
console.warn(e);
29
clearInterval(intervalId);
30
intervalId = null;
31
})
32
}
35
try {
36
cookies = await readFile(cookiePath, 'utf8');
37
cookies = JSON.parse(cookies);
38
for (const serviceName in cookies) {
39
if (!VALID_SERVICES.has(serviceName)) {
40
console.warn(`${Yellow('[!]')} ignoring unknown service in cookie file: ${serviceName}`);
41
} else if (!Array.isArray(cookies[serviceName])) {
42
console.warn(`${Yellow('[!]')} ${serviceName} in cookies file is not an array, ignoring it`);
43
} else if (cookies[serviceName].some(c => typeof c !== 'string')) {
44
console.warn(`${Yellow('[!]')} some cookie for ${serviceName} contains non-string value in cookies file`);
45
} else continue;
46
47
invalidCookies[serviceName] = cookies[serviceName];
48
delete cookies[serviceName];
49
}
50
51
if (!intervalId) {
52
intervalId = setInterval(() => writeChanges(cookiePath), WRITE_INTERVAL);
53
}
54
55
cluster.broadcast({ cookies });
56
57
console.log(`${Green('[✓]')} cookies loaded successfully!`);
59
console.error(`${Yellow('[!]')} failed to load cookies.`);
60
console.error('error:', e);
64
const setupWorker = async () => {
65
cookies = (await cluster.waitFor('cookies')).cookies;
66
}
67
68
export const loadFromFile = async (path) => {
69
if (cluster.isPrimary) {
70
await setupMain(path);
71
} else if (cluster.isWorker) {
72
await setupWorker();
73
}
78
export const setup = async (path) => {
79
await loadFromFile(path);
80
81
if (isCluster) {
82
const messageHandler = (message) => {
83
if ('cookieUpdate' in message) {
84
const { cookieUpdate } = message;
85
86
if (cluster.isPrimary) {
87
dirty = true;
88
cluster.broadcast({ cookieUpdate });
89
}
90
91
const { service, idx, cookie } = cookieUpdate;
92
cookies[service][idx] = cookie;
93
}
94
}
95
96
if (cluster.isPrimary) {
97
cluster.mainOnMessage(messageHandler);
98
} else {
99
process.on('message', messageHandler);
100
}
101
}
105
if (!VALID_SERVICES.has(service)) {
106
console.error(
107
`${Red('[!]')} ${service} not in allowed services list for cookies.`
108
+ ' if adding a new cookie type, include it there.'
109
);
110
return;
111
}
112
115
const idx = Math.floor(Math.random() * cookies[service].length);
116
117
const cookie = cookies[service][idx];
118
if (typeof cookie === 'string') {
119
cookies[service][idx] = Cookie.fromString(cookie);
122
cookies[service][idx].meta = { service, idx };
123
return cookies[service][idx];
124
}
125
126
export function updateCookieValues(cookie, values) {
127
let changed = false;
128
129
for (const [ key, value ] of Object.entries(values)) {
130
changed = cookie.set(key, value) || changed;
131
}
133
if (changed && cookie.meta) {
134
dirty = true;
135
if (isCluster) {
136
const message = { cookieUpdate: { ...cookie.meta, cookie } };
137
cluster.send(message);
138
}
139
}
140
141
return changed;
142
}
143
144
export function updateCookie(cookie, headers) {
145
if (!cookie) return;
146
147
const parsed = parseSetCookie(
148
splitCookiesString(headers.get('set-cookie')),
149
{ decodeValues: false }
150
), values = {}
152
cookie.unset(parsed.filter(c => c.expires < new Date()).map(c => c.name));
153
parsed.filter(c => !c.expires || c.expires > new Date()).forEach(c => values[c.name] = c.value);
154
155
updateCookieValues(cookie, values);