mirror of
https://github.com/CompeyDev/fxtwitter-docker.git
synced 2025-04-06 19:10:54 +01:00
Run prettier
This commit is contained in:
parent
85eb2cead1
commit
b5ee1b8fe7
14 changed files with 131 additions and 91 deletions
|
@ -63,17 +63,17 @@ export const cacheMiddleware = (): MiddlewareHandler => async (c, next) => {
|
|||
case 'DELETE':
|
||||
console.log('Purging cache as requested');
|
||||
await cache.delete(cacheKey);
|
||||
return c.text('')
|
||||
return c.text('');
|
||||
/* yes, we do give HEAD */
|
||||
case 'HEAD':
|
||||
return c.text('')
|
||||
return c.text('');
|
||||
/* We properly state our OPTIONS when asked */
|
||||
case 'OPTIONS':
|
||||
c.header('allow', Constants.RESPONSE_HEADERS.allow)
|
||||
c.status(204)
|
||||
c.header('allow', Constants.RESPONSE_HEADERS.allow);
|
||||
c.status(204);
|
||||
return c.text('');
|
||||
default:
|
||||
c.status(405);
|
||||
return c.text('')
|
||||
return c.text('');
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -10,13 +10,15 @@ import { constructTwitterThread } from '../providers/twitter/conversation';
|
|||
import { Context } from 'hono';
|
||||
|
||||
export const returnError = (c: Context, error: string): Response => {
|
||||
return c.text(Strings.BASE_HTML.format({
|
||||
lang: '',
|
||||
headers: [
|
||||
`<meta property="og:title" content="${Constants.BRANDING_NAME}"/>`,
|
||||
`<meta property="og:description" content="${error}"/>`
|
||||
].join('')
|
||||
}));
|
||||
return c.text(
|
||||
Strings.BASE_HTML.format({
|
||||
lang: '',
|
||||
headers: [
|
||||
`<meta property="og:title" content="${Constants.BRANDING_NAME}"/>`,
|
||||
`<meta property="og:description" content="${error}"/>`
|
||||
].join('')
|
||||
})
|
||||
);
|
||||
};
|
||||
/* Handler for Twitter statuses (Tweets).
|
||||
Like Twitter, we use the terminologies interchangably. */
|
||||
|
@ -26,7 +28,7 @@ export const handleStatus = async (
|
|||
mediaNumber: number | undefined,
|
||||
userAgent: string,
|
||||
flags: InputFlags,
|
||||
language: string,
|
||||
language: string
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
): Promise<Response> => {
|
||||
console.log('Direct?', flags?.direct);
|
||||
|
@ -423,9 +425,11 @@ export const handleStatus = async (
|
|||
const lang = tweet.lang === null ? 'en' : tweet.lang || 'en';
|
||||
|
||||
/* Finally, after all that work we return the response HTML! */
|
||||
return c.html(Strings.BASE_HTML.format({
|
||||
lang: `lang="${lang}"`,
|
||||
headers: headers.join(''),
|
||||
body: ivbody
|
||||
}).replace(/>(\s+)</gm, '><'));
|
||||
return c.html(
|
||||
Strings.BASE_HTML.format({
|
||||
lang: `lang="${lang}"`,
|
||||
headers: headers.join(''),
|
||||
body: ivbody
|
||||
}).replace(/>(\s+)</gm, '><')
|
||||
);
|
||||
};
|
||||
|
|
11
src/fetch.ts
11
src/fetch.ts
|
@ -172,7 +172,9 @@ export const twitterFetch = async (
|
|||
}
|
||||
!useElongator &&
|
||||
c.executionCtx &&
|
||||
c.executionCtx.waitUntil(cache.delete(guestTokenRequestCacheDummy.clone(), { ignoreMethod: true }));
|
||||
c.executionCtx.waitUntil(
|
||||
cache.delete(guestTokenRequestCacheDummy.clone(), { ignoreMethod: true })
|
||||
);
|
||||
if (useElongator) {
|
||||
console.log('Elongator request failed, trying again without it');
|
||||
wasElongatorDisabled = true;
|
||||
|
@ -202,7 +204,9 @@ export const twitterFetch = async (
|
|||
if (!useElongator && remainingRateLimit < 10) {
|
||||
console.log(`Purging token on this edge due to low rate limit remaining`);
|
||||
c.executionCtx &&
|
||||
c.executionCtx.waitUntil(cache.delete(guestTokenRequestCacheDummy.clone(), { ignoreMethod: true }));
|
||||
c.executionCtx.waitUntil(
|
||||
cache.delete(guestTokenRequestCacheDummy.clone(), { ignoreMethod: true })
|
||||
);
|
||||
}
|
||||
|
||||
if (!validateFunction(response)) {
|
||||
|
@ -250,7 +254,8 @@ export const fetchUser = async (
|
|||
typeof c.env.TwitterProxy !== 'undefined'
|
||||
)
|
||||
): Promise<GraphQLUserResponse> => {
|
||||
return (await twitterFetch(c,
|
||||
return (await twitterFetch(
|
||||
c,
|
||||
`${
|
||||
Constants.TWITTER_ROOT
|
||||
}/i/api/graphql/sLVLhk0bGj3MVFEKTdax1w/UserByScreenName?variables=${encodeURIComponent(
|
||||
|
|
|
@ -11,7 +11,8 @@ export const fetchTweetDetail = async (
|
|||
useElongator = typeof c.env.TwitterProxy !== 'undefined',
|
||||
cursor: string | null = null
|
||||
): Promise<TweetDetailResult> => {
|
||||
return (await twitterFetch(c,
|
||||
return (await twitterFetch(
|
||||
c,
|
||||
`${
|
||||
Constants.TWITTER_ROOT
|
||||
}/i/api/graphql/7xdlmKfKUJQP7D7woCL5CA/TweetDetail?variables=${encodeURIComponent(
|
||||
|
@ -95,7 +96,8 @@ export const fetchByRestId = async (
|
|||
typeof c.env.TwitterProxy !== 'undefined'
|
||||
)
|
||||
): Promise<TweetResultsByRestIdResult> => {
|
||||
return (await twitterFetch(c,
|
||||
return (await twitterFetch(
|
||||
c,
|
||||
`${
|
||||
Constants.TWITTER_ROOT
|
||||
}/i/api/graphql/2ICDjqPd81tulZcYrtpTuQ/TweetResultByRestId?variables=${encodeURIComponent(
|
||||
|
|
|
@ -14,7 +14,7 @@ export const buildAPITweet = async (
|
|||
tweet: GraphQLTweet,
|
||||
language: string | undefined,
|
||||
threadPiece = false,
|
||||
legacyAPI = false,
|
||||
legacyAPI = false
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
): Promise<APITweet | FetchResults | null> => {
|
||||
const apiTweet = {} as APITweet;
|
||||
|
|
|
@ -11,7 +11,6 @@ api.get('/status/:id/:language?', statusRequest);
|
|||
api.get('/:handle/status/:id/:language?', statusRequest);
|
||||
|
||||
api.get('/:handle', profileRequest);
|
||||
api.get('/robots.txt', async (c) => c.text(Strings.ROBOTS_TXT));
|
||||
api.get('/robots.txt', async c => c.text(Strings.ROBOTS_TXT));
|
||||
|
||||
|
||||
api.all('*', async (c) => c.redirect(Constants.API_DOCS_URL, 302));
|
||||
api.all('*', async c => c.redirect(Constants.API_DOCS_URL, 302));
|
||||
|
|
|
@ -5,16 +5,18 @@ import { Strings } from '../../strings';
|
|||
export const versionRoute = async (c: Context) => {
|
||||
c.header('cache-control', 'max-age=0, no-cache, no-store, must-revalidate');
|
||||
const req = c.req;
|
||||
return c.html(Strings.VERSION_HTML.format({
|
||||
rtt: req.raw.cf?.clientTcpRtt ? `🏓 ${req.raw.cf.clientTcpRtt} ms RTT` : '',
|
||||
colo: (req.raw.cf?.colo as string) ?? '??',
|
||||
httpversion: (req.raw.cf?.httpProtocol as string) ?? 'Unknown HTTP Version',
|
||||
tlsversion: (req.raw.cf?.tlsVersion as string) ?? 'Unknown TLS Version',
|
||||
ip: req.header('x-real-ip') ?? req.header('cf-connecting-ip') ?? 'Unknown IP',
|
||||
city: (req.raw.cf?.city as string) ?? 'Unknown City',
|
||||
region: (req.raw.cf?.region as string) ?? req.raw.cf?.country ?? 'Unknown Region',
|
||||
country: (req.raw.cf?.country as string) ?? 'Unknown Country',
|
||||
asn: `AS${req.raw.cf?.asn ?? '??'} (${req.raw.cf?.asOrganization ?? 'Unknown ASN'})`,
|
||||
ua: sanitizeText(req.header('user-agent') ?? 'Unknown User Agent')
|
||||
}))
|
||||
return c.html(
|
||||
Strings.VERSION_HTML.format({
|
||||
rtt: req.raw.cf?.clientTcpRtt ? `🏓 ${req.raw.cf.clientTcpRtt} ms RTT` : '',
|
||||
colo: (req.raw.cf?.colo as string) ?? '??',
|
||||
httpversion: (req.raw.cf?.httpProtocol as string) ?? 'Unknown HTTP Version',
|
||||
tlsversion: (req.raw.cf?.tlsVersion as string) ?? 'Unknown TLS Version',
|
||||
ip: req.header('x-real-ip') ?? req.header('cf-connecting-ip') ?? 'Unknown IP',
|
||||
city: (req.raw.cf?.city as string) ?? 'Unknown City',
|
||||
region: (req.raw.cf?.region as string) ?? req.raw.cf?.country ?? 'Unknown Region',
|
||||
country: (req.raw.cf?.country as string) ?? 'Unknown Country',
|
||||
asn: `AS${req.raw.cf?.asn ?? '??'} (${req.raw.cf?.asOrganization ?? 'Unknown ASN'})`,
|
||||
ua: sanitizeText(req.header('user-agent') ?? 'Unknown User Agent')
|
||||
})
|
||||
);
|
||||
};
|
||||
|
|
|
@ -44,11 +44,11 @@ twitter.get('/version', versionRoute);
|
|||
twitter.get('/set_base_redirect', setRedirectRequest);
|
||||
twitter.get('/oembed', oembed);
|
||||
|
||||
twitter.get('/robots.txt', async (c) => c.text(Strings.ROBOTS_TXT));
|
||||
twitter.get('/robots.txt', async c => c.text(Strings.ROBOTS_TXT));
|
||||
|
||||
twitter.get('/i/events/:id', genericTwitterRedirect);
|
||||
twitter.get('/hashtag/:hashtag', genericTwitterRedirect);
|
||||
|
||||
twitter.get('/:handle', profileRequest);
|
||||
|
||||
twitter.all('*', async (c) => c.redirect(Constants.REDIRECT_URL, 302));
|
||||
twitter.all('*', async c => c.redirect(Constants.REDIRECT_URL, 302));
|
||||
|
|
|
@ -27,8 +27,8 @@ export const oembed = async (c: Context) => {
|
|||
type: 'link',
|
||||
version: '1.0'
|
||||
};
|
||||
c.header('content-type', 'application/json')
|
||||
c.header('content-type', 'application/json');
|
||||
c.status(200);
|
||||
/* Stringify and send it on its way! */
|
||||
return c.text(JSON.stringify(test))
|
||||
return c.text(JSON.stringify(test));
|
||||
};
|
||||
|
|
|
@ -38,7 +38,7 @@ export const profileRequest = async (c: Context) => {
|
|||
|
||||
/* Do not cache if using a custom redirect */
|
||||
const cacheControl = baseUrl !== Constants.TWITTER_ROOT ? 'max-age=0' : undefined;
|
||||
|
||||
|
||||
if (cacheControl) {
|
||||
c.header('cache-control', cacheControl);
|
||||
}
|
||||
|
@ -65,6 +65,6 @@ export const profileRequest = async (c: Context) => {
|
|||
Obviously we just need to redirect to the user directly.*/
|
||||
console.log('Matched human UA', userAgent);
|
||||
|
||||
return c.redirect(`${baseUrl}/${handle}`, 302)
|
||||
return c.redirect(`${baseUrl}/${handle}`, 302);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -13,7 +13,7 @@ export const genericTwitterRedirect = async (c: Context) => {
|
|||
if (cacheControl) {
|
||||
c.header('cache-control', cacheControl);
|
||||
}
|
||||
|
||||
|
||||
return c.redirect(`${baseUrl}${url.pathname}`, 302);
|
||||
};
|
||||
|
||||
|
@ -27,22 +27,31 @@ export const setRedirectRequest = async (c: Context) => {
|
|||
if (origin && !Constants.STANDARD_DOMAIN_LIST.includes(new URL(origin).hostname)) {
|
||||
c.status(403);
|
||||
|
||||
return c.html(Strings.MESSAGE_HTML.format({
|
||||
message: `Failed to set base redirect: Your request seems to be originating from another domain, please open this up in a new tab if you are trying to set your base redirect.`
|
||||
}))
|
||||
return c.html(
|
||||
Strings.MESSAGE_HTML.format({
|
||||
message: `Failed to set base redirect: Your request seems to be originating from another domain, please open this up in a new tab if you are trying to set your base redirect.`
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
|
||||
/* Remove redirect URL */
|
||||
// eslint-disable-next-line sonarjs/no-duplicate-string
|
||||
c.header('set-cookie', `base_redirect=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT; secure; HttpOnly`);
|
||||
c.header(
|
||||
'set-cookie',
|
||||
`base_redirect=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT; secure; HttpOnly`
|
||||
);
|
||||
// eslint-disable-next-line sonarjs/no-duplicate-string
|
||||
c.header('content-security-policy', `frame-ancestors ${Constants.STANDARD_DOMAIN_LIST.join(' ')};`);
|
||||
c.header(
|
||||
'content-security-policy',
|
||||
`frame-ancestors ${Constants.STANDARD_DOMAIN_LIST.join(' ')};`
|
||||
);
|
||||
c.status(200);
|
||||
return c.html(Strings.MESSAGE_HTML.format({
|
||||
message: `Your base redirect has been cleared. To set one, please pass along the <code>url</code> parameter.`
|
||||
}))
|
||||
return c.html(
|
||||
Strings.MESSAGE_HTML.format({
|
||||
message: `Your base redirect has been cleared. To set one, please pass along the <code>url</code> parameter.`
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -54,21 +63,36 @@ export const setRedirectRequest = async (c: Context) => {
|
|||
/* URL is not well-formed, remove */
|
||||
console.log('Invalid base redirect URL, removing cookie before redirect');
|
||||
|
||||
c.header('set-cookie', `base_redirect=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT; secure; HttpOnly`);
|
||||
c.header('content-security-policy', `frame-ancestors ${Constants.STANDARD_DOMAIN_LIST.join(' ')};`);
|
||||
c.header(
|
||||
'set-cookie',
|
||||
`base_redirect=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT; secure; HttpOnly`
|
||||
);
|
||||
c.header(
|
||||
'content-security-policy',
|
||||
`frame-ancestors ${Constants.STANDARD_DOMAIN_LIST.join(' ')};`
|
||||
);
|
||||
c.status(200);
|
||||
return c.html(Strings.MESSAGE_HTML.format({
|
||||
message: `Your URL does not appear to be well-formed. Example: ?url=https://nitter.net`
|
||||
}))
|
||||
return c.html(
|
||||
Strings.MESSAGE_HTML.format({
|
||||
message: `Your URL does not appear to be well-formed. Example: ?url=https://nitter.net`
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
url = `https://${url}`;
|
||||
}
|
||||
|
||||
c.header('set-cookie', `base_redirect=${url}; path=/; max-age=63072000; secure; HttpOnly`);
|
||||
c.header('content-security-policy', `frame-ancestors ${Constants.STANDARD_DOMAIN_LIST.join(' ')};`);
|
||||
c.header(
|
||||
'content-security-policy',
|
||||
`frame-ancestors ${Constants.STANDARD_DOMAIN_LIST.join(' ')};`
|
||||
);
|
||||
|
||||
return c.html(Strings.MESSAGE_HTML.format({
|
||||
message: `Successfully set base redirect, you will now be redirected to ${sanitizeText(url)} rather than ${Constants.TWITTER_ROOT}`
|
||||
}))
|
||||
return c.html(
|
||||
Strings.MESSAGE_HTML.format({
|
||||
message: `Successfully set base redirect, you will now be redirected to ${sanitizeText(
|
||||
url
|
||||
)} rather than ${Constants.TWITTER_ROOT}`
|
||||
})
|
||||
);
|
||||
};
|
||||
|
|
|
@ -101,7 +101,8 @@ export const statusRequest = async (c: Context) => {
|
|||
}
|
||||
|
||||
/* This throws the necessary data to handleStatus (in status.ts) */
|
||||
const statusResponse = await handleStatus(c,
|
||||
const statusResponse = await handleStatus(
|
||||
c,
|
||||
id?.match(/\d{2,20}/)?.[0] || '0',
|
||||
mediaNumber ? parseInt(mediaNumber) : undefined,
|
||||
userAgent,
|
||||
|
@ -124,7 +125,7 @@ export const statusRequest = async (c: Context) => {
|
|||
Embeds will return as usual to bots as if direct media was never specified. */
|
||||
if (!isBotUA && !flags.api) {
|
||||
const baseUrl = getBaseRedirectUrl(c);
|
||||
|
||||
|
||||
return c.redirect(`${baseUrl}/${handle || 'i'}/status/${id}`, 302);
|
||||
}
|
||||
|
||||
|
|
28
src/user.ts
28
src/user.ts
|
@ -4,20 +4,22 @@ import { Strings } from './strings';
|
|||
import { userAPI } from './providers/twitter/profile';
|
||||
|
||||
export const returnError = (c: Context, error: string): Response => {
|
||||
return c.html(Strings.BASE_HTML.format({
|
||||
lang: '',
|
||||
headers: [
|
||||
`<meta property="og:title" content="${Constants.BRANDING_NAME}"/>`,
|
||||
`<meta property="og:description" content="${error}"/>`
|
||||
].join('')
|
||||
}));
|
||||
return c.html(
|
||||
Strings.BASE_HTML.format({
|
||||
lang: '',
|
||||
headers: [
|
||||
`<meta property="og:title" content="${Constants.BRANDING_NAME}"/>`,
|
||||
`<meta property="og:description" content="${error}"/>`
|
||||
].join('')
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
/* Handler for Twitter users */
|
||||
export const handleProfile = async (
|
||||
c: Context,
|
||||
username: string,
|
||||
flags: InputFlags,
|
||||
flags: InputFlags
|
||||
): Promise<Response> => {
|
||||
console.log('Direct?', flags?.direct);
|
||||
|
||||
|
@ -51,8 +53,10 @@ export const handleProfile = async (
|
|||
// TODO Add card creation logic here
|
||||
|
||||
/* Finally, after all that work we return the response HTML! */
|
||||
return c.html(Strings.BASE_HTML.format({
|
||||
lang: `lang="en"`,
|
||||
headers: headers.join('')
|
||||
}));
|
||||
return c.html(
|
||||
Strings.BASE_HTML.format({
|
||||
lang: `lang="en"`,
|
||||
headers: headers.join('')
|
||||
})
|
||||
);
|
||||
};
|
||||
|
|
|
@ -11,7 +11,9 @@ import { cacheMiddleware } from './caches';
|
|||
|
||||
const noCache = 'max-age=0, no-cache, no-store, must-revalidate';
|
||||
|
||||
const app = new Hono<{ Bindings: { TwitterProxy: Fetcher; AnalyticsEngine: AnalyticsEngineDataset } }>({
|
||||
const app = new Hono<{
|
||||
Bindings: { TwitterProxy: Fetcher; AnalyticsEngine: AnalyticsEngineDataset };
|
||||
}>({
|
||||
getPath: req => {
|
||||
let url: URL;
|
||||
|
||||
|
@ -27,7 +29,7 @@ const app = new Hono<{ Bindings: { TwitterProxy: Fetcher; AnalyticsEngine: Analy
|
|||
realm = 'api';
|
||||
console.log('API realm');
|
||||
} else if (Constants.STANDARD_DOMAIN_LIST.includes(baseHostName)) {
|
||||
console.log()
|
||||
console.log();
|
||||
realm = 'twitter';
|
||||
console.log('Twitter realm');
|
||||
} else {
|
||||
|
@ -71,7 +73,7 @@ app.onError((err, c) => {
|
|||
return c.html(Strings.ERROR_HTML);
|
||||
});
|
||||
|
||||
const customLogger = (message: string, ...rest: string[]) => {
|
||||
const customLogger = (message: string, ...rest: string[]) => {
|
||||
console.log(message, ...rest);
|
||||
};
|
||||
|
||||
|
@ -89,14 +91,11 @@ app.use('*', timing({ enabled: false }));
|
|||
app.route(`/api`, api);
|
||||
app.route(`/twitter`, twitter);
|
||||
|
||||
app.all(
|
||||
'/error',
|
||||
async (c) => {
|
||||
c.header('cache-control', noCache);
|
||||
c.status(400);
|
||||
return c.body('')
|
||||
}
|
||||
);
|
||||
app.all('/error', async c => {
|
||||
c.header('cache-control', noCache);
|
||||
c.status(400);
|
||||
return c.body('');
|
||||
});
|
||||
|
||||
export default {
|
||||
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
|
||||
|
@ -105,7 +104,7 @@ export default {
|
|||
} catch (err) {
|
||||
console.error(err);
|
||||
console.log('Ouch, that error hurt so much Sentry couldnt catch it');
|
||||
|
||||
|
||||
return new Response(Strings.ERROR_HTML, {
|
||||
headers: {
|
||||
...Constants.RESPONSE_HEADERS,
|
||||
|
|
Loading…
Add table
Reference in a new issue