Bluesky app fork with some witchin' additions 馃挮
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 95 lines 3.2 kB view raw
1import assert from 'node:assert' 2 3import {DAY, SECOND} from '@atproto/common' 4import {type Express} from 'express' 5 6import {type AppContext} from '../context.js' 7import {linkRedirectContents} from '../html/linkRedirectContents.js' 8import {linkWarningContents} from '../html/linkWarningContents.js' 9import {linkWarningLayout} from '../html/linkWarningLayout.js' 10import {redirectLogger} from '../logger.js' 11import {handler} from './util.js' 12 13const INTERNAL_IP_REGEX = new RegExp( 14 '(^127.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$)|(^10.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$)|(^172.1[6-9]{1}[0-9]{0,1}.[0-9]{1,3}.[0-9]{1,3}$)|(^172.2[0-9]{1}[0-9]{0,1}.[0-9]{1,3}.[0-9]{1,3}$)|(^172.3[0-1]{1}[0-9]{0,1}.[0-9]{1,3}.[0-9]{1,3}$)|(^192.168.[0-9]{1,3}.[0-9]{1,3}$)|^localhost', 15 'i', 16) 17 18export default function (ctx: AppContext, app: Express) { 19 return app.get( 20 '/redirect', 21 handler(async (req, res) => { 22 let link = req.query.u 23 assert( 24 typeof link === 'string', 25 'express guarantees link query parameter is a string', 26 ) 27 28 let url: URL | undefined 29 try { 30 url = new URL(link) 31 } catch {} 32 33 if ( 34 !url || 35 (url.protocol !== 'http:' && url.protocol !== 'https:') || // is a http(s) url 36 (ctx.cfg.service.hostnames.includes(url.hostname.toLowerCase()) && 37 url.pathname === '/redirect') || // is a redirect loop 38 INTERNAL_IP_REGEX.test(url.hostname) // isn't directing to an internal location 39 ) { 40 res.setHeader('Cache-Control', 'no-store') 41 res.setHeader('Location', `https://${ctx.cfg.service.appHostname}`) 42 return res.status(302).end() 43 } 44 45 // Default to a max age header 46 res.setHeader('Cache-Control', `max-age=${(7 * DAY) / SECOND}`) 47 res.status(200) 48 res.type('html') 49 50 let html: string | undefined 51 52 if (ctx.cfg.service.safelinkEnabled) { 53 const rule = await ctx.safelinkClient.tryFindRule(link) 54 if (rule !== 'ok') { 55 switch (rule.action) { 56 case 'whitelist': 57 redirectLogger.info({rule}, 'Whitelist rule matched') 58 break 59 case 'block': 60 html = linkWarningLayout( 61 'Blocked Link Warning', 62 linkWarningContents(req, { 63 type: 'block', 64 link: url.href, 65 }), 66 ) 67 res.setHeader('Cache-Control', 'no-store') 68 redirectLogger.info({rule}, 'Block rule matched') 69 break 70 case 'warn': 71 html = linkWarningLayout( 72 'Malicious Link Warning', 73 linkWarningContents(req, { 74 type: 'warn', 75 link: url.href, 76 }), 77 ) 78 res.setHeader('Cache-Control', 'no-store') 79 redirectLogger.info({rule}, 'Warn rule matched') 80 break 81 default: 82 redirectLogger.warn({rule}, 'Unknown rule matched') 83 } 84 } 85 } 86 87 // If there is no html defined yet, we will create a redirect html 88 if (!html) { 89 html = linkRedirectContents(url.href) 90 } 91 92 return res.end(html) 93 }), 94 ) 95}