Skip to content

Commit 86ebc75

Browse files
committed
handle invalid urls better
1 parent e13a874 commit 86ebc75

File tree

4 files changed

+52
-29
lines changed

4 files changed

+52
-29
lines changed

src/Sitemap.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const sitemapQuery = graphql`
4141
`;
4242

4343
export async function buildSitemap({siteHostname}: {siteHostname: string}) {
44+
// eslint-disable-next-line react-hooks/rules-of-hooks
4445
const basePath = useBasePath();
4546
const smStream = new SitemapStream({hostname: `${siteHostname}`});
4647
smStream.write({url: `${basePath}/`});

src/config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export type Config = {
1111
gaTrackingId: ?string,
1212
vercelUrl: ?string,
1313
codeTheme: string,
14+
displayImageTitleAsCaption: boolean,
1415
};
1516

1617
function ensureEnv(s, variable: string): string {

src/imageProxy.js

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// @flow
2+
13
const https = require('https');
24
const PixelStream = require('pixel-stream');
35
const neuquant = require('neuquant');
@@ -6,16 +8,19 @@ const GifEncoder = require('gif-stream/encoder');
68
const inherits = require('util').inherits;
79

810
function ConcatFrames(callback) {
9-
if (!(this instanceof ConcatFrames)) return new ConcatFrames(callback);
10-
11-
PixelStream.call(this);
12-
13-
this.frame = null;
14-
this.buffers = [];
15-
this.callback = callback;
16-
17-
// put the stream in flowing mode
18-
this.resume();
11+
const concatFrames = this;
12+
if (concatFrames instanceof ConcatFrames) {
13+
PixelStream.call(concatFrames);
14+
15+
concatFrames.frame = null;
16+
concatFrames.buffers = [];
17+
concatFrames.callback = callback;
18+
19+
// put the stream in flowing mode
20+
concatFrames.resume();
21+
} else {
22+
return new ConcatFrames(callback);
23+
}
1924
}
2025

2126
inherits(ConcatFrames, PixelStream);
@@ -50,8 +55,8 @@ ConcatFrames.prototype._end = function (done) {
5055

5156
const MAX_REDIRECT_DEPTH = 5;
5257

53-
export function getWithRedirect(url, cb, depth = 1) {
54-
return https.get(url, (resp) => {
58+
export function getWithRedirect(url: URL, cb: any, depth: number = 1) {
59+
return https.get(url.toString(), (resp) => {
5560
if (
5661
resp.statusCode > 300 &&
5762
resp.statusCode < 400 &&
@@ -79,15 +84,20 @@ function padBase64String(input: string): string {
7984
return `${input}${pad}`;
8085
}
8186

82-
function decodeUrl(base64Url) {
83-
return Buffer.from(
84-
padBase64String(base64Url).replace(/-/g, '+').replace(/_/g, '/'),
85-
'base64',
86-
).toString('utf-8');
87+
function decodeUrl(base64Url: string): URL | Error {
88+
try {
89+
const url = Buffer.from(
90+
padBase64String(base64Url).replace(/-/g, '+').replace(/_/g, '/'),
91+
'base64',
92+
).toString('utf-8');
93+
return new URL(url);
94+
} catch (e) {
95+
return e;
96+
}
8797
}
8898

89-
function isGitHubUrl(url: string): boolean {
90-
const host = new URL(url).host;
99+
function isGitHubUrl(url: URL): boolean {
100+
const host = url.host;
91101
const parts = host.split('.');
92102
return (
93103
parts.length >= 2 &&
@@ -97,7 +107,7 @@ function isGitHubUrl(url: string): boolean {
97107
}
98108

99109
// workaround for netlify (res.redirect is broken)
100-
function redirect(res, statusOrUrl, url) {
110+
function redirect(res, statusOrUrl: string | number, url?: ?string) {
101111
if (typeof statusOrUrl === 'string') {
102112
url = statusOrUrl;
103113
statusOrUrl = 307;
@@ -112,12 +122,18 @@ function redirect(res, statusOrUrl, url) {
112122
return res;
113123
}
114124

115-
export const firstFrame = (req, res) => {
125+
export const firstFrame = (req: any, res: any) => {
116126
const url = decodeUrl(req.params.base64Url);
117127

128+
if (url instanceof Error) {
129+
res.status(400);
130+
res.send('Invalid URL.');
131+
return;
132+
}
133+
118134
if (!isGitHubUrl(url)) {
119-
console.warn('Non-GitHub url, redirecting', url);
120-
redirect(res, url);
135+
console.warn('Non-GitHub url, redirecting', url.toString());
136+
redirect(res, url.toString());
121137
return;
122138
}
123139

@@ -141,10 +157,10 @@ export const firstFrame = (req, res) => {
141157
});
142158
};
143159

144-
export const proxyImage = (res, url) => {
160+
export const proxyImage = (res: any, url: URL): any => {
145161
if (!isGitHubUrl(url)) {
146-
console.warn('Non-GitHub url, redirecting', url);
147-
redirect(res, url);
162+
console.warn('Non-GitHub url, redirecting', url.toString());
163+
redirect(res, url.toString());
148164
return;
149165
}
150166

@@ -158,7 +174,7 @@ export const proxyImage = (res, url) => {
158174
}
159175
if (contentLength && contentLength >= 4500000) {
160176
// Lambda can't handle anything larger than 5mb, so we'll redirect to the original url instead
161-
redirect(res, url);
177+
redirect(res, url.toString());
162178
} else {
163179
res.status(resp.statusCode);
164180
for (const k of Object.keys(resp.headers)) {
@@ -185,8 +201,13 @@ export const proxyImage = (res, url) => {
185201
});
186202
};
187203

188-
export const imageProxy = async (req, res) => {
204+
export const imageProxy = async (req: any, res: any) => {
189205
const url = decodeUrl(req.params.base64Url);
206+
if (url instanceof Error) {
207+
res.status(400);
208+
res.send('Invalid URL.');
209+
return;
210+
}
190211
await proxyImage(res, url);
191212
return;
192213
};

src/ogImage.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ export const ogImage = async (req: any, res: any) => {
132132
if (bodyImage.type === 'code') {
133133
return await respondWithCodeImage(res, bodyImage);
134134
} else if (bodyImage.type === 'url') {
135-
return await proxyImage(res, bodyImage.url);
135+
return await proxyImage(res, new URL(bodyImage.url));
136136
}
137137
} else {
138138
const avatarUrl = issue?.assignees?.nodes?.[0]?.avatarUrl;

0 commit comments

Comments
 (0)