security: check schema for URL previews

Changelog: Fixed
This commit is contained in:
Johann150 2023-02-10 20:01:57 +01:00
parent 48fd543d0f
commit 27b912b9b0
Signed by untrusted user: Johann150
GPG key ID: 9EE6577A2A06F8F1
3 changed files with 19 additions and 9 deletions

View file

@ -38,6 +38,14 @@ export const urlPreviewHandler = async (ctx: Koa.Context): Promise<void> => {
logger.succ(`Got preview of ${url}: ${summary.title}`);
if (summary.url && !(summary.url.startsWith('http://') || summary.url.startsWith('https://'))) {
throw new Error('unsupported schema included');
}
if (summary.player?.url && !(summary.player.url.startsWith('http://') || summary.player.url.startsWith('https://'))) {
throw new Error('unsupported schema included');
}
summary.icon = wrap(summary.icon);
summary.thumbnail = wrap(summary.thumbnail);
@ -54,12 +62,10 @@ export const urlPreviewHandler = async (ctx: Koa.Context): Promise<void> => {
};
function wrap(url?: string): string | null {
return url != null
? url.match(/^https?:\/\//)
? `${config.url}/proxy/preview.webp?${query({
url,
preview: '1',
})}`
: url
: null;
if (url == null) return null;
if (!['http:', 'https:'].includes(new URL(url).protocol)) return null;
return config.url + '/proxy/preview.webp?' + query({
url,
preview: '1',
});
}

View file

@ -35,6 +35,7 @@ const props = withDefaults(defineProps<{
const self = props.url.startsWith(local);
const uri = new URL(props.url);
if (!['http:', 'https:'].includes(url.protocol)) throw new Error('invalid url');
let el: HTMLElement | null = $ref(null);
let schema = $ref(uri.protocol);

View file

@ -54,6 +54,7 @@ let player = $ref({
let playerEnabled = $ref(false);
const requestUrl = new URL(props.url);
if(!['http:', 'https:].includes(requestUrl.protocol)) throw new Error('invalid url');
if (requestUrl.hostname === 'music.youtube.com' && requestUrl.pathname.match('^/(?:watch|channel)')) {
requestUrl.hostname = 'www.youtube.com';
@ -72,7 +73,9 @@ fetch(`/url?url=${encodeURIComponent(requestUrl.href)}&lang=${requestLang}`).the
icon = info.icon;
sitename = info.sitename;
fetching = false;
player = info.player;
if (['http:', 'https:'].includes(new URL(info.player.url).protocol)) {
player = info.player;
}
});
});
</script>