@@ -70,6 +70,7 @@ SPDX-License-Identifier: AGPL-3.0-only
70
70
:enableEmojiMenu="true"
71
71
:enableEmojiMenuReaction="true"
72
72
/>
73
+ <MkPhishingCaution v-if="isSuspectPhishingLink" :cautionMessage="i18n.ts.shortPhishingCaution" />
73
74
<div v-if="translating || translation" :class="$style.translation">
74
75
<MkLoading v-if="translating" mini/>
75
76
<div v-else-if="translation">
@@ -82,7 +83,7 @@ SPDX-License-Identifier: AGPL-3.0-only
82
83
<MkMediaList :mediaList="appearNote.files"/>
83
84
</div>
84
85
<MkPoll v-if="appearNote.poll" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/>
85
- <MkUrlPreview v-for="url in urls " :key="url" :url="url" :compact="true" :detail="false" :class="$style.urlPreview"/>
86
+ <MkUrlPreview v-for="url in previewUrls " :key="url" :url="url.href " :compact="true" :detail="false" :class="$style.urlPreview"/>
86
87
<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
87
88
<button v-if="isLong && collapsed" :class="$style.collapsed" class="_button" @click="collapsed = false">
88
89
<span :class="$style.collapsedLabel">{{ i18n.ts.showMore }}</span>
@@ -168,6 +169,7 @@ import MkPoll from '@/components/MkPoll.vue';
168
169
import MkUsersTooltip from '@/components/MkUsersTooltip.vue';
169
170
import MkUrlPreview from '@/components/MkUrlPreview.vue';
170
171
import MkInstanceTicker from '@/components/MkInstanceTicker.vue';
172
+ import MkPhishingCaution from '@/components/MkPhishingCaution.vue';
171
173
import { pleaseLogin } from '@/scripts/please-login.js';
172
174
import { focusPrev, focusNext } from '@/scripts/focus.js';
173
175
import { checkWordMute } from '@/scripts/check-word-mute.js';
@@ -250,7 +252,8 @@ const appearNote = computed(() => isRenote ? note.value.renote as Misskey.entiti
250
252
const isMyRenote = $i && ($i.id === note.value.userId);
251
253
const showContent = ref(false);
252
254
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : null);
253
- const urls = computed(() => parsed.value ? extractUrlFromMfm(parsed.value).filter((url) => appearNote.value.renote?.url !== url && appearNote.value.renote?.uri !== url) : null);
255
+ const urls = computed(() => parsed.value ? extractUrlFromMfm(parsed.value).filter((url) => appearNote.value.renote?.url !== url.href && appearNote.value.renote?.uri !== url.href) : null);
256
+ const previewUrls = computed(() => urls.value.filter(url => url.preview));
254
257
const isLong = shouldCollapsed(appearNote.value, urls.value ?? []);
255
258
const collapsed = ref(appearNote.value.cw == null && isLong);
256
259
const isDeleted = ref(false);
@@ -267,6 +270,43 @@ const renoteCollapsed = ref(
267
270
)
268
271
);
269
272
273
+ function isURL(str) {
274
+ try {
275
+ new URL(str);
276
+ return true;
277
+ } catch (error) {
278
+ return false;
279
+ }
280
+ }
281
+
282
+ function getDomain(url) {
283
+ try {
284
+ const domain = new URL(url).hostname;
285
+ return domain;
286
+ } catch (error) {
287
+ return null;
288
+ }
289
+ }
290
+
291
+ const isSuspectPhishingLink = computed(() => {
292
+ return urls.value.some(url => {
293
+ // url.textが配列でない場合、配列に変換
294
+ const text = Array.isArray(url.text) ? url.text.join('') : url.text;
295
+
296
+ // textがURLでない場合、すぐに次のurlへ
297
+ console.log(text);
298
+ if (!isURL((text.startsWith('https://') || text.startsWith('http://')) ? text : `https://${text}`)) return false;
299
+
300
+ // hrefとtextのドメインを比較
301
+ const hrefDomain = getDomain(url.href);
302
+ const textDomain = getDomain(text);
303
+ console.log(hrefDomain, textDomain);
304
+
305
+ // ドメインが一致しない場合、フィッシングの疑いあり
306
+ return hrefDomain !== textDomain && textDomain;
307
+ });
308
+ });
309
+
270
310
/* Overload FunctionにLintが対応していないのでコメントアウト
271
311
function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string | string[]> | undefined | null, checkOnly: true): boolean;
272
312
function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string | string[]> | undefined | null, checkOnly: false): boolean | 'sensitiveMute';
0 commit comments