From 708a8d28a68064ac76ee7452284405c3dd084320 Mon Sep 17 00:00:00 2001 From: ltlapy Date: Fri, 27 Dec 2024 13:09:57 +0900 Subject: [PATCH] feat: Requiring credential to view local timeline --- locales/en-US.yml | 1 + locales/ja-JP.yml | 1 + locales/ko-KR.yml | 1 + locales/ko-NYAN.yml | 1 + ...34-add-local-timeline-requires-credential.ts | 13 +++++++++++++ packages/backend/src/models/entities/meta.ts | 5 +++++ .../src/server/api/endpoints/admin/meta.ts | 1 + .../server/api/endpoints/admin/update-meta.ts | 5 +++++ .../backend/src/server/api/endpoints/meta.ts | 6 ++++++ .../src/server/api/endpoints/notes/featured.ts | 17 +++++++++++++++++ .../api/endpoints/notes/local-timeline.ts | 2 +- .../api/stream/channels/local-timeline.ts | 2 +- packages/backend/src/server/nodeinfo.ts | 1 + .../client/src/components/MkTutorialDialog.vue | 2 +- packages/client/src/pages/admin/settings.vue | 9 +++++++++ packages/client/src/pages/timeline.vue | 2 +- .../iceshrimp-sdk/etc/iceshrimp-sdk.api.json | 2 +- packages/iceshrimp-sdk/etc/iceshrimp-sdk.api.md | 1 + ...eshrimp-sdk.entities.liteinstancemetadata.md | 1 + packages/iceshrimp-sdk/src/entities.ts | 1 + 20 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 packages/backend/src/migration/1735271639334-add-local-timeline-requires-credential.ts diff --git a/locales/en-US.yml b/locales/en-US.yml index 046be6788..f23a11fd5 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -2181,3 +2181,4 @@ _wellness: newPostsButton: "Enable new posts alert button" newPostsGlowOpacity: "New posts glow opacity" immediacy: "Immediacy" +localTimelineRequiresCredential: Disable local timeline for non-logged in users \ No newline at end of file diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index c5b181991..03b6f8975 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1972,3 +1972,4 @@ _cwStyle: alternative: 代替(Firefish-like) cwStyle: 閲覧注意投稿の表示スタイル searchNotLoggedIn_2: しかし、ハッシュタグ検索とユーザー検索は利用できます。 +localTimelineRequiresCredential: 非ログインユーザーにローカルタイムラインを非公開 \ No newline at end of file diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index e4a8b930f..f80d779aa 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -1899,3 +1899,4 @@ removeMember: 멤버 삭제하기 searchEmptyQuery: 검색할 내용을 입력해주세요. searchNotLoggedIn_1: 전체 텍스트 검색을 하려면 먼저 로그인해야 합니다. searchNotLoggedIn_2: 대신, 해시태그나 유저를 검색할 수 있습니다. +localTimelineRequiresCredential: 비로그인 상태의 로컬 타임라인 열람 제한 \ No newline at end of file diff --git a/locales/ko-NYAN.yml b/locales/ko-NYAN.yml index 47ed2008d..994656986 100644 --- a/locales/ko-NYAN.yml +++ b/locales/ko-NYAN.yml @@ -1887,3 +1887,4 @@ removeMember: 멤버 삭제하기 searchEmptyQuery: 검색할 내용을 입력해달라냥. searchNotLoggedIn_1: 전체 텍스트 검색을 하려면 먼저 로그인해야 한다냥. searchNotLoggedIn_2: 대신, 해시태그나 유저를 검색할 수 있다냥. +localTimelineRequiresCredential: 비로그인 상태의 로컬 타임라인 열람 제한 diff --git a/packages/backend/src/migration/1735271639334-add-local-timeline-requires-credential.ts b/packages/backend/src/migration/1735271639334-add-local-timeline-requires-credential.ts new file mode 100644 index 000000000..8933e9642 --- /dev/null +++ b/packages/backend/src/migration/1735271639334-add-local-timeline-requires-credential.ts @@ -0,0 +1,13 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddLocalTimelineRequiresCredential1735271639334 implements MigrationInterface { + name = 'AddLocalTimelineRequiresCredential1735271639334' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "meta" ADD "localTimelineRequiresCredential" boolean;`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "localTimelineRequiresCredential"`); + } +} diff --git a/packages/backend/src/models/entities/meta.ts b/packages/backend/src/models/entities/meta.ts index dfebad853..8583f1f40 100644 --- a/packages/backend/src/models/entities/meta.ts +++ b/packages/backend/src/models/entities/meta.ts @@ -45,6 +45,11 @@ export class Meta { default: false, }) public disableRegistration: boolean; + + @Column("boolean", { + default: false, + }) + public localTimelineRequiresCredential: boolean; @Column("boolean", { default: false, diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 4a5a4eea6..6853150e7 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -425,6 +425,7 @@ export default define(meta, paramDef, async (ps, me) => { repositoryUrl: instance.repositoryUrl, feedbackUrl: instance.feedbackUrl, disableRegistration: instance.disableRegistration, + localTimelineRequiresCredential: instance.localTimelineRequiresCredential, disableLocalTimeline: instance.disableLocalTimeline, disableRecommendedTimeline: instance.disableRecommendedTimeline, disableGlobalTimeline: instance.disableGlobalTimeline, diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index 90f089c78..be6b73c40 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -18,6 +18,7 @@ export const paramDef = { type: "object", properties: { disableRegistration: { type: "boolean", nullable: true }, + localTimelineRequiresCredential: { type: "boolean", nullable: true }, disableLocalTimeline: { type: "boolean", nullable: true }, disableRecommendedTimeline: { type: "boolean", nullable: true }, disableGlobalTimeline: { type: "boolean", nullable: true }, @@ -178,6 +179,10 @@ export default define(meta, paramDef, async (ps, me) => { set.disableRegistration = ps.disableRegistration; } + if (typeof ps.localTimelineRequiresCredential === "boolean") { + set.localTimelineRequiresCredential = ps.localTimelineRequiresCredential; + } + if (typeof ps.disableLocalTimeline === "boolean") { set.disableLocalTimeline = ps.disableLocalTimeline; } diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 834562dae..9e811665d 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -98,6 +98,11 @@ export const meta = { optional: false, nullable: false, }, + localTimelineRequiresCredential: { + type: "boolean", + optional: false, + nullable: false, + }, disableLocalTimeline: { type: "boolean", optional: false, @@ -409,6 +414,7 @@ export default define(meta, paramDef, async (ps, me) => { privateMode: instance.privateMode, disableRegistration: instance.disableRegistration, + localTimelineRequiresCredential: instance.localTimelineRequiresCredential, disableLocalTimeline: instance.disableLocalTimeline, disableRecommendedTimeline: instance.disableRecommendedTimeline, disableGlobalTimeline: instance.disableGlobalTimeline, diff --git a/packages/backend/src/server/api/endpoints/notes/featured.ts b/packages/backend/src/server/api/endpoints/notes/featured.ts index 04a36f974..b89b28c0e 100644 --- a/packages/backend/src/server/api/endpoints/notes/featured.ts +++ b/packages/backend/src/server/api/endpoints/notes/featured.ts @@ -1,5 +1,7 @@ +import { fetchMeta } from "@/misc/fetch-meta.js"; import { Notes } from "@/models/index.js"; import define from "../../define.js"; +import { ApiError } from "../../error.js"; import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js"; import { generateBlockedUserQuery } from "../../common/generate-block-query.js"; @@ -20,6 +22,14 @@ export const meta = { ref: "Note", }, }, + + errors: { + ltlDisabled: { + message: "Local timeline has been disabled.", + code: "LTL_DISABLED", + id: "45a6eb02-7695-4393-b023-dd3be9aaaefd", + }, + } } as const; export const paramDef = { @@ -38,6 +48,13 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, user) => { + const m = await fetchMeta(); + if (m.disableLocalTimeline || m.localTimelineRequiresCredential) { + if (user == null || !(user.isAdmin || user.isModerator)) { + throw new ApiError(meta.errors.ltlDisabled); + } + } + const max = 30; const day = 1000 * 60 * 60 * 24 * ps.days; diff --git a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts index 443222964..d292aa430 100644 --- a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts @@ -72,7 +72,7 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { const m = await fetchMeta(); - if (m.disableLocalTimeline) { + if (m.disableLocalTimeline || m.localTimelineRequiresCredential) { if (user == null || !(user.isAdmin || user.isModerator)) { throw new ApiError(meta.errors.ltlDisabled); } diff --git a/packages/backend/src/server/api/stream/channels/local-timeline.ts b/packages/backend/src/server/api/stream/channels/local-timeline.ts index 39f59d4a9..c44e4b869 100644 --- a/packages/backend/src/server/api/stream/channels/local-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts @@ -18,7 +18,7 @@ export default class extends Channel { public async init(params: any) { const meta = await fetchMeta(); - if (meta.disableLocalTimeline) { + if (meta.disableLocalTimeline || meta.localTimelineRequiresCredential && this.user == null) { if (this.user == null || !(this.user.isAdmin || this.user.isModerator)) return; } diff --git a/packages/backend/src/server/nodeinfo.ts b/packages/backend/src/server/nodeinfo.ts index 65fe5a3f4..90000043e 100644 --- a/packages/backend/src/server/nodeinfo.ts +++ b/packages/backend/src/server/nodeinfo.ts @@ -74,6 +74,7 @@ const nodeinfo2 = async () => { repositoryUrl: meta.repositoryUrl, feedbackUrl: meta.feedbackUrl, disableRegistration: meta.disableRegistration, + localTimelineRequiresCredential: meta.localTimelineRequiresCredential, disableLocalTimeline: meta.disableLocalTimeline, disableRecommendedTimeline: meta.disableRecommendedTimeline, disableGlobalTimeline: meta.disableGlobalTimeline, diff --git a/packages/client/src/components/MkTutorialDialog.vue b/packages/client/src/components/MkTutorialDialog.vue index dd5336d47..968e22d0d 100644 --- a/packages/client/src/components/MkTutorialDialog.vue +++ b/packages/client/src/components/MkTutorialDialog.vue @@ -221,7 +221,7 @@ import { $i } from "@/account"; import { instance } from "@/instance"; const isLocalTimelineAvailable = - !instance.disableLocalTimeline || + (!instance.disableLocalTimeline && (!instance.localTimelineRequiresCredential || $i != null)) || ($i != null && ($i.isModerator || $i.isAdmin)); const isRecommendedTimelineAvailable = !instance.disableRecommendedTimeline || diff --git a/packages/client/src/pages/admin/settings.vue b/packages/client/src/pages/admin/settings.vue index 8062b6955..280b02f5f 100644 --- a/packages/client/src/pages/admin/settings.vue +++ b/packages/client/src/pages/admin/settings.vue @@ -123,6 +123,12 @@ class="_formBlock" >{{ i18n.ts.enableLocalTimeline }} + {{ i18n.ts.localTimelineRequiresCredential }}