xnotif 0.2.0 → 0.2.1
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/dist/index.mjs +73 -62
- package/package.json +2 -5
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { EventEmitter } from "events";
|
|
2
|
-
import { TwitterOpenApi } from "twitter-openapi-typescript";
|
|
3
|
-
import { BaseAPI } from "twitter-openapi-typescript-generated";
|
|
4
2
|
|
|
5
3
|
//#region src/utils.ts
|
|
6
4
|
function base64urlToBuffer(b64url) {
|
|
@@ -274,70 +272,83 @@ var AutopushClient = class {
|
|
|
274
272
|
|
|
275
273
|
//#endregion
|
|
276
274
|
//#region src/twitter.ts
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
"
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
"
|
|
292
|
-
|
|
293
|
-
"
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
const apiKey = this.configuration.apiKey;
|
|
304
|
-
if (apiKey) for (const name of API_HEADER_NAMES) {
|
|
305
|
-
const value = await apiKey(name);
|
|
306
|
-
if (value) headers[name] = value;
|
|
307
|
-
}
|
|
308
|
-
const accessToken = this.configuration.accessToken;
|
|
309
|
-
if (accessToken) headers["Authorization"] = `Bearer ${await accessToken()}`;
|
|
310
|
-
headers["Content-Type"] = "application/json";
|
|
311
|
-
return this.request({
|
|
312
|
-
path,
|
|
313
|
-
method: "POST",
|
|
314
|
-
headers,
|
|
315
|
-
body
|
|
316
|
-
}, initOverride);
|
|
317
|
-
}
|
|
318
|
-
};
|
|
319
|
-
async function createClient$1(cookies) {
|
|
320
|
-
return new TwitterOpenApi().getClientFromCookies(cookies);
|
|
275
|
+
const BEARER_TOKEN = "AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA";
|
|
276
|
+
const HEADER_URL = "https://raw.githubusercontent.com/fa0311/latest-user-agent/refs/heads/main/header.json";
|
|
277
|
+
const PAIR_URL = "https://raw.githubusercontent.com/fa0311/x-client-transaction-pair-dict/refs/heads/main/pair.json";
|
|
278
|
+
async function generateTransactionId(method, path, key, animationKey) {
|
|
279
|
+
const DEFAULT_KEYWORD = "obfiowerehiring";
|
|
280
|
+
const ADDITIONAL_RANDOM_NUMBER = 3;
|
|
281
|
+
const timeNow = Math.floor((Date.now() - 1682924400 * 1e3) / 1e3);
|
|
282
|
+
const timeNowBytes = [
|
|
283
|
+
timeNow & 255,
|
|
284
|
+
timeNow >> 8 & 255,
|
|
285
|
+
timeNow >> 16 & 255,
|
|
286
|
+
timeNow >> 24 & 255
|
|
287
|
+
];
|
|
288
|
+
const data = `${method}!${path}!${timeNow}${DEFAULT_KEYWORD}${animationKey}`;
|
|
289
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(data));
|
|
290
|
+
const hashBytes = Array.from(new Uint8Array(hashBuffer));
|
|
291
|
+
const keyBytes = Array.from(Buffer.from(key, "base64"));
|
|
292
|
+
const randomNum = Math.floor(Math.random() * 256);
|
|
293
|
+
const bytesArr = [
|
|
294
|
+
...keyBytes,
|
|
295
|
+
...timeNowBytes,
|
|
296
|
+
...hashBytes.slice(0, 16),
|
|
297
|
+
ADDITIONAL_RANDOM_NUMBER
|
|
298
|
+
];
|
|
299
|
+
const out = new Uint8Array([randomNum, ...bytesArr.map((b) => b ^ randomNum)]);
|
|
300
|
+
return Buffer.from(out).toString("base64").replace(/=/g, "");
|
|
321
301
|
}
|
|
322
|
-
function
|
|
323
|
-
return
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
302
|
+
function encodeCookies(cookies) {
|
|
303
|
+
return Object.entries(cookies).map(([k, v]) => `${k}=${v}`).join("; ");
|
|
304
|
+
}
|
|
305
|
+
async function createClient$1(cookies) {
|
|
306
|
+
const [headerJson, pairs] = await Promise.all([fetch(HEADER_URL).then((r) => r.json()), fetch(PAIR_URL).then((r) => r.json())]);
|
|
307
|
+
const ignore = new Set(["host", "connection"]);
|
|
308
|
+
const headers = {
|
|
309
|
+
...Object.fromEntries(Object.entries(headerJson["chrome-fetch"]).filter(([k]) => !ignore.has(k))),
|
|
310
|
+
"accept-encoding": "identity",
|
|
311
|
+
pragma: "no-cache",
|
|
312
|
+
referer: "https://x.com",
|
|
313
|
+
priority: "u=1, i",
|
|
314
|
+
"x-twitter-client-language": "en",
|
|
315
|
+
"x-twitter-active-user": "yes",
|
|
316
|
+
authorization: `Bearer ${BEARER_TOKEN}`
|
|
317
|
+
};
|
|
318
|
+
if (cookies["ct0"]) {
|
|
319
|
+
headers["x-twitter-auth-type"] = "OAuth2Session";
|
|
320
|
+
headers["x-csrf-token"] = cookies["ct0"];
|
|
321
|
+
}
|
|
322
|
+
if (cookies["gt"]) headers["x-guest-token"] = cookies["gt"];
|
|
323
|
+
return {
|
|
324
|
+
headers,
|
|
325
|
+
cookies,
|
|
326
|
+
pairs
|
|
327
|
+
};
|
|
327
328
|
}
|
|
328
329
|
async function registerPush(client, subscription) {
|
|
329
|
-
const api = new NotificationApi(client.config);
|
|
330
330
|
const path = "/1.1/notifications/settings/login.json";
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
331
|
+
const pair = client.pairs[Math.floor(Math.random() * client.pairs.length)];
|
|
332
|
+
const tid = await generateTransactionId("POST", path, pair.verification, pair.animationKey);
|
|
333
|
+
const res = await fetch(`https://x.com/i/api${path}`, {
|
|
334
|
+
method: "POST",
|
|
335
|
+
headers: {
|
|
336
|
+
...client.headers,
|
|
337
|
+
cookie: encodeCookies(client.cookies),
|
|
338
|
+
"content-type": "application/json",
|
|
339
|
+
"x-client-transaction-id": tid
|
|
340
|
+
},
|
|
341
|
+
body: JSON.stringify({ push_device_info: {
|
|
342
|
+
os_version: "Web/Chrome",
|
|
343
|
+
udid: "Web/Chrome",
|
|
344
|
+
env: 3,
|
|
345
|
+
locale: "en",
|
|
346
|
+
protocol_version: 1,
|
|
347
|
+
token: subscription.endpoint,
|
|
348
|
+
encryption_key1: subscription.p256dh,
|
|
349
|
+
encryption_key2: subscription.auth
|
|
350
|
+
} })
|
|
351
|
+
});
|
|
341
352
|
if (!res.ok) {
|
|
342
353
|
const text = await res.text();
|
|
343
354
|
throw new Error(`login.json failed (${res.status}): ${text}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xnotif",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Receive Twitter/X push notifications programmatically via Mozilla Autopush",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"autopush",
|
|
@@ -30,10 +30,7 @@
|
|
|
30
30
|
"import": "./dist/index.mjs"
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
|
-
"dependencies": {
|
|
34
|
-
"twitter-openapi-typescript": "^0.0.55",
|
|
35
|
-
"twitter-openapi-typescript-generated": "^0.0.38"
|
|
36
|
-
},
|
|
33
|
+
"dependencies": {},
|
|
37
34
|
"devDependencies": {
|
|
38
35
|
"@types/node": "^22.0.0",
|
|
39
36
|
"@vitest/coverage-v8": "^4.0.18",
|