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