Guest token caching (doesn't seem to work?)

This commit is contained in:
dangered wolf 2022-07-18 19:53:01 -04:00
parent 66147807ac
commit 1a84aff39f
No known key found for this signature in database
GPG key ID: 41E4D37680ED8B58
5 changed files with 53 additions and 15 deletions

View file

@ -45,8 +45,9 @@ export const Constants = {
'allow': 'OPTIONS, GET, PURGE, HEAD', 'allow': 'OPTIONS, GET, PURGE, HEAD',
'content-type': 'text/html;charset=UTF-8', 'content-type': 'text/html;charset=UTF-8',
'x-powered-by': '🏳️‍⚧️ Trans Rights', 'x-powered-by': '🏳️‍⚧️ Trans Rights',
'cache-control': 'max-age=3600' 'cache-control': 'max-age=3600' // Can be overriden in some cases, like poll tweets
}, },
POLL_TWEET_CACHE: 'max-age=60',
DEFAULT_COLOR: '#10A3FF', DEFAULT_COLOR: '#10A3FF',
ROBOTS_TXT: `User-agent: * ROBOTS_TXT: `User-agent: *
Allow: /$ Allow: /$

View file

@ -1,7 +1,28 @@
import { Constants } from './constants'; import { Constants } from './constants';
export const fetchUsingGuest = async (status: string): Promise<TimelineBlobPartial> => { export const fetchUsingGuest = async (status: string, event: FetchEvent): Promise<TimelineBlobPartial> => {
let apiAttempts = 0; let apiAttempts = 0;
let cachedTokenFailed = false;
const tokenHeaders: { [header: string]: string } = {
Authorization: Constants.GUEST_BEARER_TOKEN,
...Constants.BASE_HEADERS
};
const guestTokenRequest = new Request(
`${Constants.TWITTER_API_ROOT}/1.1/guest/activate.json`,
{
method: 'POST',
headers: tokenHeaders,
cf: {
cacheEverything: true,
cacheTtl: 600
},
body: ''
}
);
const cache = caches.default;
while (apiAttempts < 10) { while (apiAttempts < 10) {
const csrfToken = crypto.randomUUID().replace(/-/g, ''); // Generate a random CSRF token, this doesn't matter, Twitter just cares that header and cookie match const csrfToken = crypto.randomUUID().replace(/-/g, ''); // Generate a random CSRF token, this doesn't matter, Twitter just cares that header and cookie match
@ -13,19 +34,28 @@ export const fetchUsingGuest = async (status: string): Promise<TimelineBlobParti
apiAttempts++; apiAttempts++;
let activate: Response | null = null;
if (!cachedTokenFailed) {
let cachedResponse = await cache.match(guestTokenRequest);
if (cachedResponse) {
console.log('Token cache hit');
activate = cachedResponse;
}
console.log('Token cache miss');
cachedTokenFailed = true;
}
if (cachedTokenFailed || activate === null) {
/* If all goes according to plan, we have a guest token we can use to call API /* If all goes according to plan, we have a guest token we can use to call API
AFAIK there is no limit to how many guest tokens you can request. AFAIK there is no limit to how many guest tokens you can request.
This can effectively mean virtually unlimited (read) access to Twitter's API, This can effectively mean virtually unlimited (read) access to Twitter's API,
which is very funny. */ which is very funny. */
const activate = await fetch( activate = await fetch(guestTokenRequest);
`${Constants.TWITTER_API_ROOT}/1.1/guest/activate.json`,
{
method: 'POST',
headers: headers,
body: ''
} }
);
/* Let's grab that guest_token so we can use it */ /* Let's grab that guest_token so we can use it */
let activateJson: { guest_token: string }; let activateJson: { guest_token: string };
@ -71,6 +101,7 @@ export const fetchUsingGuest = async (status: string): Promise<TimelineBlobParti
/* We'll usually only hit this if we get an invalid response from Twitter. /* We'll usually only hit this if we get an invalid response from Twitter.
It's rare, but it happens */ It's rare, but it happens */
console.error('Unknown error while fetching conversation from API'); console.error('Unknown error while fetching conversation from API');
cachedTokenFailed = true;
continue; continue;
} }
@ -80,9 +111,13 @@ export const fetchUsingGuest = async (status: string): Promise<TimelineBlobParti
conversation.errors?.[0]?.code === 239) conversation.errors?.[0]?.code === 239)
) { ) {
console.log('Failed to fetch conversation, got', conversation); console.log('Failed to fetch conversation, got', conversation);
cachedTokenFailed = true;
continue; continue;
} }
/* Once we've confirmed we have a working guest token, let's cache it! */
// event.waitUntil(cache.put(guestTokenRequest, activate.clone()));
return conversation; return conversation;
} }

View file

@ -2,7 +2,7 @@ import { linkFixer } from './linkFixer';
import { Strings } from './strings'; import { Strings } from './strings';
export const handleQuote = (quote: TweetPartial): string | null => { export const handleQuote = (quote: TweetPartial): string | null => {
console.log('quote tweet: ', quote); console.log('Quoting status ', quote.id_str);
let str = `\n`; let str = `\n`;
str += Strings.QUOTE_TEXT.format({ str += Strings.QUOTE_TEXT.format({

View file

@ -26,6 +26,7 @@ const statusRequest = async (request: any, event: FetchEvent, flags: InputFlags
let response: Response; let response: Response;
let statusResponse = await handleStatus( let statusResponse = await handleStatus(
event,
id.match(/\d{2,20}/)?.[0], id.match(/\d{2,20}/)?.[0],
parseInt(mediaNumber || 1), parseInt(mediaNumber || 1),
userAgent, userAgent,

View file

@ -20,13 +20,14 @@ export const returnError = (error: string): StatusResponse => {
}; };
export const handleStatus = async ( export const handleStatus = async (
event: FetchEvent,
status: string, status: string,
mediaNumber?: number, mediaNumber?: number,
userAgent?: string, userAgent?: string,
flags?: InputFlags flags?: InputFlags
): Promise<StatusResponse> => { ): Promise<StatusResponse> => {
console.log('Direct?', flags?.direct); console.log('Direct?', flags?.direct);
const conversation = await fetchUsingGuest(status); const conversation = await fetchUsingGuest(status, event);
const tweet = conversation?.globalObjects?.tweets?.[status] || {}; const tweet = conversation?.globalObjects?.tweets?.[status] || {};
/* With v2 conversation API we re-add the user object ot the tweet because /* With v2 conversation API we re-add the user object ot the tweet because