From 4d8428435697e2dfd07ee8b1bbb1be81a68f4a37 Mon Sep 17 00:00:00 2001 From: Sal Rahman Date: Mon, 21 Aug 2023 21:02:36 -0700 Subject: [PATCH] Some more minor changes --- .../client/src/components/MkUrlPreview.vue | 20 +++++++------ .../client/src/components/global/MkUrl.vue | 8 ++++-- packages/client/src/const.ts | 13 +++++++++ packages/client/src/scripts/parse-uri.ts | 28 +++++++++++++++++-- packages/ffm-js/src/internal/parser.ts | 4 +-- 5 files changed, 58 insertions(+), 15 deletions(-) diff --git a/packages/client/src/components/MkUrlPreview.vue b/packages/client/src/components/MkUrlPreview.vue index 9241c49c36..3db512e148 100644 --- a/packages/client/src/components/MkUrlPreview.vue +++ b/packages/client/src/components/MkUrlPreview.vue @@ -103,6 +103,8 @@ import { onUnmounted, ref } from "vue"; import { url as local, lang } from "@/config"; import { i18n } from "@/i18n"; import { defaultStore } from "@/store"; +import { parseUri, parsedUriToString } from '@/scripts/parse-uri' +import { SCHEMA_BROWSERSAFE } from "../const"; const props = withDefaults( defineProps<{ @@ -134,30 +136,30 @@ let tweetExpanded = ref(props.detail); const embedId = `embed${Math.random().toString().replace(/\D/, "")}`; let tweetHeight = ref(150); -const requestUrl = new URL(props.url); -if (!["http:", "https:", "gopher:", "gemini:", "matrix:", "ipfs:", "ipns:", "finger:"].includes(requestUrl.protocol) && !requestUrl.protocol.startsWith("web+")) +const requestUrl = parseUri(props.url); +if (!SCHEMA_BROWSERSAFE.includes(requestUrl.scheme)) throw new Error("invalid url"); if ( - ["twitter.com", "mobile.twitter.com", "x.com"].includes(requestUrl.hostname) + ["twitter.com", "mobile.twitter.com", "x.com"].includes(requestUrl.authority ?? "") ) { - const m = requestUrl.pathname.match(/^\/.+\/status(?:es)?\/(\d+)/); + const m = (requestUrl.path ?? "").match(/^\/.+\/status(?:es)?\/(\d+)/); if (m) tweetId.value = m[1]; } if ( - requestUrl.hostname === "music.youtube.com" && - requestUrl.pathname.match("^/(?:watch|channel)") + requestUrl.authority === "music.youtube.com" && + (requestUrl.path ?? "").match("^/(?:watch|channel)") ) { - requestUrl.hostname = "www.youtube.com"; + requestUrl.authority = "www.youtube.com"; } const requestLang = (lang || "ja-JP").replace("ja-KS", "ja-JP"); -requestUrl.hash = ""; +requestUrl.fragment = ""; fetch( - `/url?url=${encodeURIComponent(requestUrl.href)}&lang=${requestLang}`, + `/url?url=${encodeURIComponent(parsedUriToString(requestUrl))}&lang=${requestLang}`, ).then((res) => { res.json().then((info) => { if (info.url == null) return; diff --git a/packages/client/src/components/global/MkUrl.vue b/packages/client/src/components/global/MkUrl.vue index e44e980054..387e610bbf 100644 --- a/packages/client/src/components/global/MkUrl.vue +++ b/packages/client/src/components/global/MkUrl.vue @@ -11,7 +11,7 @@ @click.stop > @@ -38,6 +38,7 @@ import * as os from "@/os"; import { useTooltip } from "@/scripts/use-tooltip"; import { safeURIDecode } from "@/scripts/safe-uri-decode"; import { parseUri } from "@/scripts/parse-uri" +import { SCHEMA_BROWSERSAFE } from "../../const"; const props = defineProps<{ url: string; @@ -46,7 +47,10 @@ const props = defineProps<{ const self = props.url.startsWith(local); const url = parseUri(props.url); -if (!["http", "https", "gopher", "gemini", "matrix", "ipfs", "ipns", "finger"].includes(url.scheme) && !url.scheme.startsWith("web+")) +console.log(url); +console.log(props.url); +console.log(url.scheme); +if (!SCHEMA_BROWSERSAFE.includes(url.scheme)) throw new Error("invalid url"); const el = ref(); diff --git a/packages/client/src/const.ts b/packages/client/src/const.ts index a73e09718e..7bf8865e23 100644 --- a/packages/client/src/const.ts +++ b/packages/client/src/const.ts @@ -38,6 +38,19 @@ export const FILE_TYPE_BROWSERSAFE = [ "audio/x-flac", "audio/vnd.wave", ]; + +export const SCHEMA_BROWSERSAFE = [ + "http", + "https", + "gopher", + "gemini", + "matrix", + "ipfs", + "ipns", + "icmp", + "finger" +]; + /* https://github.com/sindresorhus/file-type/blob/main/supported.js https://github.com/sindresorhus/file-type/blob/main/core.js diff --git a/packages/client/src/scripts/parse-uri.ts b/packages/client/src/scripts/parse-uri.ts index 3408c5f078..a0a9216a77 100644 --- a/packages/client/src/scripts/parse-uri.ts +++ b/packages/client/src/scripts/parse-uri.ts @@ -1,10 +1,12 @@ -export function parseUri(uri: string): { +type URI = { scheme: string; authority: string | null; path: string | null; query: string | null; fragment: string | null; -} { +} + +export function parseUri(uri: string): URI { const urlParts = uri.match( /^([\w+]+):(\/\/)?([^/?#]*)(\/([^?#]*))?(\?([^#]*))?(#(.*))?$/, ); @@ -24,3 +26,25 @@ export function parseUri(uri: string): { fragment: fragment || null, }; } + +export function parsedUriToString(uri: URI): string { + let result = `${uri.scheme}:`; + + if (uri.authority) { + result += `//${uri.authority}`; + } + + if (uri.path) { + result += uri.path; + } + + if (uri.query) { + result += `?${uri.query}`; + } + + if (uri.fragment) { + result += `#${uri.fragment}`; + } + + return result; +} diff --git a/packages/ffm-js/src/internal/parser.ts b/packages/ffm-js/src/internal/parser.ts index 3dc186c4cb..4775003d61 100644 --- a/packages/ffm-js/src/internal/parser.ts +++ b/packages/ffm-js/src/internal/parser.ts @@ -674,7 +674,7 @@ export const language = P.createLanguage({ ])); const parser = P.seq([ notLinkLabel, - P.regexp(/((https?)|(gemini)|(gopher)|(matrix)|(ipns)|(ipfs)|(finger)|(web\+\w+)):\/\//), + P.regexp(/(?:https?|gemini|gopher|matrix|ipns|ipfs|icmp|finger|cool|web\+\w+):\/\//), innerItem.many(1).text(), ]); return new P.Parser((input, index, state) => { @@ -706,7 +706,7 @@ export const language = P.createLanguage({ const parser = P.seq([ notLinkLabel, open, - P.regexp(/((https?)|(gemini)|(gopher)|(matrix)|(ipns)|(ipfs)|(finger)|(web\+\w+)):\/\//), + P.regexp(/(?:https?|gemini|gopher|matrix|ipns|ipfs|finger|cool|web\+\w+):\/\//), P.seq([P.notMatch(P.alt([close, space])), P.char], 1).many(1), close, ]).text();