Merge branch 'develop'

This commit is contained in:
syuilo 2023-02-04 09:12:26 +09:00
commit 24705a7e39
17 changed files with 52 additions and 37 deletions

View file

@ -9,6 +9,14 @@
You should also include the user name that made the change. You should also include the user name that made the change.
--> -->
## 13.3.1 (2023/02/04)
### Bugfixes
- Client: カスタム絵文字にアニメーション画像を再生しない設定が適用されていない問題を修正
- Client: オートコンプリートでUnicode絵文字がカスタム絵文字として表示されてしまうのを修正
- Client: Fix Vue-plyr CORS issue
- Client: validate urls to improve security
## 13.3.0 (2023/02/03) ## 13.3.0 (2023/02/03)
### Changes ### Changes
- twitter/github/discord連携機能が削除されました - twitter/github/discord連携機能が削除されました

View file

@ -68,7 +68,7 @@ export: "Export"
files: "Dateien" files: "Dateien"
download: "Herunterladen" download: "Herunterladen"
driveFileDeleteConfirm: "Möchtest du die Datei „{name}“ wirklich löschen? Notizen mit dieser Datei werden ebenso verschwinden." driveFileDeleteConfirm: "Möchtest du die Datei „{name}“ wirklich löschen? Notizen mit dieser Datei werden ebenso verschwinden."
unfollowConfirm: "Möchtest du {name} nicht mehr folgen?" unfollowConfirm: "Möchtest du {name} wirklich nicht mehr folgen?"
exportRequested: "Du hast einen Export angefragt. Dies kann etwas Zeit in Anspruch nehmen. Sobald der Export abgeschlossen ist, wird er deiner Drive hinzugefügt." exportRequested: "Du hast einen Export angefragt. Dies kann etwas Zeit in Anspruch nehmen. Sobald der Export abgeschlossen ist, wird er deiner Drive hinzugefügt."
importRequested: "Du hast einen Import angefragt. Dies kann etwas Zeit in Anspruch nehmen." importRequested: "Du hast einen Import angefragt. Dies kann etwas Zeit in Anspruch nehmen."
lists: "Listen" lists: "Listen"
@ -94,7 +94,7 @@ defaultNoteVisibility: "Standardsichtbarkeit"
follow: "Folgen" follow: "Folgen"
followRequest: "Follow-Anfrage senden" followRequest: "Follow-Anfrage senden"
followRequests: "Follow-Anfragen" followRequests: "Follow-Anfragen"
unfollow: "Nicht mehr folgen" unfollow: "Entfolgen"
followRequestPending: "Follow-Anfrage ausstehend" followRequestPending: "Follow-Anfrage ausstehend"
enterEmoji: "Gib ein Emoji ein" enterEmoji: "Gib ein Emoji ein"
renote: "Renote" renote: "Renote"

View file

@ -68,7 +68,7 @@ export: "Export"
files: "Files" files: "Files"
download: "Download" download: "Download"
driveFileDeleteConfirm: "Are you sure you want to delete the file \"{name}\"? Notes with this file attached will also be deleted." driveFileDeleteConfirm: "Are you sure you want to delete the file \"{name}\"? Notes with this file attached will also be deleted."
unfollowConfirm: "Are you sure that you want to unfollow {name}?" unfollowConfirm: "Are you sure you want to unfollow {name}?"
exportRequested: "You've requested an export. This may take a while. It will be added to your Drive once completed." exportRequested: "You've requested an export. This may take a while. It will be added to your Drive once completed."
importRequested: "You've requested an import. This may take a while." importRequested: "You've requested an import. This may take a while."
lists: "Lists" lists: "Lists"

View file

