mirror of
https://codeberg.org/yeentown/barkey.git
synced 2025-07-07 20:44:34 +00:00
skip resolving preview when a link is known to be recursive
This commit is contained in:
parent
38d4a7fd56
commit
dc1adcc491
7 changed files with 49 additions and 13 deletions
|
@ -236,6 +236,7 @@ import { useRouter } from '@/router.js';
|
||||||
import SkMutedNote from '@/components/SkMutedNote.vue';
|
import SkMutedNote from '@/components/SkMutedNote.vue';
|
||||||
import SkNoteTranslation from '@/components/SkNoteTranslation.vue';
|
import SkNoteTranslation from '@/components/SkNoteTranslation.vue';
|
||||||
import { getSelfNoteIds } from '@/utility/get-self-note-ids.js';
|
import { getSelfNoteIds } from '@/utility/get-self-note-ids.js';
|
||||||
|
import { extractPreviewUrls } from '@/utility/extract-preview-urls.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
note: Misskey.entities.Note;
|
note: Misskey.entities.Note;
|
||||||
|
@ -303,7 +304,7 @@ const galleryEl = useTemplateRef('galleryEl');
|
||||||
const isMyRenote = $i && ($i.id === note.value.userId);
|
const isMyRenote = $i && ($i.id === note.value.userId);
|
||||||
const showContent = ref(prefer.s.uncollapseCW);
|
const showContent = ref(prefer.s.uncollapseCW);
|
||||||
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : null);
|
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : null);
|
||||||
const urls = computed(() => parsed.value ? extractUrlFromMfm(parsed.value).filter((url) => appearNote.value.renote?.url !== url && appearNote.value.renote?.uri !== url) : null);
|
const urls = computed(() => parsed.value ? extractPreviewUrls(props.note, parsed.value) : null);
|
||||||
const selfNoteIds = computed(() => getSelfNoteIds(props.note));
|
const selfNoteIds = computed(() => getSelfNoteIds(props.note));
|
||||||
const isLong = shouldCollapsed(appearNote.value, urls.value ?? []);
|
const isLong = shouldCollapsed(appearNote.value, urls.value ?? []);
|
||||||
const collapsed = ref(prefer.s.expandLongNote && appearNote.value.cw == null && isLong ? false : appearNote.value.cw == null && isLong);
|
const collapsed = ref(prefer.s.expandLongNote && appearNote.value.cw == null && isLong ? false : appearNote.value.cw == null && isLong);
|
||||||
|
|
|
@ -286,6 +286,7 @@ import { DI } from '@/di.js';
|
||||||
import SkMutedNote from '@/components/SkMutedNote.vue';
|
import SkMutedNote from '@/components/SkMutedNote.vue';
|
||||||
import SkNoteTranslation from '@/components/SkNoteTranslation.vue';
|
import SkNoteTranslation from '@/components/SkNoteTranslation.vue';
|
||||||
import { getSelfNoteIds } from '@/utility/get-self-note-ids.js';
|
import { getSelfNoteIds } from '@/utility/get-self-note-ids.js';
|
||||||
|
import { extractPreviewUrls } from '@/utility/extract-preview-urls.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
note: Misskey.entities.Note;
|
note: Misskey.entities.Note;
|
||||||
|
@ -338,10 +339,10 @@ const isDeleted = ref(false);
|
||||||
const renoted = ref(false);
|
const renoted = ref(false);
|
||||||
const translation = ref<Misskey.entities.NotesTranslateResponse | false | null>(null);
|
const translation = ref<Misskey.entities.NotesTranslateResponse | false | null>(null);
|
||||||
const translating = ref(false);
|
const translating = ref(false);
|
||||||
const parsed = appearNote.value.text ? mfm.parse(appearNote.value.text) : null;
|
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : null);
|
||||||
const urls = parsed ? extractUrlFromMfm(parsed).filter((url) => appearNote.value.renote?.url !== url && appearNote.value.renote?.uri !== url) : null;
|
const urls = computed(() => parsed.value ? extractPreviewUrls(props.note, parsed.value) : null);
|
||||||
const selfNoteIds = computed(() => getSelfNoteIds(props.note));
|
const selfNoteIds = computed(() => getSelfNoteIds(props.note));
|
||||||
const animated = computed(() => parsed ? checkAnimationFromMfm(parsed) : null);
|
const animated = computed(() => parsed.value ? checkAnimationFromMfm(parsed.value) : null);
|
||||||
const allowAnim = ref(prefer.s.advancedMfm && prefer.s.animatedMfm);
|
const allowAnim = ref(prefer.s.advancedMfm && prefer.s.animatedMfm);
|
||||||
const showTicker = (prefer.s.instanceTicker === 'always') || (prefer.s.instanceTicker === 'remote' && appearNote.value.user.instance);
|
const showTicker = (prefer.s.instanceTicker === 'always') || (prefer.s.instanceTicker === 'remote' && appearNote.value.user.instance);
|
||||||
const conversation = ref<Misskey.entities.Note[]>([]);
|
const conversation = ref<Misskey.entities.Note[]>([]);
|
||||||
|
|
|
@ -236,6 +236,7 @@ import { useRouter } from '@/router.js';
|
||||||
import SkMutedNote from '@/components/SkMutedNote.vue';
|
import SkMutedNote from '@/components/SkMutedNote.vue';
|
||||||
import SkNoteTranslation from '@/components/SkNoteTranslation.vue';
|
import SkNoteTranslation from '@/components/SkNoteTranslation.vue';
|
||||||
import { getSelfNoteIds } from '@/utility/get-self-note-ids.js';
|
import { getSelfNoteIds } from '@/utility/get-self-note-ids.js';
|
||||||
|
import { extractPreviewUrls } from '@/utility/extract-preview-urls.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
note: Misskey.entities.Note;
|
note: Misskey.entities.Note;
|
||||||
|
@ -303,7 +304,7 @@ const galleryEl = useTemplateRef('galleryEl');
|
||||||
const isMyRenote = $i && ($i.id === note.value.userId);
|
const isMyRenote = $i && ($i.id === note.value.userId);
|
||||||
const showContent = ref(prefer.s.uncollapseCW);
|
const showContent = ref(prefer.s.uncollapseCW);
|
||||||
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : null);
|
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : null);
|
||||||
const urls = computed(() => parsed.value ? extractUrlFromMfm(parsed.value).filter((url) => appearNote.value.renote?.url !== url && appearNote.value.renote?.uri !== url) : null);
|
const urls = computed(() => parsed.value ? extractPreviewUrls(props.note, parsed.value) : null);
|
||||||
const selfNoteIds = computed(() => getSelfNoteIds(props.note));
|
const selfNoteIds = computed(() => getSelfNoteIds(props.note));
|
||||||
const isLong = shouldCollapsed(appearNote.value, urls.value ?? []);
|
const isLong = shouldCollapsed(appearNote.value, urls.value ?? []);
|
||||||
const collapsed = ref(prefer.s.expandLongNote && appearNote.value.cw == null && isLong ? false : appearNote.value.cw == null && isLong);
|
const collapsed = ref(prefer.s.expandLongNote && appearNote.value.cw == null && isLong ? false : appearNote.value.cw == null && isLong);
|
||||||
|
|
|
@ -291,6 +291,7 @@ import { DI } from '@/di.js';
|
||||||
import SkMutedNote from '@/components/SkMutedNote.vue';
|
import SkMutedNote from '@/components/SkMutedNote.vue';
|
||||||
import SkNoteTranslation from '@/components/SkNoteTranslation.vue';
|
import SkNoteTranslation from '@/components/SkNoteTranslation.vue';
|
||||||
import { getSelfNoteIds } from '@/utility/get-self-note-ids.js';
|
import { getSelfNoteIds } from '@/utility/get-self-note-ids.js';
|
||||||
|
import { extractPreviewUrls } from '@/utility/extract-preview-urls';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
note: Misskey.entities.Note;
|
note: Misskey.entities.Note;
|
||||||
|
@ -344,10 +345,10 @@ const isDeleted = ref(false);
|
||||||
const renoted = ref(false);
|
const renoted = ref(false);
|
||||||
const translation = ref<Misskey.entities.NotesTranslateResponse | false | null>(null);
|
const translation = ref<Misskey.entities.NotesTranslateResponse | false | null>(null);
|
||||||
const translating = ref(false);
|
const translating = ref(false);
|
||||||
const parsed = appearNote.value.text ? mfm.parse(appearNote.value.text) : null;
|
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : null);
|
||||||
const urls = parsed ? extractUrlFromMfm(parsed).filter((url) => appearNote.value.renote?.url !== url && appearNote.value.renote?.uri !== url) : null;
|
const urls = computed(() => parsed.value ? extractPreviewUrls(props.note, parsed.value) : null);
|
||||||
const selfNoteIds = computed(() => getSelfNoteIds(props.note));
|
const selfNoteIds = computed(() => getSelfNoteIds(props.note));
|
||||||
const animated = computed(() => parsed ? checkAnimationFromMfm(parsed) : null);
|
const animated = computed(() => parsed.value ? checkAnimationFromMfm(parsed.value) : null);
|
||||||
const allowAnim = ref(prefer.s.advancedMfm && prefer.s.animatedMfm ? true : false);
|
const allowAnim = ref(prefer.s.advancedMfm && prefer.s.animatedMfm ? true : false);
|
||||||
const showTicker = (prefer.s.instanceTicker === 'always') || (prefer.s.instanceTicker === 'remote' && appearNote.value.user.instance);
|
const showTicker = (prefer.s.instanceTicker === 'always') || (prefer.s.instanceTicker === 'remote' && appearNote.value.user.instance);
|
||||||
const conversation = ref<Misskey.entities.Note[]>([]);
|
const conversation = ref<Misskey.entities.Note[]>([]);
|
||||||
|
|
|
@ -86,7 +86,6 @@ import MkPoll from '@/components/MkPoll.vue';
|
||||||
import MkUrlPreview from '@/components/MkUrlPreview.vue';
|
import MkUrlPreview from '@/components/MkUrlPreview.vue';
|
||||||
import MkInstanceTicker from '@/components/MkInstanceTicker.vue';
|
import MkInstanceTicker from '@/components/MkInstanceTicker.vue';
|
||||||
import { userPage } from '@/filters/user.js';
|
import { userPage } from '@/filters/user.js';
|
||||||
import { extractUrlFromMfm } from '@/utility/extract-url-from-mfm.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { deepClone } from '@/utility/clone.js';
|
import { deepClone } from '@/utility/clone.js';
|
||||||
import { dateTimeFormat } from '@/utility/intl-const.js';
|
import { dateTimeFormat } from '@/utility/intl-const.js';
|
||||||
|
@ -94,6 +93,7 @@ import { prefer } from '@/preferences';
|
||||||
import { getPluginHandlers } from '@/plugin.js';
|
import { getPluginHandlers } from '@/plugin.js';
|
||||||
import SkNoteTranslation from '@/components/SkNoteTranslation.vue';
|
import SkNoteTranslation from '@/components/SkNoteTranslation.vue';
|
||||||
import { getSelfNoteIds } from '@/utility/get-self-note-ids';
|
import { getSelfNoteIds } from '@/utility/get-self-note-ids';
|
||||||
|
import { extractPreviewUrls } from '@/utility/extract-preview-urls.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
note: Misskey.entities.Note;
|
note: Misskey.entities.Note;
|
||||||
|
@ -142,14 +142,13 @@ const isRenote = (
|
||||||
);
|
);
|
||||||
|
|
||||||
const el = shallowRef<HTMLElement>();
|
const el = shallowRef<HTMLElement>();
|
||||||
let appearNote = computed(() => isRenote ? note.value.renote as Misskey.entities.Note : note.value);
|
const appearNote = computed(() => isRenote ? note.value.renote as Misskey.entities.Note : note.value);
|
||||||
const renoteUrl = appearNote.value.renote ? appearNote.value.renote.url : null;
|
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : null);
|
||||||
const renoteUri = appearNote.value.renote ? appearNote.value.renote.uri : null;
|
|
||||||
|
|
||||||
const showContent = ref(false);
|
const showContent = ref(false);
|
||||||
const translation = ref<Misskey.entities.NotesTranslateResponse | false | null>(null);
|
const translation = ref<Misskey.entities.NotesTranslateResponse | false | null>(null);
|
||||||
const translating = ref(false);
|
const translating = ref(false);
|
||||||
const urls = appearNote.value.text ? extractUrlFromMfm(mfm.parse(appearNote.value.text)).filter(u => u !== renoteUrl && u !== renoteUri) : null;
|
const urls = computed(() => parsed.value ? extractPreviewUrls(props.note, parsed.value) : null);
|
||||||
const selfNoteIds = computed(() => getSelfNoteIds(props.note));
|
const selfNoteIds = computed(() => getSelfNoteIds(props.note));
|
||||||
const showTicker = (prefer.s.instanceTicker === 'always') || (prefer.s.instanceTicker === 'remote' && appearNote.value.user.instance);
|
const showTicker = (prefer.s.instanceTicker === 'always') || (prefer.s.instanceTicker === 'remote' && appearNote.value.user.instance);
|
||||||
|
|
||||||
|
|
32
packages/frontend/src/utility/extract-preview-urls.ts
Normal file
32
packages/frontend/src/utility/extract-preview-urls.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { host } from '@@/js/config.js';
|
||||||
|
import type * as Misskey from 'misskey-js';
|
||||||
|
import type * as mfm from '@transfem-org/sfm-js';
|
||||||
|
import { extractUrlFromMfm } from '@/utility/extract-url-from-mfm.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts all previewable URLs from a note.
|
||||||
|
*/
|
||||||
|
export function extractPreviewUrls(note: Misskey.entities.Note, contents: mfm.MfmNode[]): string[] {
|
||||||
|
const links = extractUrlFromMfm(contents);
|
||||||
|
return links.filter(url =>
|
||||||
|
// Remote note
|
||||||
|
url !== note.url &&
|
||||||
|
url !== note.uri &&
|
||||||
|
// Local note
|
||||||
|
url !== `https://${host}/notes/${note.id}` &&
|
||||||
|
// Remote renote or quote
|
||||||
|
url !== note.renote?.url &&
|
||||||
|
url !== note.renote?.uri &&
|
||||||
|
// Local renote or quote
|
||||||
|
url !== `https://${host}/notes/${note.renote?.id}` &&
|
||||||
|
// Remote renote *of* a quote
|
||||||
|
url !== note.renote?.renote?.url &&
|
||||||
|
url !== note.renote?.renote?.uri &&
|
||||||
|
// Local renote *of* a quote
|
||||||
|
url !== `https://${host}/notes/${note.renote?.renote?.id}`);
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ import { unique } from '@/utility/array.js';
|
||||||
// [ http://a/#1, http://a/#2, http://b/#3 ] => [ http://a/#1, http://b/#3 ]
|
// [ http://a/#1, http://a/#2, http://b/#3 ] => [ http://a/#1, http://b/#3 ]
|
||||||
const removeHash = (x: string) => x.replace(/#[^#]*$/, '');
|
const removeHash = (x: string) => x.replace(/#[^#]*$/, '');
|
||||||
|
|
||||||
|
// TODO this is O(n^2) which could introduce a frontend DoS with a large enough character limit
|
||||||
export function extractUrlFromMfm(nodes: mfm.MfmNode[], respectSilentFlag = true): string[] {
|
export function extractUrlFromMfm(nodes: mfm.MfmNode[], respectSilentFlag = true): string[] {
|
||||||
const urlNodes = mfm.extract(nodes, (node) => {
|
const urlNodes = mfm.extract(nodes, (node) => {
|
||||||
return (node.type === 'url') || (node.type === 'link' && (!respectSilentFlag || !node.props.silent));
|
return (node.type === 'url') || (node.type === 'link' && (!respectSilentFlag || !node.props.silent));
|
||||||
|
|
Loading…
Add table
Reference in a new issue