summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--locales/index.d.ts26
-rw-r--r--locales/ja-JP.yml8
-rw-r--r--packages/backend/migration/1729333924409-signinRequiredForShowContents.js16
-rw-r--r--packages/backend/src/core/WebhookTestService.ts1
-rw-r--r--packages/backend/src/core/activitypub/ApRendererService.ts1
-rw-r--r--packages/backend/src/core/activitypub/misc/contexts.ts1
-rw-r--r--packages/backend/src/core/activitypub/models/ApPersonService.ts1
-rw-r--r--packages/backend/src/core/activitypub/type.ts1
-rw-r--r--packages/backend/src/core/entities/NoteEntityService.ts4
-rw-r--r--packages/backend/src/core/entities/UserEntityService.ts1
-rw-r--r--packages/backend/src/models/User.ts5
-rw-r--r--packages/backend/src/models/json-schema/user.ts4
-rw-r--r--packages/backend/src/server/api/GetterService.ts11
-rw-r--r--packages/backend/src/server/api/endpoints/i/update.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/notes/show.ts12
-rw-r--r--packages/backend/src/server/api/endpoints/users/notes.ts6
-rw-r--r--packages/backend/src/server/web/ClientServerService.ts11
-rw-r--r--packages/frontend/src/components/MkFollowButton.vue4
-rw-r--r--packages/frontend/src/components/MkNote.vue8
-rw-r--r--packages/frontend/src/components/MkNoteDetailed.vue10
-rw-r--r--packages/frontend/src/components/MkPoll.vue6
-rw-r--r--packages/frontend/src/os.ts18
-rw-r--r--packages/frontend/src/pages/not-found.vue2
-rw-r--r--packages/frontend/src/pages/note.vue6
-rw-r--r--packages/frontend/src/pages/settings/privacy.vue19
-rw-r--r--packages/frontend/src/scripts/please-login.ts14
-rw-r--r--packages/misskey-js/src/autogen/types.ts2
28 files changed, 167 insertions, 35 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c815e65ab3..4d8c8ded3a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,7 @@
## Unreleased
### General
--
+- Feat: コンテンツの表示にログインを必須にできるように
### Client
- Enhance: Bull DashboardでRelationship Queueの状態も確認できるように
diff --git a/locales/index.d.ts b/locales/index.d.ts
index fb010d9353..e002540307 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -5190,6 +5190,32 @@ export interface Locale extends ILocale {
* 名前に禁止されている文字列が含まれています。この名前を使用したい場合は、サーバー管理者にお問い合わせください。
*/
"yourNameContainsProhibitedWordsDescription": string;
+ /**
+ * 投稿者により、表示にはログインが必要と設定されています
+ */
+ "thisContentsAreMarkedAsSigninRequiredByAuthor": string;
+ /**
+ * ロックダウン
+ */
+ "lockdown": string;
+ "_accountSettings": {
+ /**
+ * コンテンツの表示にログインを必須にする
+ */
+ "requireSigninToViewContents": string;
+ /**
+ * あなたが作成した全てのノートなどのコンテンツを表示するのにログインを必須にします。クローラーから情報を収集されるのを防ぐ効果が期待できます。
+ */
+ "requireSigninToViewContentsDescription1": string;
+ /**
+ * URLプレビュー(OGP)、Webページへの埋め込み、ノートの引用に対応していないサーバーからの表示も不可になります。
+ */
+ "requireSigninToViewContentsDescription2": string;
+ /**
+ * リモートサーバーに連合されたコンテンツでは、これらの制限が適用されない場合があります。
+ */
+ "requireSigninToViewContentsDescription3": string;
+ };
"_abuseUserReport": {
/**
* 転送
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index c241a9e560..f3f7e5c77f 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1293,6 +1293,14 @@ prohibitedWordsForNameOfUser: "禁止ワード(ユーザーの名前)"
prohibitedWordsForNameOfUserDescription: "このリストに含まれる文字列がユーザーの名前に含まれる場合、ユーザーの名前の変更を拒否します。モデレーター権限を持つユーザーはこの制限の影響を受けません。"
yourNameContainsProhibitedWords: "変更しようとした名前に禁止された文字列が含まれています"
yourNameContainsProhibitedWordsDescription: "名前に禁止されている文字列が含まれています。この名前を使用したい場合は、サーバー管理者にお問い合わせください。"
+thisContentsAreMarkedAsSigninRequiredByAuthor: "投稿者により、表示にはログインが必要と設定されています"
+lockdown: "ロックダウン"
+
+_accountSettings:
+ requireSigninToViewContents: "コンテンツの表示にログインを必須にする"
+ requireSigninToViewContentsDescription1: "あなたが作成した全てのノートなどのコンテンツを表示するのにログインを必須にします。クローラーから情報を収集されるのを防ぐ効果が期待できます。"
+ requireSigninToViewContentsDescription2: "URLプレビュー(OGP)、Webページへの埋め込み、ノートの引用に対応していないサーバーからの表示も不可になります。"
+ requireSigninToViewContentsDescription3: "リモートサーバーに連合されたコンテンツでは、これらの制限が適用されない場合があります。"
_abuseUserReport:
forward: "転送"
diff --git a/packages/backend/migration/1729333924409-signinRequiredForShowContents.js b/packages/backend/migration/1729333924409-signinRequiredForShowContents.js
new file mode 100644
index 0000000000..5d4d1fcce2
--- /dev/null
+++ b/packages/backend/migration/1729333924409-signinRequiredForShowContents.js
@@ -0,0 +1,16 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class SigninRequiredForShowContents1729333924409 {
+ name = 'SigninRequiredForShowContents1729333924409'
+
+ async up(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "user" ADD "requireSigninToViewContents" boolean NOT NULL DEFAULT false`);
+ }
+
+ async down(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "requireSigninToViewContents"`);
+ }
+}
diff --git a/packages/backend/src/core/WebhookTestService.ts b/packages/backend/src/core/WebhookTestService.ts
index 55c8a52705..254d961040 100644
--- a/packages/backend/src/core/WebhookTestService.ts
+++ b/packages/backend/src/core/WebhookTestService.ts
@@ -83,6 +83,7 @@ function generateDummyUser(override?: Partial<MiUser>): MiUser {
isExplorable: true,
isHibernated: false,
isDeleted: false,
+ requireSigninToViewContents: false,
emojis: [],
score: 0,
host: null,
diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts
index fba8947f03..8235d7ba30 100644
--- a/packages/backend/src/core/activitypub/ApRendererService.ts
+++ b/packages/backend/src/core/activitypub/ApRendererService.ts
@@ -495,6 +495,7 @@ export class ApRendererService {
summary: profile.description ? this.mfmService.toHtml(mfm.parse(profile.description)) : null,
_misskey_summary: profile.description,
_misskey_followedMessage: profile.followedMessage,
+ _misskey_requireSigninToViewContents: user.requireSigninToViewContents,
icon: avatar ? this.renderImage(avatar) : null,
image: banner ? this.renderImage(banner) : null,
tag,
diff --git a/packages/backend/src/core/activitypub/misc/contexts.ts b/packages/backend/src/core/activitypub/misc/contexts.ts
index 3dd85b9b86..447f7ef3db 100644
--- a/packages/backend/src/core/activitypub/misc/contexts.ts
+++ b/packages/backend/src/core/activitypub/misc/contexts.ts
@@ -555,6 +555,7 @@ const extension_context_definition = {
'_misskey_votes': 'misskey:_misskey_votes',
'_misskey_summary': 'misskey:_misskey_summary',
'_misskey_followedMessage': 'misskey:_misskey_followedMessage',
+ '_misskey_requireSigninToViewContents': 'misskey:_misskey_requireSigninToViewContents',
'isCat': 'misskey:isCat',
// vcard
vcard: 'http://www.w3.org/2006/vcard/ns#',
diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts
index 73281078e5..c7915ed94f 100644
--- a/packages/backend/src/core/activitypub/models/ApPersonService.ts
+++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts
@@ -356,6 +356,7 @@ export class ApPersonService implements OnModuleInit {
tags,
isBot,
isCat: (person as any).isCat === true,
+ requireSigninToViewContents: (person as any).requireSigninToViewContents === true,
emojis,
})) as MiRemoteUser;
diff --git a/packages/backend/src/core/activitypub/type.ts b/packages/backend/src/core/activitypub/type.ts
index 154965b9d5..8a860335fa 100644
--- a/packages/backend/src/core/activitypub/type.ts
+++ b/packages/backend/src/core/activitypub/type.ts
@@ -14,6 +14,7 @@ export interface IObject {
summary?: string;
_misskey_summary?: string;
_misskey_followedMessage?: string | null;
+ _misskey_requireSigninToViewContents?: boolean;
published?: string;
cc?: ApObject;
to?: ApObject;
diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts
index 3e1f094fce..62016936a2 100644
--- a/packages/backend/src/core/entities/NoteEntityService.ts
+++ b/packages/backend/src/core/entities/NoteEntityService.ts
@@ -149,6 +149,10 @@ export class NoteEntityService implements OnModuleInit {
}
}
+ if (packedNote.user.requireSigninToViewContents && meId == null) {
+ hide = true;
+ }
+
if (hide) {
packedNote.visibleUserIds = undefined;
packedNote.fileIds = [];
diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts
index c9939adf11..747ffc780f 100644
--- a/packages/backend/src/core/entities/UserEntityService.ts
+++ b/packages/backend/src/core/entities/UserEntityService.ts
@@ -490,6 +490,7 @@ export class UserEntityService implements OnModuleInit {
}))) : [],
isBot: user.isBot,
isCat: user.isCat,
+ requireSigninToViewContents: user.requireSigninToViewContents === false ? undefined : true,
instance: user.host ? this.federatedInstanceService.federatedInstanceCache.fetch(user.host).then(instance => instance ? {
name: instance.name,
softwareName: instance.softwareName,
diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts
index 805a1e75ae..6fcff77854 100644
--- a/packages/backend/src/models/User.ts
+++ b/packages/backend/src/models/User.ts
@@ -202,6 +202,11 @@ export class MiUser {
})
public isHibernated: boolean;
+ @Column('boolean', {
+ default: false,
+ })
+ public requireSigninToViewContents: boolean;
+
// アカウントが削除されたかどうかのフラグだが、完全に削除される際は物理削除なので実質削除されるまでの「削除が進行しているかどうか」のフラグ
@Column('boolean', {
default: false,
diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts
index 9cffd680f2..817f8e9292 100644
--- a/packages/backend/src/models/json-schema/user.ts
+++ b/packages/backend/src/models/json-schema/user.ts
@@ -115,6 +115,10 @@ export const packedUserLiteSchema = {
type: 'boolean',
nullable: false, optional: true,
},
+ requireSigninToViewContents: {
+ type: 'boolean',
+ nullable: false, optional: true,
+ },
instance: {
type: 'object',
nullable: false, optional: true,
diff --git a/packages/backend/src/server/api/GetterService.ts b/packages/backend/src/server/api/GetterService.ts
index bff3ab96f3..444e6db744 100644
--- a/packages/backend/src/server/api/GetterService.ts
+++ b/packages/backend/src/server/api/GetterService.ts
@@ -39,6 +39,17 @@ export class GetterService {
return note;
}
+ @bindThis
+ public async getNoteWithUser(noteId: MiNote['id']) {
+ const note = await this.notesRepository.findOne({ where: { id: noteId }, relations: ['user'] });
+
+ if (note == null) {
+ throw new IdentifiableError('9725d0ce-ba28-4dde-95a7-2cbb2c15de24', 'No such note.');
+ }
+
+ return note;
+ }
+
/**
* Get user for API processing
*/
diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts
index 0b35005a87..6680c96f3f 100644
--- a/packages/backend/src/server/api/endpoints/i/update.ts
+++ b/packages/backend/src/server/api/endpoints/i/update.ts
@@ -179,6 +179,7 @@ export const paramDef = {
autoAcceptFollowed: { type: 'boolean' },
noCrawle: { type: 'boolean' },
preventAiLearning: { type: 'boolean' },
+ requireSigninToViewContents: { type: 'boolean' },
isBot: { type: 'boolean' },
isCat: { type: 'boolean' },
injectFeaturedNote: { type: 'boolean' },
@@ -334,6 +335,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (typeof ps.autoAcceptFollowed === 'boolean') profileUpdates.autoAcceptFollowed = ps.autoAcceptFollowed;
if (typeof ps.noCrawle === 'boolean') profileUpdates.noCrawle = ps.noCrawle;
if (typeof ps.preventAiLearning === 'boolean') profileUpdates.preventAiLearning = ps.preventAiLearning;
+ if (typeof ps.requireSigninToViewContents === 'boolean') updates.requireSigninToViewContents = ps.requireSigninToViewContents;
if (typeof ps.isCat === 'boolean') updates.isCat = ps.isCat;
if (typeof ps.injectFeaturedNote === 'boolean') profileUpdates.injectFeaturedNote = ps.injectFeaturedNote;
if (typeof ps.receiveAnnouncementEmail === 'boolean') profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail;
diff --git a/packages/backend/src/server/api/endpoints/notes/show.ts b/packages/backend/src/server/api/endpoints/notes/show.ts
index adcda30a7d..11839bce36 100644
--- a/packages/backend/src/server/api/endpoints/notes/show.ts
+++ b/packages/backend/src/server/api/endpoints/notes/show.ts
@@ -26,6 +26,12 @@ export const meta = {
code: 'NO_SUCH_NOTE',
id: '24fcbfc6-2e37-42b6-8388-c29b3861a08d',
},
+
+ signinRequired: {
+ message: 'Signin required.',
+ code: 'SIGNIN_REQUIRED',
+ id: '8e75455b-738c-471d-9f80-62693f33372e',
+ },
},
} as const;
@@ -44,11 +50,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private getterService: GetterService,
) {
super(meta, paramDef, async (ps, me) => {
- const note = await this.getterService.getNote(ps.noteId).catch(err => {
+ const note = await this.getterService.getNoteWithUser(ps.noteId).catch(err => {
if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
throw err;
});
+ if (note.user!.requireSigninToViewContents && me == null) {
+ throw new ApiError(meta.errors.signinRequired);
+ }
+
return await this.noteEntityService.pack(note, me, {
detail: true,
});
diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts
index 7fc11ba369..e9c334057e 100644
--- a/packages/backend/src/server/api/endpoints/users/notes.ts
+++ b/packages/backend/src/server/api/endpoints/users/notes.ts
@@ -42,6 +42,12 @@ export const meta = {
code: 'BOTH_WITH_REPLIES_AND_WITH_FILES',
id: '91c8cb9f-36ed-46e7-9ca2-7df96ed6e222',
},
+
+ signinRequired: {
+ message: 'Signin required.',
+ code: 'SIGNIN_REQUIRED',
+ id: 'd1588a9e-4b4d-4c07-807f-16f1486577a2',
+ },
},
} as const;
diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts
index c9c29e42a8..4860ef3e12 100644
--- a/packages/backend/src/server/web/ClientServerService.ts
+++ b/packages/backend/src/server/web/ClientServerService.ts
@@ -601,12 +601,15 @@ export class ClientServerService {
fastify.get<{ Params: { note: string; } }>('/notes/:note', async (request, reply) => {
vary(reply.raw, 'Accept');
- const note = await this.notesRepository.findOneBy({
- id: request.params.note,
- visibility: In(['public', 'home']),
+ const note = await this.notesRepository.findOne({
+ where: {
+ id: request.params.note,
+ visibility: In(['public', 'home']),
+ },
+ relations: ['user'],
});
- if (note) {
+ if (note && !note.user!.requireSigninToViewContents) {
const _note = await this.noteEntityService.pack(note);
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: note.userId });
reply.header('Cache-Control', 'public, max-age=15');
diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue
index ccea7cd453..cc07175907 100644
--- a/packages/frontend/src/components/MkFollowButton.vue
+++ b/packages/frontend/src/components/MkFollowButton.vue
@@ -37,13 +37,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { onBeforeUnmount, onMounted, ref } from 'vue';
import * as Misskey from 'misskey-js';
+import { host } from '@@/js/config.js';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { useStream } from '@/stream.js';
import { i18n } from '@/i18n.js';
import { claimAchievement } from '@/scripts/achievements.js';
import { pleaseLogin } from '@/scripts/please-login.js';
-import { host } from '@@/js/config.js';
import { $i } from '@/account.js';
import { defaultStore } from '@/store.js';
@@ -80,7 +80,7 @@ function onFollowChange(user: Misskey.entities.UserDetailed) {
}
async function onClick() {
- pleaseLogin(undefined, { type: 'web', path: `/@${props.user.username}@${props.user.host ?? host}` });
+ pleaseLogin({ openOnRemote: { type: 'web', path: `/@${props.user.username}@${props.user.host ?? host}` } });
wait.value = true;
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue
index 828ad2e872..425c4992da 100644
--- a/packages/frontend/src/components/MkNote.vue
+++ b/packages/frontend/src/components/MkNote.vue
@@ -419,7 +419,7 @@ if (!props.mock) {
}
function renote(viaKeyboard = false) {
- pleaseLogin(undefined, pleaseLoginContext.value);
+ pleaseLogin({ openOnRemote: pleaseLoginContext.value });
showMovedDialog();
const { menu } = getRenoteMenu({ note: note.value, renoteButton, mock: props.mock });
@@ -429,7 +429,7 @@ function renote(viaKeyboard = false) {
}
function reply(): void {
- pleaseLogin(undefined, pleaseLoginContext.value);
+ pleaseLogin({ openOnRemote: pleaseLoginContext.value });
if (props.mock) {
return;
}
@@ -442,7 +442,7 @@ function reply(): void {
}
function react(): void {
- pleaseLogin(undefined, pleaseLoginContext.value);
+ pleaseLogin({ openOnRemote: pleaseLoginContext.value });
showMovedDialog();
if (appearNote.value.reactionAcceptance === 'likeOnly') {
sound.playMisskeySfx('reaction');
@@ -563,7 +563,7 @@ function showRenoteMenu(): void {
}
if (isMyRenote) {
- pleaseLogin(undefined, pleaseLoginContext.value);
+ pleaseLogin({ openOnRemote: pleaseLoginContext.value });
os.popupMenu([
getCopyNoteLinkMenu(note.value, i18n.ts.copyLinkRenote),
{ type: 'divider' },
diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue
index 6d53685651..e0473dce5e 100644
--- a/packages/frontend/src/components/MkNoteDetailed.vue
+++ b/packages/frontend/src/components/MkNoteDetailed.vue
@@ -207,6 +207,7 @@ import { computed, inject, onMounted, provide, ref, shallowRef } from 'vue';
import * as mfm from 'mfm-js';
import * as Misskey from 'misskey-js';
import { isLink } from '@@/js/is-link.js';
+import { host } from '@@/js/config.js';
import MkNoteSub from '@/components/MkNoteSub.vue';
import MkNoteSimple from '@/components/MkNoteSimple.vue';
import MkReactionsViewer from '@/components/MkReactionsViewer.vue';
@@ -230,7 +231,6 @@ import { reactionPicker } from '@/scripts/reaction-picker.js';
import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js';
import { $i } from '@/account.js';
import { i18n } from '@/i18n.js';
-import { host } from '@@/js/config.js';
import { getNoteClipMenu, getNoteMenu, getRenoteMenu } from '@/scripts/get-note-menu.js';
import { useNoteCapture } from '@/scripts/use-note-capture.js';
import { deepClone } from '@/scripts/clone.js';
@@ -404,7 +404,7 @@ if (appearNote.value.reactionAcceptance === 'likeOnly') {
}
function renote() {
- pleaseLogin(undefined, pleaseLoginContext.value);
+ pleaseLogin({ openOnRemote: pleaseLoginContext.value });
showMovedDialog();
const { menu } = getRenoteMenu({ note: note.value, renoteButton });
@@ -412,7 +412,7 @@ function renote() {
}
function reply(): void {
- pleaseLogin(undefined, pleaseLoginContext.value);
+ pleaseLogin({ openOnRemote: pleaseLoginContext.value });
showMovedDialog();
os.post({
reply: appearNote.value,
@@ -423,7 +423,7 @@ function reply(): void {
}
function react(): void {
- pleaseLogin(undefined, pleaseLoginContext.value);
+ pleaseLogin({ openOnRemote: pleaseLoginContext.value });
showMovedDialog();
if (appearNote.value.reactionAcceptance === 'likeOnly') {
sound.playMisskeySfx('reaction');
@@ -499,7 +499,7 @@ async function clip(): Promise<void> {
function showRenoteMenu(): void {
if (!isMyRenote) return;
- pleaseLogin(undefined, pleaseLoginContext.value);
+ pleaseLogin({ openOnRemote: pleaseLoginContext.value });
os.popupMenu([{
text: i18n.ts.unrenote,
icon: 'ti ti-trash',
diff --git a/packages/frontend/src/components/MkPoll.vue b/packages/frontend/src/components/MkPoll.vue
index 48913004e0..e70ac7ff1a 100644
--- a/packages/frontend/src/components/MkPoll.vue
+++ b/packages/frontend/src/components/MkPoll.vue
@@ -29,14 +29,14 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed, ref } from 'vue';
import * as Misskey from 'misskey-js';
+import { host } from '@@/js/config.js';
+import { useInterval } from '@@/js/use-interval.js';
import type { OpenOnRemoteOptions } from '@/scripts/please-login.js';
import { sum } from '@/scripts/array.js';
import { pleaseLogin } from '@/scripts/please-login.js';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { i18n } from '@/i18n.js';
-import { host } from '@@/js/config.js';
-import { useInterval } from '@@/js/use-interval.js';
const props = defineProps<{
noteId: string;
@@ -85,7 +85,7 @@ if (props.poll.expiresAt) {
const vote = async (id) => {
if (props.readOnly || closed.value || isVoted.value) return;
- pleaseLogin(undefined, pleaseLoginContext.value);
+ pleaseLogin({ openOnRemote: pleaseLoginContext.value });
const { canceled } = await os.confirm({
type: 'question',
diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts
index 4d41cf5bc0..07d91a0644 100644
--- a/packages/frontend/src/os.ts
+++ b/packages/frontend/src/os.ts
@@ -688,14 +688,16 @@ export function contextMenu(items: MenuItem[], ev: MouseEvent): Promise<void> {
}
export function post(props: Record<string, any> = {}): Promise<void> {
- pleaseLogin(undefined, (props.initialText || props.initialNote ? {
- type: 'share',
- params: {
- text: props.initialText ?? props.initialNote.text,
- visibility: props.initialVisibility ?? props.initialNote?.visibility,
- localOnly: (props.initialLocalOnly || props.initialNote?.localOnly) ? '1' : '0',
- },
- } : undefined));
+ pleaseLogin({
+ openOnRemote: (props.initialText || props.initialNote ? {
+ type: 'share',
+ params: {
+ text: props.initialText ?? props.initialNote.text,
+ visibility: props.initialVisibility ?? props.initialNote?.visibility,
+ localOnly: (props.initialLocalOnly || props.initialNote?.localOnly) ? '1' : '0',
+ },
+ } : undefined),
+ });
showMovedDialog();
return new Promise(resolve => {
diff --git a/packages/frontend/src/pages/not-found.vue b/packages/frontend/src/pages/not-found.vue
index 93a792c42f..6a2d01b6fa 100644
--- a/packages/frontend/src/pages/not-found.vue
+++ b/packages/frontend/src/pages/not-found.vue
@@ -24,7 +24,7 @@ const props = defineProps<{
}>();
if (props.showLoginPopup) {
- pleaseLogin('/');
+ pleaseLogin({ path: '/' });
}
const headerActions = computed(() => []);
diff --git a/packages/frontend/src/pages/note.vue b/packages/frontend/src/pages/note.vue
index 448244204d..454ee3c6bc 100644
--- a/packages/frontend/src/pages/note.vue
+++ b/packages/frontend/src/pages/note.vue
@@ -61,6 +61,7 @@ import { i18n } from '@/i18n.js';
import { dateString } from '@/filters/date.js';
import MkClipPreview from '@/components/MkClipPreview.vue';
import { defaultStore } from '@/store.js';
+import { pleaseLogin } from '@/scripts/please-login.js';
const props = defineProps<{
noteId: string;
@@ -128,6 +129,11 @@ function fetchNote() {
});
}
}).catch(err => {
+ if (err.id === '8e75455b-738c-471d-9f80-62693f33372e') {
+ pleaseLogin({
+ message: i18n.ts.thisContentsAreMarkedAsSigninRequiredByAuthor,
+ });
+ }
error.value = err;
});
}
diff --git a/packages/frontend/src/pages/settings/privacy.vue b/packages/frontend/src/pages/settings/privacy.vue
index d418be624e..e277dfad71 100644
--- a/packages/frontend/src/pages/settings/privacy.vue
+++ b/packages/frontend/src/pages/settings/privacy.vue
@@ -36,7 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #caption>{{ i18n.ts.noCrawleDescription }}</template>
</MkSwitch>
<MkSwitch v-model="preventAiLearning" @update:modelValue="save()">
- {{ i18n.ts.preventAiLearning }}<span class="_beta">{{ i18n.ts.beta }}</span>
+ {{ i18n.ts.preventAiLearning }}
<template #caption>{{ i18n.ts.preventAiLearningDescription }}</template>
</MkSwitch>
<MkSwitch v-model="isExplorable" @update:modelValue="save()">
@@ -45,6 +45,21 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkSwitch>
<FormSection>
+ <template #label>{{ i18n.ts.lockdown }}</template>
+
+ <div class="_gaps_m">
+ <MkSwitch v-model="requireSigninToViewContents" @update:modelValue="save()">
+ {{ i18n.ts._accountSettings.requireSigninToViewContents }}<span class="_beta">{{ i18n.ts.beta }}</span>
+ <template #caption>
+ <div>{{ i18n.ts._accountSettings.requireSigninToViewContentsDescription1 }}</div>
+ <div><i class="ti ti-alert-triangle" style="color: var(--MI_THEME-warn);"></i> {{ i18n.ts._accountSettings.requireSigninToViewContentsDescription2 }}</div>
+ <div><i class="ti ti-alert-triangle" style="color: var(--MI_THEME-warn);"></i> {{ i18n.ts._accountSettings.requireSigninToViewContentsDescription3 }}</div>
+ </template>
+ </MkSwitch>
+ </div>
+ </FormSection>
+
+ <FormSection>
<div class="_gaps_m">
<MkSwitch v-model="rememberNoteVisibility" @update:modelValue="save()">{{ i18n.ts.rememberNoteVisibility }}</MkSwitch>
<MkFolder v-if="!rememberNoteVisibility">
@@ -90,6 +105,7 @@ const autoAcceptFollowed = ref($i.autoAcceptFollowed);
const noCrawle = ref($i.noCrawle);
const preventAiLearning = ref($i.preventAiLearning);
const isExplorable = ref($i.isExplorable);
+const requireSigninToViewContents = ref($i.requireSigninToViewContents ?? false);
const hideOnlineStatus = ref($i.hideOnlineStatus);
const publicReactions = ref($i.publicReactions);
const followingVisibility = ref($i.followingVisibility);
@@ -107,6 +123,7 @@ function save() {
noCrawle: !!noCrawle.value,
preventAiLearning: !!preventAiLearning.value,
isExplorable: !!isExplorable.value,
+ requireSigninToViewContents: !!requireSigninToViewContents.value,
hideOnlineStatus: !!hideOnlineStatus.value,
publicReactions: !!publicReactions.value,
followingVisibility: followingVisibility.value,
diff --git a/packages/frontend/src/scripts/please-login.ts b/packages/frontend/src/scripts/please-login.ts
index 18f05bc7f4..43dcf11936 100644
--- a/packages/frontend/src/scripts/please-login.ts
+++ b/packages/frontend/src/scripts/please-login.ts
@@ -44,17 +44,21 @@ export type OpenOnRemoteOptions = {
params: Record<string, string>;
};
-export function pleaseLogin(path?: string, openOnRemote?: OpenOnRemoteOptions) {
+export function pleaseLogin(opts: {
+ path?: string;
+ message?: string;
+ openOnRemote?: OpenOnRemoteOptions;
+} = {}) {
if ($i) return;
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {
autoSet: true,
- message: openOnRemote ? i18n.ts.signinOrContinueOnRemote : i18n.ts.signinRequired,
- openOnRemote,
+ message: opts.message ?? (opts.openOnRemote ? i18n.ts.signinOrContinueOnRemote : i18n.ts.signinRequired),
+ openOnRemote: opts.openOnRemote,
}, {
cancelled: () => {
- if (path) {
- window.location.href = path;
+ if (opts.path) {
+ window.location.href = opts.path;
}
},
closed: () => dispose(),
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 698c08826a..8f84aa37ff 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -3736,6 +3736,7 @@ export type components = {
}[];
isBot?: boolean;
isCat?: boolean;
+ requireSigninToViewContents?: boolean;
instance?: {
name: string | null;
softwareName: string | null;
@@ -19844,6 +19845,7 @@ export type operations = {
autoAcceptFollowed?: boolean;
noCrawle?: boolean;
preventAiLearning?: boolean;
+ requireSigninToViewContents?: boolean;
isBot?: boolean;
isCat?: boolean;
injectFeaturedNote?: boolean;