@ -943,8 +943,8 @@ _achievements:
earnedAt: "Desbloqueado el" earnedAt: "Desbloqueado el"
_types: _types:
_notes1: _notes1:
title: "Configurando mis espacio" title: "¡Hola Misskey!"
description: "Publicar tu primera nota" description: "Publicaste tu primera nota"
flavor: "¡Pasándola bien con Misskey!" flavor: "¡Pasándola bien con Misskey!"
_notes10: _notes10:
title: "Algunas notas" title: "Algunas notas"
@ -1233,8 +1233,8 @@ _role:
or: "Condicional OR" or: "Condicional OR"
not: "Condicional NOT" not: "Condicional NOT"
_sensitiveMediaDetection: _sensitiveMediaDetection:
description: "Reduce el esfuerzo de la moderación el el servidor a través del reconocimiento automático de contenido NSFW usando 'Machine Learning'. Esto puede incrementar ligeramente la carga en el servidor." description: "Reduce el esfuerzo de la moderación en el servidor a través del reconocimiento automático de contenido NSFW usando 'Machine Learning'. Esto puede incrementar ligeramente la carga en el servidor."
sensitivity: "Sensibilidad de detección" sensitivity: "Sensibilidad de la detección"
sensitivityDescription: "Reducir la sensibilidad puede acarrear a varios falsos positivos, mientras que incrementarla puede reducir las detecciones (falsos negativos)." sensitivityDescription: "Reducir la sensibilidad puede acarrear a varios falsos positivos, mientras que incrementarla puede reducir las detecciones (falsos negativos)."
setSensitiveFlagAutomatically: "Marcar como NSFW" setSensitiveFlagAutomatically: "Marcar como NSFW"
setSensitiveFlagAutomaticallyDescription: "Los resultados de la detección interna pueden ser retenidos incluso si la opción está desactivada." setSensitiveFlagAutomaticallyDescription: "Los resultados de la detección interna pueden ser retenidos incluso si la opción está desactivada."

View file

@ -1072,19 +1072,21 @@ _achievements:
description: "第一次被关注" description: "第一次被关注"
_followers10: _followers10:
title: "关注我吧!" title: "关注我吧!"
description: "关注者超过10人" description: "拥有超过10名关注者"
_followers50: _followers50:
title: "三五成群" title: "三五成群"
description: "关注者超过50人" description: "拥有超过50名关注者"
_followers100: _followers100:
title: "胜友如云" title: "胜友如云"
description: "关注者超过100人" description: "拥有超过100名关注者"
_followers300: _followers300:
title: "排列成行" title: "排列成行"
description: "关注者超过300人" description: "拥有超过300名关注者"
_followers500: _followers500:
title: "信号塔" title: "信号塔"
description: "关注者超过500人" description: "拥有超过500名关注者"
_followers1000:
description: "拥有超过1000名关注者"
_collectAchievements30: _collectAchievements30:
title: "成就收藏家" title: "成就收藏家"
description: "获得超过30个成就" description: "获得超过30个成就"
@ -1096,6 +1098,7 @@ _achievements:
description: "发布\"I ❤ #Misskey\"帖子" description: "发布\"I ❤ #Misskey\"帖子"
flavor: "感谢您使用 Misskey by 开发团队" flavor: "感谢您使用 Misskey by 开发团队"
_foundTreasure: _foundTreasure:
title: "寻宝"
description: "发现了隐藏的宝藏" description: "发现了隐藏的宝藏"
_client30min: _client30min:
title: "休息一下!" title: "休息一下!"
@ -1122,11 +1125,13 @@ _achievements:
description: "查看了实例信息中的图表" description: "查看了实例信息中的图表"
_outputHelloWorldOnScratchpad: _outputHelloWorldOnScratchpad:
title: "Hello, world!" title: "Hello, world!"
description: "在AiScript控制台中输出 hello world"
_open3windows: _open3windows:
title: "多窗口" title: "多窗口"
description: "打开了三个或更多的窗口" description: "打开了三个或更多的窗口"
_driveFolderCircularReference: _driveFolderCircularReference:
title: "循环引用" title: "循环引用"
description: "试图对网盘中的文件夹进行循环嵌套"
_reactWithoutRead: _reactWithoutRead:
title: "有好好读过吗?" title: "有好好读过吗?"
description: "在含有100字以上的帖子被发出三秒内做出回应" description: "在含有100字以上的帖子被发出三秒内做出回应"

View file

@ -1,6 +1,6 @@
{ {
"name": "misskey", "name": "misskey",
"version": "13.3.0", "version": "13.3.1",
"codename": "nasubi", "codename": "nasubi",
"repository": { "repository": {
"type": "git", "type": "git",

View file

@ -17,7 +17,8 @@
</ol> </ol>
<ol v-else-if="emojis.length > 0" ref="suggests" :class="$style.list"> <ol v-else-if="emojis.length > 0" ref="suggests" :class="$style.list">
<li v-for="emoji in emojis" :key="emoji.emoji" :class="$style.item" tabindex="-1" @click="complete(type, emoji.emoji)" @keydown="onKeydown"> <li v-for="emoji in emojis" :key="emoji.emoji" :class="$style.item" tabindex="-1" @click="complete(type, emoji.emoji)" @keydown="onKeydown">
<MkCustomEmoji :name="emoji.emoji" :class="$style.emoji"/> <MkCustomEmoji v-if="'isCustomEmoji' in emoji && emoji.isCustomEmoji" :name="emoji.emoji" :class="$style.emoji"/>
<MkEmoji v-else :emoji="emoji.emoji" :class="$style.emoji"/>
<!-- eslint-disable-next-line vue/no-v-html --> <!-- eslint-disable-next-line vue/no-v-html -->
<span v-if="q" :class="$style.emojiName" v-html="sanitizeHtml(emoji.name.replace(q, `<b>${q}</b>`))"></span> <span v-if="q" :class="$style.emojiName" v-html="sanitizeHtml(emoji.name.replace(q, `<b>${q}</b>`))"></span>
<span v-else v-text="emoji.name"></span> <span v-else v-text="emoji.name"></span>

View file

@ -9,8 +9,6 @@
<vue-plyr> <vue-plyr>
<video <video
controls controls
crossorigin
playsinline
:data-poster="video.thumbnailUrl" :data-poster="video.thumbnailUrl"
> >
<source <source

View file

@ -56,8 +56,6 @@ async function renderChart() {
} }
} }
console.log(data);
fetching = false; fetching = false;
await nextTick(); await nextTick();

View file

@ -154,7 +154,6 @@ function queryKey() {
function onSubmit() { function onSubmit() {
signing = true; signing = true;
console.log('submit');
if (!totpLogin && user && user.twoFactorEnabled) { if (!totpLogin && user && user.twoFactorEnabled) {
if (window.PublicKeyCredential && user.securityKeys) { if (window.PublicKeyCredential && user.securityKeys) {
os.api('signin', { os.api('signin', {

View file

@ -86,6 +86,7 @@ let tweetHeight = $ref(150);
let unknownUrl = $ref(false); let unknownUrl = $ref(false);
const requestUrl = new URL(props.url); const requestUrl = new URL(props.url);
if (!['http:', 'https:'].includes(requestUrl.protocol)) throw new Error('invalid url');
if (requestUrl.hostname === 'twitter.com' || requestUrl.hostname === 'mobile.twitter.com') { if (requestUrl.hostname === 'twitter.com' || requestUrl.hostname === 'mobile.twitter.com') {
const m = requestUrl.pathname.match(/^\/.+\/status(?:es)?\/(\d+)/); const m = requestUrl.pathname.match(/^\/.+\/status(?:es)?\/(\d+)/);

View file

@ -26,6 +26,7 @@ const props = defineProps<{
}>(); }>();
const requestUrl = new URL(props.url); const requestUrl = new URL(props.url);
if (!['http:', 'https:'].includes(requestUrl.protocol)) throw new Error('invalid url');
let fetching = $ref(true); let fetching = $ref(true);
let title = $ref<string | null>(null); let title = $ref<string | null>(null);

View file

@ -18,19 +18,23 @@ const props = defineProps<{
}>(); }>();
const customEmojiName = computed(() => (props.name[0] === ':' ? props.name.substr(1, props.name.length - 2) : props.name).replace('@.', '')); const customEmojiName = computed(() => (props.name[0] === ':' ? props.name.substr(1, props.name.length - 2) : props.name).replace('@.', ''));
const url = computed(() => {
const rawUrl = computed(() => {
if (props.url) { if (props.url) {
return props.url; return props.url;
} else if (props.host == null && !customEmojiName.value.includes('@')) {
const found = customEmojis.value.find(x => x.name === customEmojiName.value);
return found ? defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(found.url) : found.url : null;
} else {
const rawUrl = props.host ? `/emoji/${customEmojiName.value}@${props.host}.webp` : `/emoji/${customEmojiName.value}.webp`;
return defaultStore.state.disableShowingAnimatedImages
? getStaticImageUrl(rawUrl)
: rawUrl;
} }
if (props.host == null && !customEmojiName.value.includes('@')) {
return customEmojis.value.find(x => x.name === customEmojiName.value)?.url || null;
}
return props.host ? `/emoji/${customEmojiName.value}@${props.host}.webp` : `/emoji/${customEmojiName.value}.webp`;
}); });
const url = computed(() =>
defaultStore.reactiveState.disableShowingAnimatedImages.value && rawUrl.value
? getStaticImageUrl(rawUrl.value)
: rawUrl.value
);
const alt = computed(() => `:${customEmojiName.value}:`); const alt = computed(() => `:${customEmojiName.value}:`);
let errored = $ref(url.value == null); let errored = $ref(url.value == null);
</script> </script>

View file

@ -33,6 +33,7 @@ const props = defineProps<{
const self = props.url.startsWith(local); const self = props.url.startsWith(local);
const url = new URL(props.url); const url = new URL(props.url);
if (!['http:', 'https:'].includes(url.protocol)) throw new Error('invalid url');
const el = ref(); const el = ref();
useTooltip(el, (showing) => { useTooltip(el, (showing) => {

View file

@ -70,6 +70,7 @@ async function accept(): Promise<void> {
state = 'accepted'; state = 'accepted';
if (props.callback) { if (props.callback) {
const cbUrl = new URL(props.callback); const cbUrl = new URL(props.callback);
if (!['http:', 'https:'].includes(cbUrl.protocol)) throw new Error('invalid url');
cbUrl.searchParams.set('session', props.session); cbUrl.searchParams.set('session', props.session);
location.href = cbUrl.href; location.href = cbUrl.href;
} }

View file

@ -38,14 +38,11 @@ const init = async () => {
getAccounts().then(accounts => { getAccounts().then(accounts => {
storedAccounts.value = accounts.filter(x => x.id !== $i!.id); storedAccounts.value = accounts.filter(x => x.id !== $i!.id);
console.log(storedAccounts.value);
return os.api('users/show', { return os.api('users/show', {
userIds: storedAccounts.value.map(x => x.id), userIds: storedAccounts.value.map(x => x.id),
}); });
}).then(response => { }).then(response => {
accounts.value = response; accounts.value = response;
console.log(accounts.value);
}); });
}; };

View file

@ -8,14 +8,15 @@ import {
const fallbackName = (key: string) => `idbfallback::${key}`; const fallbackName = (key: string) => `idbfallback::${key}`;
let idbAvailable = typeof window !== 'undefined' ? !!window.indexedDB : true; let idbAvailable = typeof window !== 'undefined' ? !!(window.indexedDB && window.indexedDB.open) : true;
if (idbAvailable) { if (idbAvailable) {
iset('idb-test', 'test').catch(err => { await iset('idb-test', 'test')
console.error('idb error', err); .catch(err => {
console.error('indexedDB is unavailable. It will use localStorage.'); console.error('idb error', err);
idbAvailable = false; console.error('indexedDB is unavailable. It will use localStorage.');
}); idbAvailable = false;
});
} else { } else {
console.error('indexedDB is unavailable. It will use localStorage.'); console.error('indexedDB is unavailable. It will use localStorage.');
} }