From 788708262298c6fc626c1c067a5c37fa7bf231f6 Mon Sep 17 00:00:00 2001 From: nullobsi Date: Mon, 19 Jul 2021 15:41:23 -0700 Subject: [PATCH 1/5] Add migration for allowedHosts, secureMode, privateMode --- .../1626733991004-allowlist-secure-mode.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 packages/backend/migration/1626733991004-allowlist-secure-mode.js diff --git a/packages/backend/migration/1626733991004-allowlist-secure-mode.js b/packages/backend/migration/1626733991004-allowlist-secure-mode.js new file mode 100644 index 0000000000..aa3fcf8752 --- /dev/null +++ b/packages/backend/migration/1626733991004-allowlist-secure-mode.js @@ -0,0 +1,17 @@ + + +export class allowlistSecureMode1626733991004 { + name = 'allowlistSecureMode1626733991004'; + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "allowedHosts" character varying(256) [] default '{}'`); + await queryRunner.query(`ALTER TABLE "meta" ADD "secureMode" bool default false`); + await queryRunner.query(`ALTER TABLE "meta" ADD "privateMode" bool default false`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "allowedHosts"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "secureMode"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "privateMode"`); + } +} + From a03f13fb3f7e5f6ce8eddfc53330c707cd5e8aef Mon Sep 17 00:00:00 2001 From: nullobsi Date: Tue, 20 Jul 2021 09:45:41 -0700 Subject: [PATCH 2/5] Add Secure Mode and Private Mode - Add instance actor - Add private mode, which uses an allowlist - Add Secure Mode, restricts access to blocked instances --- packages/backend/src/models/entities/meta.ts | 15 +++ .../backend/src/queue/processors/deliver.ts | 4 + .../backend/src/queue/processors/inbox.ts | 5 + .../src/remote/activitypub/check-fetch.ts | 73 ++++++++++ .../src/remote/activitypub/resolver.ts | 4 + packages/backend/src/server/activitypub.ts | 127 ++++++++++++++++-- .../src/server/activitypub/featured.ts | 16 ++- .../src/server/activitypub/followers.ts | 15 ++- .../src/server/activitypub/following.ts | 15 ++- .../backend/src/server/activitypub/outbox.ts | 16 ++- .../backend/src/server/api/endpoints/meta.ts | 12 +- 11 files changed, 289 insertions(+), 13 deletions(-) create mode 100644 packages/backend/src/remote/activitypub/check-fetch.ts diff --git a/packages/backend/src/models/entities/meta.ts b/packages/backend/src/models/entities/meta.ts index d33ff2519e..42c763d27d 100644 --- a/packages/backend/src/models/entities/meta.ts +++ b/packages/backend/src/models/entities/meta.ts @@ -77,6 +77,21 @@ export class Meta { }) public blockedHosts: string[]; + @Column('boolean', { + default: false + }) + public secureMode: boolean; + + @Column('boolean', { + default: false + }) + public privateMode: boolean; + + @Column('varchar', { + length: 256, array: true, default: '{}' + }) + public allowedHosts: string[]; + @Column('varchar', { length: 512, array: true, default: '{/featured,/channels,/explore,/pages,/about-misskey}', }) diff --git a/packages/backend/src/queue/processors/deliver.ts b/packages/backend/src/queue/processors/deliver.ts index 291c05766e..01ba4381a2 100644 --- a/packages/backend/src/queue/processors/deliver.ts +++ b/packages/backend/src/queue/processors/deliver.ts @@ -28,6 +28,10 @@ export default async (job: Bull.Job) => { return 'skip (blocked)'; } + if (meta.privateMode && !meta.allowedHosts.includes(toPuny(host))) { + return 'skip (not allowed)'; + } + // isSuspendedなら中断 let suspendedHosts = suspendedHostsCache.get(null); if (suspendedHosts == null) { diff --git a/packages/backend/src/queue/processors/inbox.ts b/packages/backend/src/queue/processors/inbox.ts index 198dde6050..422632059a 100644 --- a/packages/backend/src/queue/processors/inbox.ts +++ b/packages/backend/src/queue/processors/inbox.ts @@ -39,6 +39,11 @@ export default async (job: Bull.Job): Promise => { return `Blocked request: ${host}`; } + // 非公開モードなら許可なインスタンスのみ + if (meta.privateMode && !meta.allowedHosts.includes(host)) { + return `Blocked request: ${host}`; + } + const keyIdLower = signature.keyId.toLowerCase(); if (keyIdLower.startsWith('acct:')) { return `Old keyId is no longer supported. ${keyIdLower}`; diff --git a/packages/backend/src/remote/activitypub/check-fetch.ts b/packages/backend/src/remote/activitypub/check-fetch.ts new file mode 100644 index 0000000000..8a53396b6d --- /dev/null +++ b/packages/backend/src/remote/activitypub/check-fetch.ts @@ -0,0 +1,73 @@ +import config from '@/config/index.js'; +import { IncomingMessage } from 'http'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import httpSignature from '@peertube/http-signature'; +import { URL } from 'url'; +import { toPuny } from '@/misc/convert-host.js'; +import DbResolver from '@/remote/activitypub/db-resolver.js'; +import { getApId } from '@/remote/activitypub/type.js'; + + +export default async function checkFetch(req: IncomingMessage): Promise { + const meta = await fetchMeta(); + if (meta.secureMode || meta.privateMode) { + let signature; + + try { + signature = httpSignature.parseRequest(req, { 'headers': [] }); + } catch (e) { + return 401; + } + + const keyId = new URL(signature.keyId); + const host = toPuny(keyId.hostname); + + if (meta.blockedHosts.includes(host)) { + return 403; + } + + if (meta.privateMode && host !== config.host && !meta.allowedHosts.includes(host)) { + return 403; + } + + const keyIdLower = signature.keyId.toLowerCase(); + if (keyIdLower.startsWith('acct:')) { + // Old keyId is no longer supported. + return 401; + } + + const dbResolver = new DbResolver(); + + // HTTP-Signature keyIdを元にDBから取得 + let authUser = await dbResolver.getAuthUserFromKeyId(signature.keyId); + + // keyIdでわからなければ、resolveしてみる + if (authUser == null) { + try { + keyId.hash = ''; + authUser = await dbResolver.getAuthUserFromApId(getApId(keyId.toString())); + } catch (e) { + // できなければ駄目 + return 403; + } + } + + // publicKey がなくても終了 + if (authUser?.key == null) { + return 403; + } + + // もう一回チェック + if (authUser.user.host !== host) { + return 403; + } + + // HTTP-Signatureの検証 + const httpSignatureValidated = httpSignature.verifySignature(signature, authUser.key.keyPem); + + if (!httpSignatureValidated) { + return 403; + } + } + return 200; +} diff --git a/packages/backend/src/remote/activitypub/resolver.ts b/packages/backend/src/remote/activitypub/resolver.ts index 2f9af43c0c..e89a7b21a7 100644 --- a/packages/backend/src/remote/activitypub/resolver.ts +++ b/packages/backend/src/remote/activitypub/resolver.ts @@ -72,6 +72,10 @@ export default class Resolver { throw new Error('Instance is blocked'); } + if (meta.privateMode && config.host !== host && !meta.allowedHosts.includes(host)) { + throw new Error('Instance is not allowed'); + } + if (config.signToActivityPubGet && !this.user) { this.user = await getInstanceActor(); } diff --git a/packages/backend/src/server/activitypub.ts b/packages/backend/src/server/activitypub.ts index cd5f917c40..250a39bf04 100644 --- a/packages/backend/src/server/activitypub.ts +++ b/packages/backend/src/server/activitypub.ts @@ -12,12 +12,15 @@ import Followers from './activitypub/followers.js'; import Following from './activitypub/following.js'; import Featured from './activitypub/featured.js'; import { inbox as processInbox } from '@/queue/index.js'; -import { isSelfHost } from '@/misc/convert-host.js'; +import { isSelfHost, toPuny } from '@/misc/convert-host.js'; import { Notes, Users, Emojis, NoteReactions } from '@/models/index.js'; import { ILocalUser, User } from '@/models/entities/user.js'; import { In, IsNull, Not } from 'typeorm'; import { renderLike } from '@/remote/activitypub/renderer/like.js'; import { getUserKeypair } from '@/misc/keypair-store.js'; +import checkFetch from '@/remote/activitypub/check-fetch.js'; +import { getInstanceActor } from '@/services/instance-actor.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; import renderFollow from '@/remote/activitypub/renderer/follow.js'; // Init router @@ -66,6 +69,12 @@ router.post('/users/:user/inbox', json(), inbox); router.get('/notes/:note', async (ctx, next) => { if (!isActivityPubReq(ctx)) return await next(); + const verify = await checkFetch(ctx.req); + if (verify != 200) { + ctx.status = verify; + return; + } + const note = await Notes.findOneBy({ id: ctx.params.note, visibility: In(['public' as const, 'home' as const]), @@ -88,12 +97,24 @@ router.get('/notes/:note', async (ctx, next) => { } ctx.body = renderActivity(await renderNote(note, false)); - ctx.set('Cache-Control', 'public, max-age=180'); + + const meta = await fetchMeta(); + if (meta.secureMode || meta.privateMode) { + ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + } else { + ctx.set('Cache-Control', 'public, max-age=180'); + } setResponseType(ctx); }); // note activity router.get('/notes/:note/activity', async ctx => { + const verify = await checkFetch(ctx.req); + if (verify != 200) { + ctx.status = verify; + return; + } + const note = await Notes.findOneBy({ id: ctx.params.note, userHost: IsNull(), @@ -107,7 +128,12 @@ router.get('/notes/:note/activity', async ctx => { } ctx.body = renderActivity(await packActivity(note)); - ctx.set('Cache-Control', 'public, max-age=180'); + const meta = await fetchMeta(); + if (meta.secureMode || meta.privateMode) { + ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + } else { + ctx.set('Cache-Control', 'public, max-age=180'); + } setResponseType(ctx); }); @@ -125,6 +151,20 @@ router.get('/users/:user/collections/featured', Featured); // publickey router.get('/users/:user/publickey', async ctx => { + const instanceActor = await getInstanceActor(); + if (ctx.params.user === instanceActor.id) { + ctx.body = renderActivity(renderKey(instanceActor, await getUserKeypair(instanceActor.id))); + ctx.set('Cache-Control', 'public, max-age=180'); + setResponseType(ctx); + return; + } + + const verify = await checkFetch(ctx.req); + if (verify != 200) { + ctx.status = verify; + return; + } + const userId = ctx.params.user; const user = await Users.findOneBy({ @@ -141,7 +181,12 @@ router.get('/users/:user/publickey', async ctx => { if (Users.isLocalUser(user)) { ctx.body = renderActivity(renderKey(user, keypair)); - ctx.set('Cache-Control', 'public, max-age=180'); + const meta = await fetchMeta(); + if (meta.secureMode || meta.privateMode) { + ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + } else { + ctx.set('Cache-Control', 'public, max-age=180'); + } setResponseType(ctx); } else { ctx.status = 400; @@ -156,13 +201,30 @@ async function userInfo(ctx: Router.RouterContext, user: User | null) { } ctx.body = renderActivity(await renderPerson(user as ILocalUser)); - ctx.set('Cache-Control', 'public, max-age=180'); + const meta = await fetchMeta(); + if (meta.secureMode || meta.privateMode) { + ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + } else { + ctx.set('Cache-Control', 'public, max-age=180'); + } setResponseType(ctx); } router.get('/users/:user', async (ctx, next) => { if (!isActivityPubReq(ctx)) return await next(); + const instanceActor = await getInstanceActor(); + if (ctx.params.user === instanceActor.id) { + await userInfo(ctx, instanceActor); + return; + } + + const verify = await checkFetch(ctx.req); + if (verify != 200) { + ctx.status = verify; + return; + } + const userId = ctx.params.user; const user = await Users.findOneBy({ @@ -177,6 +239,18 @@ router.get('/users/:user', async (ctx, next) => { router.get('/@:user', async (ctx, next) => { if (!isActivityPubReq(ctx)) return await next(); + if (ctx.params.user === 'instance.actor') { + const instanceActor = await getInstanceActor(); + await userInfo(ctx, instanceActor); + return; + } + + const verify = await checkFetch(ctx.req); + if (verify != 200) { + ctx.status = verify; + return; + } + const user = await Users.findOneBy({ usernameLower: ctx.params.user.toLowerCase(), host: IsNull(), @@ -185,10 +259,21 @@ router.get('/@:user', async (ctx, next) => { await userInfo(ctx, user); }); + +router.get('/actor', async (ctx, next) => { + const instanceActor = await getInstanceActor(); + await userInfo(ctx, instanceActor); +}); //#endregion // emoji router.get('/emojis/:emoji', async ctx => { + const verify = await checkFetch(ctx.req); + if (verify != 200) { + ctx.status = verify; + return; + } + const emoji = await Emojis.findOneBy({ host: IsNull(), name: ctx.params.emoji, @@ -200,12 +285,23 @@ router.get('/emojis/:emoji', async ctx => { } ctx.body = renderActivity(await renderEmoji(emoji)); - ctx.set('Cache-Control', 'public, max-age=180'); + const meta = await fetchMeta(); + if (meta.secureMode || meta.privateMode) { + ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + } else { + ctx.set('Cache-Control', 'public, max-age=180'); + } setResponseType(ctx); }); // like router.get('/likes/:like', async ctx => { + const verify = await checkFetch(ctx.req); + if (verify != 200) { + ctx.status = verify; + return; + } + const reaction = await NoteReactions.findOneBy({ id: ctx.params.like }); if (reaction == null) { @@ -221,12 +317,22 @@ router.get('/likes/:like', async ctx => { } ctx.body = renderActivity(await renderLike(reaction, note)); - ctx.set('Cache-Control', 'public, max-age=180'); + const meta = await fetchMeta(); + if (meta.secureMode || meta.privateMode) { + ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + } else { + ctx.set('Cache-Control', 'public, max-age=180'); + } setResponseType(ctx); }); // follow router.get('/follows/:follower/:followee', async ctx => { + const verify = await checkFetch(ctx.req); + if (verify != 200) { + ctx.status = verify; + return; + } // This may be used before the follow is completed, so we do not // check if the following exists. @@ -247,7 +353,12 @@ router.get('/follows/:follower/:followee', async ctx => { } ctx.body = renderActivity(renderFollow(follower, followee)); - ctx.set('Cache-Control', 'public, max-age=180'); + const meta = await fetchMeta(); + if (meta.secureMode || meta.privateMode) { + ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + } else { + ctx.set('Cache-Control', 'public, max-age=180'); + } setResponseType(ctx); }); diff --git a/packages/backend/src/server/activitypub/featured.ts b/packages/backend/src/server/activitypub/featured.ts index c03fd1049f..87e4f83203 100644 --- a/packages/backend/src/server/activitypub/featured.ts +++ b/packages/backend/src/server/activitypub/featured.ts @@ -6,8 +6,16 @@ import { setResponseType } from '../activitypub.js'; import renderNote from '@/remote/activitypub/renderer/note.js'; import { Users, Notes, UserNotePinings } from '@/models/index.js'; import { IsNull } from 'typeorm'; +import checkFetch from '@/remote/activitypub/check-fetch.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; export default async (ctx: Router.RouterContext) => { + const verify = await checkFetch(ctx.req); + if (verify != 200) { + ctx.status = verify; + return; + } + const userId = ctx.params.user; const user = await Users.findOneBy({ @@ -36,6 +44,12 @@ export default async (ctx: Router.RouterContext) => { ); ctx.body = renderActivity(rendered); - ctx.set('Cache-Control', 'public, max-age=180'); + + const meta = await fetchMeta(); + if (meta.secureMode || meta.privateMode) { + ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + } else { + ctx.set('Cache-Control', 'public, max-age=180'); + } setResponseType(ctx); }; diff --git a/packages/backend/src/server/activitypub/followers.ts b/packages/backend/src/server/activitypub/followers.ts index beb48713a6..833f0e77f6 100644 --- a/packages/backend/src/server/activitypub/followers.ts +++ b/packages/backend/src/server/activitypub/followers.ts @@ -9,8 +9,16 @@ import renderFollowUser from '@/remote/activitypub/renderer/follow-user.js'; import { Users, Followings, UserProfiles } from '@/models/index.js'; import { Following } from '@/models/entities/following.js'; import { setResponseType } from '../activitypub.js'; +import checkFetch from '@/remote/activitypub/check-fetch.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; export default async (ctx: Router.RouterContext) => { + const verify = await checkFetch(ctx.req); + if (verify != 200) { + ctx.status = verify; + return; + } + const userId = ctx.params.user; const cursor = ctx.request.query.cursor; @@ -89,7 +97,12 @@ export default async (ctx: Router.RouterContext) => { // index page const rendered = renderOrderedCollection(partOf, user.followersCount, `${partOf}?page=true`); ctx.body = renderActivity(rendered); - ctx.set('Cache-Control', 'public, max-age=180'); setResponseType(ctx); } + const meta = await fetchMeta(); + if (meta.secureMode || meta.privateMode) { + ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + } else { + ctx.set('Cache-Control', 'public, max-age=180'); + } }; diff --git a/packages/backend/src/server/activitypub/following.ts b/packages/backend/src/server/activitypub/following.ts index 3a25a6316c..f843d79f09 100644 --- a/packages/backend/src/server/activitypub/following.ts +++ b/packages/backend/src/server/activitypub/following.ts @@ -9,8 +9,16 @@ import renderFollowUser from '@/remote/activitypub/renderer/follow-user.js'; import { Users, Followings, UserProfiles } from '@/models/index.js'; import { Following } from '@/models/entities/following.js'; import { setResponseType } from '../activitypub.js'; +import checkFetch from '@/remote/activitypub/check-fetch.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; export default async (ctx: Router.RouterContext) => { + const verify = await checkFetch(ctx.req); + if (verify != 200) { + ctx.status = verify; + return; + } + const userId = ctx.params.user; const cursor = ctx.request.query.cursor; @@ -89,7 +97,12 @@ export default async (ctx: Router.RouterContext) => { // index page const rendered = renderOrderedCollection(partOf, user.followingCount, `${partOf}?page=true`); ctx.body = renderActivity(rendered); - ctx.set('Cache-Control', 'public, max-age=180'); setResponseType(ctx); } + const meta = await fetchMeta(); + if (meta.secureMode || meta.privateMode) { + ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + } else { + ctx.set('Cache-Control', 'public, max-age=180'); + } }; diff --git a/packages/backend/src/server/activitypub/outbox.ts b/packages/backend/src/server/activitypub/outbox.ts index 7a2586998a..4a6b5caff6 100644 --- a/packages/backend/src/server/activitypub/outbox.ts +++ b/packages/backend/src/server/activitypub/outbox.ts @@ -13,8 +13,16 @@ import { Users, Notes } from '@/models/index.js'; import { Note } from '@/models/entities/note.js'; import { makePaginationQuery } from '../api/common/make-pagination-query.js'; import { setResponseType } from '../activitypub.js'; +import checkFetch from '@/remote/activitypub/check-fetch.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; export default async (ctx: Router.RouterContext) => { + const verify = await checkFetch(ctx.req); + if (verify != 200) { + ctx.status = verify; + return; + } + const userId = ctx.params.user; const sinceId = ctx.request.query.since_id; @@ -89,9 +97,15 @@ export default async (ctx: Router.RouterContext) => { `${partOf}?page=true&since_id=000000000000000000000000`, ); ctx.body = renderActivity(rendered); - ctx.set('Cache-Control', 'public, max-age=180'); + setResponseType(ctx); } + const meta = await fetchMeta(); + if (meta.secureMode || meta.privateMode) { + ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); + } else { + ctx.set('Cache-Control', 'public, max-age=180'); + } }; /** diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 5b624842c3..ca6b471d59 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -291,6 +291,16 @@ export const meta = { }, }, }, + secureMode: { + type: 'boolean', + optional: true, nullable: false, + default: false, + }, + privateMode: { + type: 'boolean', + optional: true, nullable: false, + default: false, + }, }, }, } as const; @@ -326,7 +336,7 @@ export default define(meta, paramDef, async (ps, me) => { expiresAt: MoreThan(new Date()), }, }); - + // TODO: add secure mode, etc const response: any = { maintainerName: instance.maintainerName, maintainerEmail: instance.maintainerEmail, From 26f0483094c208fafda580c57244ba4cccb1b526 Mon Sep 17 00:00:00 2001 From: nullobsi Date: Tue, 20 Jul 2021 11:51:59 -0700 Subject: [PATCH 3/5] In private mode, block access to many public APIs --- packages/backend/src/server/api/call.ts | 13 ++++++++++++ packages/backend/src/server/api/endpoints.ts | 6 ++++++ .../src/server/api/endpoints/announcements.ts | 1 + .../server/api/endpoints/channels/featured.ts | 1 + .../src/server/api/endpoints/channels/show.ts | 1 + .../server/api/endpoints/channels/timeline.ts | 1 + .../api/endpoints/charts/active-users.ts | 1 + .../server/api/endpoints/charts/ap-request.ts | 1 + .../src/server/api/endpoints/charts/drive.ts | 1 + .../server/api/endpoints/charts/federation.ts | 1 + .../server/api/endpoints/charts/hashtag.ts | 1 + .../server/api/endpoints/charts/instance.ts | 1 + .../src/server/api/endpoints/charts/notes.ts | 1 + .../server/api/endpoints/charts/user/drive.ts | 1 + .../api/endpoints/charts/user/following.ts | 1 + .../server/api/endpoints/charts/user/notes.ts | 1 + .../api/endpoints/charts/user/reactions.ts | 1 + .../src/server/api/endpoints/charts/users.ts | 1 + .../src/server/api/endpoints/clips/notes.ts | 1 + .../src/server/api/endpoints/clips/show.ts | 1 + .../api/endpoints/federation/followers.ts | 1 + .../api/endpoints/federation/following.ts | 1 + .../api/endpoints/federation/instances.ts | 1 + .../api/endpoints/federation/show-instance.ts | 1 + .../server/api/endpoints/federation/users.ts | 1 + .../server/api/endpoints/gallery/featured.ts | 1 + .../server/api/endpoints/gallery/popular.ts | 1 + .../src/server/api/endpoints/gallery/posts.ts | 1 + .../api/endpoints/gallery/posts/show.ts | 1 + .../api/endpoints/get-online-users-count.ts | 1 + .../src/server/api/endpoints/hashtags/list.ts | 1 + .../server/api/endpoints/hashtags/search.ts | 1 + .../src/server/api/endpoints/hashtags/show.ts | 1 + .../server/api/endpoints/hashtags/trend.ts | 1 + .../server/api/endpoints/hashtags/users.ts | 1 + .../backend/src/server/api/endpoints/meta.ts | 20 ++++++++++++------- .../backend/src/server/api/endpoints/notes.ts | 1 + .../server/api/endpoints/notes/children.ts | 3 ++- .../src/server/api/endpoints/notes/clips.ts | 1 + .../api/endpoints/notes/conversation.ts | 1 + .../server/api/endpoints/notes/featured.ts | 1 + .../api/endpoints/notes/global-timeline.ts | 1 + .../api/endpoints/notes/local-timeline.ts | 1 + .../server/api/endpoints/notes/reactions.ts | 1 + .../src/server/api/endpoints/notes/renotes.ts | 1 + .../src/server/api/endpoints/notes/replies.ts | 1 + .../api/endpoints/notes/search-by-tag.ts | 1 + .../src/server/api/endpoints/notes/search.ts | 1 + .../src/server/api/endpoints/notes/show.ts | 1 + .../server/api/endpoints/notes/translate.ts | 1 + .../server/api/endpoints/pages/featured.ts | 1 + .../src/server/api/endpoints/pages/show.ts | 1 + .../src/server/api/endpoints/pinned-users.ts | 1 + .../src/server/api/endpoints/server-info.ts | 1 + .../backend/src/server/api/endpoints/stats.ts | 1 + .../backend/src/server/api/endpoints/users.ts | 1 + .../src/server/api/endpoints/users/clips.ts | 1 + .../server/api/endpoints/users/followers.ts | 1 + .../server/api/endpoints/users/following.ts | 1 + .../api/endpoints/users/gallery/posts.ts | 1 + .../users/get-frequently-replied-users.ts | 1 + .../src/server/api/endpoints/users/notes.ts | 1 + .../src/server/api/endpoints/users/pages.ts | 1 + .../server/api/endpoints/users/reactions.ts | 1 + .../users/search-by-username-and-host.ts | 1 + .../src/server/api/endpoints/users/search.ts | 1 + .../src/server/api/endpoints/users/show.ts | 1 + .../src/server/api/endpoints/users/stats.ts | 1 + 68 files changed, 98 insertions(+), 8 deletions(-) diff --git a/packages/backend/src/server/api/call.ts b/packages/backend/src/server/api/call.ts index aa130459a3..9458d15fe0 100644 --- a/packages/backend/src/server/api/call.ts +++ b/packages/backend/src/server/api/call.ts @@ -7,6 +7,8 @@ import { limiter } from './limiter.js'; import endpoints, { IEndpointMeta } from './endpoints.js'; import { ApiError } from './error.js'; import { apiLogger } from './logger.js'; +import { AccessToken } from '@/models/entities/access-token.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; const accessDenied = { message: 'Access denied.', @@ -93,6 +95,17 @@ export default async (endpoint: string, user: CacheableLocalUser | null | undefi }); } + // private mode + const meta = await fetchMeta(); + if (meta.privateMode && ep.meta.requireCredentialPrivateMode && user == null) { + throw new ApiError({ + message: 'Credential required.', + code: 'CREDENTIAL_REQUIRED', + id: '1384574d-a912-4b81-8601-c7b1c4085df1', + httpStatusCode: 401 + }); + } + // Cast non JSON input if ((ep.meta.requireFile || ctx?.method === 'GET') && ep.params.properties) { for (const k of Object.keys(ep.params.properties)) { diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 4644f34d94..d7fcc32d38 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -706,6 +706,12 @@ export interface IEndpointMeta { */ readonly secure?: boolean; + /** + * プライベートモードでなら、このエンドポイントにリクエストするときにユーザー情報が必要か否か + * 省略した場合は false として解釈されます + */ + readonly requireCredentialPrivateMode?: boolean; + /** * エンドポイントの種類 * パーミッションの実現に利用されます。 diff --git a/packages/backend/src/server/api/endpoints/announcements.ts b/packages/backend/src/server/api/endpoints/announcements.ts index 23cb93c9a5..189de042b5 100644 --- a/packages/backend/src/server/api/endpoints/announcements.ts +++ b/packages/backend/src/server/api/endpoints/announcements.ts @@ -6,6 +6,7 @@ export const meta = { tags: ['meta'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/channels/featured.ts b/packages/backend/src/server/api/endpoints/channels/featured.ts index 73980c0fad..13ad6ca7d6 100644 --- a/packages/backend/src/server/api/endpoints/channels/featured.ts +++ b/packages/backend/src/server/api/endpoints/channels/featured.ts @@ -5,6 +5,7 @@ export const meta = { tags: ['channels'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/channels/show.ts b/packages/backend/src/server/api/endpoints/channels/show.ts index 87665a9865..1c8461af45 100644 --- a/packages/backend/src/server/api/endpoints/channels/show.ts +++ b/packages/backend/src/server/api/endpoints/channels/show.ts @@ -6,6 +6,7 @@ export const meta = { tags: ['channels'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'object', diff --git a/packages/backend/src/server/api/endpoints/channels/timeline.ts b/packages/backend/src/server/api/endpoints/channels/timeline.ts index deaa299013..18ba6b2e3e 100644 --- a/packages/backend/src/server/api/endpoints/channels/timeline.ts +++ b/packages/backend/src/server/api/endpoints/channels/timeline.ts @@ -8,6 +8,7 @@ export const meta = { tags: ['notes', 'channels'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/charts/active-users.ts b/packages/backend/src/server/api/endpoints/charts/active-users.ts index ea23794296..2166760209 100644 --- a/packages/backend/src/server/api/endpoints/charts/active-users.ts +++ b/packages/backend/src/server/api/endpoints/charts/active-users.ts @@ -4,6 +4,7 @@ import define from '../../define.js'; export const meta = { tags: ['charts', 'users'], + requireCredentialPrivateMode: true, res: getJsonSchema(activeUsersChart.schema), diff --git a/packages/backend/src/server/api/endpoints/charts/ap-request.ts b/packages/backend/src/server/api/endpoints/charts/ap-request.ts index 06dee250ee..a8f6e45643 100644 --- a/packages/backend/src/server/api/endpoints/charts/ap-request.ts +++ b/packages/backend/src/server/api/endpoints/charts/ap-request.ts @@ -4,6 +4,7 @@ import define from '../../define.js'; export const meta = { tags: ['charts'], + requireCredentialPrivateMode: true, res: getJsonSchema(apRequestChart.schema), diff --git a/packages/backend/src/server/api/endpoints/charts/drive.ts b/packages/backend/src/server/api/endpoints/charts/drive.ts index dd2c2d6838..14f82e39da 100644 --- a/packages/backend/src/server/api/endpoints/charts/drive.ts +++ b/packages/backend/src/server/api/endpoints/charts/drive.ts @@ -4,6 +4,7 @@ import define from '../../define.js'; export const meta = { tags: ['charts', 'drive'], + requireCredentialPrivateMode: true, res: getJsonSchema(driveChart.schema), diff --git a/packages/backend/src/server/api/endpoints/charts/federation.ts b/packages/backend/src/server/api/endpoints/charts/federation.ts index 8c35b3c46d..141e005ee9 100644 --- a/packages/backend/src/server/api/endpoints/charts/federation.ts +++ b/packages/backend/src/server/api/endpoints/charts/federation.ts @@ -4,6 +4,7 @@ import define from '../../define.js'; export const meta = { tags: ['charts'], + requireCredentialPrivateMode: true, res: getJsonSchema(federationChart.schema), diff --git a/packages/backend/src/server/api/endpoints/charts/hashtag.ts b/packages/backend/src/server/api/endpoints/charts/hashtag.ts index 77e24a62c3..d34153bc19 100644 --- a/packages/backend/src/server/api/endpoints/charts/hashtag.ts +++ b/packages/backend/src/server/api/endpoints/charts/hashtag.ts @@ -4,6 +4,7 @@ import define from '../../define.js'; export const meta = { tags: ['charts', 'hashtags'], + requireCredentialPrivateMode: true, res: getJsonSchema(hashtagChart.schema), diff --git a/packages/backend/src/server/api/endpoints/charts/instance.ts b/packages/backend/src/server/api/endpoints/charts/instance.ts index 817d51ad01..3d9619d240 100644 --- a/packages/backend/src/server/api/endpoints/charts/instance.ts +++ b/packages/backend/src/server/api/endpoints/charts/instance.ts @@ -4,6 +4,7 @@ import define from '../../define.js'; export const meta = { tags: ['charts'], + requireCredentialPrivateMode: true, res: getJsonSchema(instanceChart.schema), diff --git a/packages/backend/src/server/api/endpoints/charts/notes.ts b/packages/backend/src/server/api/endpoints/charts/notes.ts index 951adf5408..42befed276 100644 --- a/packages/backend/src/server/api/endpoints/charts/notes.ts +++ b/packages/backend/src/server/api/endpoints/charts/notes.ts @@ -4,6 +4,7 @@ import define from '../../define.js'; export const meta = { tags: ['charts', 'notes'], + requireCredentialPrivateMode: true, res: getJsonSchema(notesChart.schema), diff --git a/packages/backend/src/server/api/endpoints/charts/user/drive.ts b/packages/backend/src/server/api/endpoints/charts/user/drive.ts index f165b40224..cb73b4ac95 100644 --- a/packages/backend/src/server/api/endpoints/charts/user/drive.ts +++ b/packages/backend/src/server/api/endpoints/charts/user/drive.ts @@ -4,6 +4,7 @@ import define from '../../../define.js'; export const meta = { tags: ['charts', 'drive', 'users'], + requireCredentialPrivateMode: true, res: getJsonSchema(perUserDriveChart.schema), diff --git a/packages/backend/src/server/api/endpoints/charts/user/following.ts b/packages/backend/src/server/api/endpoints/charts/user/following.ts index f5d42e21c2..697a5f37a4 100644 --- a/packages/backend/src/server/api/endpoints/charts/user/following.ts +++ b/packages/backend/src/server/api/endpoints/charts/user/following.ts @@ -4,6 +4,7 @@ import { perUserFollowingChart } from '@/services/chart/index.js'; export const meta = { tags: ['charts', 'users', 'following'], + requireCredentialPrivateMode: true, res: getJsonSchema(perUserFollowingChart.schema), diff --git a/packages/backend/src/server/api/endpoints/charts/user/notes.ts b/packages/backend/src/server/api/endpoints/charts/user/notes.ts index aefe550d43..5b576754dc 100644 --- a/packages/backend/src/server/api/endpoints/charts/user/notes.ts +++ b/packages/backend/src/server/api/endpoints/charts/user/notes.ts @@ -4,6 +4,7 @@ import define from '../../../define.js'; export const meta = { tags: ['charts', 'users', 'notes'], + requireCredentialPrivateMode: true, res: getJsonSchema(perUserNotesChart.schema), diff --git a/packages/backend/src/server/api/endpoints/charts/user/reactions.ts b/packages/backend/src/server/api/endpoints/charts/user/reactions.ts index 6bc6b56bf0..61c4527b92 100644 --- a/packages/backend/src/server/api/endpoints/charts/user/reactions.ts +++ b/packages/backend/src/server/api/endpoints/charts/user/reactions.ts @@ -4,6 +4,7 @@ import define from '../../../define.js'; export const meta = { tags: ['charts', 'users', 'reactions'], + requireCredentialPrivateMode: true, res: getJsonSchema(perUserReactionsChart.schema), diff --git a/packages/backend/src/server/api/endpoints/charts/users.ts b/packages/backend/src/server/api/endpoints/charts/users.ts index 338e8fd338..0c799287c9 100644 --- a/packages/backend/src/server/api/endpoints/charts/users.ts +++ b/packages/backend/src/server/api/endpoints/charts/users.ts @@ -4,6 +4,7 @@ import define from '../../define.js'; export const meta = { tags: ['charts', 'users'], + requireCredentialPrivateMode: true, res: getJsonSchema(usersChart.schema), diff --git a/packages/backend/src/server/api/endpoints/clips/notes.ts b/packages/backend/src/server/api/endpoints/clips/notes.ts index 4ace747efe..eea6f0a0d9 100644 --- a/packages/backend/src/server/api/endpoints/clips/notes.ts +++ b/packages/backend/src/server/api/endpoints/clips/notes.ts @@ -10,6 +10,7 @@ export const meta = { tags: ['account', 'notes', 'clips'], requireCredential: false, + requireCredentialPrivateMode: true, kind: 'read:account', diff --git a/packages/backend/src/server/api/endpoints/clips/show.ts b/packages/backend/src/server/api/endpoints/clips/show.ts index c3d73c168d..aec4c1253d 100644 --- a/packages/backend/src/server/api/endpoints/clips/show.ts +++ b/packages/backend/src/server/api/endpoints/clips/show.ts @@ -6,6 +6,7 @@ export const meta = { tags: ['clips', 'account'], requireCredential: false, + requireCredentialPrivateMode: true, kind: 'read:account', diff --git a/packages/backend/src/server/api/endpoints/federation/followers.ts b/packages/backend/src/server/api/endpoints/federation/followers.ts index 7b1197d1e5..8a04df2d5d 100644 --- a/packages/backend/src/server/api/endpoints/federation/followers.ts +++ b/packages/backend/src/server/api/endpoints/federation/followers.ts @@ -6,6 +6,7 @@ export const meta = { tags: ['federation'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/federation/following.ts b/packages/backend/src/server/api/endpoints/federation/following.ts index ed1f142d88..fe41eefa44 100644 --- a/packages/backend/src/server/api/endpoints/federation/following.ts +++ b/packages/backend/src/server/api/endpoints/federation/following.ts @@ -6,6 +6,7 @@ export const meta = { tags: ['federation'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/federation/instances.ts b/packages/backend/src/server/api/endpoints/federation/instances.ts index 07e5c07c6a..41750f13e1 100644 --- a/packages/backend/src/server/api/endpoints/federation/instances.ts +++ b/packages/backend/src/server/api/endpoints/federation/instances.ts @@ -7,6 +7,7 @@ export const meta = { tags: ['federation'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/federation/show-instance.ts b/packages/backend/src/server/api/endpoints/federation/show-instance.ts index 2fbb8a15cb..92298f6720 100644 --- a/packages/backend/src/server/api/endpoints/federation/show-instance.ts +++ b/packages/backend/src/server/api/endpoints/federation/show-instance.ts @@ -6,6 +6,7 @@ export const meta = { tags: ['federation'], requireCredential: false, + requireCredentialPrivateMode: true, res: { oneOf: [{ diff --git a/packages/backend/src/server/api/endpoints/federation/users.ts b/packages/backend/src/server/api/endpoints/federation/users.ts index 65ad9f88d3..a9b3f3a8cc 100644 --- a/packages/backend/src/server/api/endpoints/federation/users.ts +++ b/packages/backend/src/server/api/endpoints/federation/users.ts @@ -6,6 +6,7 @@ export const meta = { tags: ['federation'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/gallery/featured.ts b/packages/backend/src/server/api/endpoints/gallery/featured.ts index e6acd36911..52232c5ccb 100644 --- a/packages/backend/src/server/api/endpoints/gallery/featured.ts +++ b/packages/backend/src/server/api/endpoints/gallery/featured.ts @@ -5,6 +5,7 @@ export const meta = { tags: ['gallery'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/gallery/popular.ts b/packages/backend/src/server/api/endpoints/gallery/popular.ts index c4c8982fcc..5286dcd8b6 100644 --- a/packages/backend/src/server/api/endpoints/gallery/popular.ts +++ b/packages/backend/src/server/api/endpoints/gallery/popular.ts @@ -5,6 +5,7 @@ export const meta = { tags: ['gallery'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/gallery/posts.ts b/packages/backend/src/server/api/endpoints/gallery/posts.ts index 428ba9cc71..f556ec513f 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts.ts @@ -4,6 +4,7 @@ import { GalleryPosts } from '@/models/index.js'; export const meta = { tags: ['gallery'], + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/show.ts b/packages/backend/src/server/api/endpoints/gallery/posts/show.ts index 4f6dafd7cb..48468f410f 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/show.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/show.ts @@ -6,6 +6,7 @@ export const meta = { tags: ['gallery'], requireCredential: false, + requireCredentialPrivateMode: true, errors: { noSuchPost: { diff --git a/packages/backend/src/server/api/endpoints/get-online-users-count.ts b/packages/backend/src/server/api/endpoints/get-online-users-count.ts index 56c5502978..a8febe05b9 100644 --- a/packages/backend/src/server/api/endpoints/get-online-users-count.ts +++ b/packages/backend/src/server/api/endpoints/get-online-users-count.ts @@ -7,6 +7,7 @@ export const meta = { tags: ['meta'], requireCredential: false, + requireCredentialPrivateMode: true, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/hashtags/list.ts b/packages/backend/src/server/api/endpoints/hashtags/list.ts index 50e36386cf..4b18cb76ac 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/list.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/list.ts @@ -5,6 +5,7 @@ export const meta = { tags: ['hashtags'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/hashtags/search.ts b/packages/backend/src/server/api/endpoints/hashtags/search.ts index c289844775..ed1abf1a10 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/search.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/search.ts @@ -5,6 +5,7 @@ export const meta = { tags: ['hashtags'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/hashtags/show.ts b/packages/backend/src/server/api/endpoints/hashtags/show.ts index 5b78f6ac7f..409233c241 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/show.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/show.ts @@ -7,6 +7,7 @@ export const meta = { tags: ['hashtags'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'object', diff --git a/packages/backend/src/server/api/endpoints/hashtags/trend.ts b/packages/backend/src/server/api/endpoints/hashtags/trend.ts index 9cdbc8941c..8795927e65 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/trend.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/trend.ts @@ -24,6 +24,7 @@ export const meta = { tags: ['hashtags'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/hashtags/users.ts b/packages/backend/src/server/api/endpoints/hashtags/users.ts index a5df21a7e3..1d18a9ce72 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/users.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/users.ts @@ -4,6 +4,7 @@ import { normalizeForSearch } from '@/misc/normalize-for-search.js'; export const meta = { requireCredential: false, + requireCredentialPrivateMode: true, tags: ['hashtags', 'users'], diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index ca6b471d59..d93d399e48 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -336,7 +336,7 @@ export default define(meta, paramDef, async (ps, me) => { expiresAt: MoreThan(new Date()), }, }); - // TODO: add secure mode, etc + const response: any = { maintainerName: instance.maintainerName, maintainerEmail: instance.maintainerEmail, @@ -350,6 +350,10 @@ export default define(meta, paramDef, async (ps, me) => { tosUrl: instance.ToSUrl, repositoryUrl: instance.repositoryUrl, feedbackUrl: instance.feedbackUrl, + + secureMode: instance.secureMode, + privateMode: instance.privateMode, + disableRegistration: instance.disableRegistration, disableLocalTimeline: instance.disableLocalTimeline, disableGlobalTimeline: instance.disableGlobalTimeline, @@ -369,10 +373,10 @@ export default define(meta, paramDef, async (ps, me) => { backgroundImageUrl: instance.backgroundImageUrl, logoImageUrl: instance.logoImageUrl, maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, // 後方互換性のため - emojis: await Emojis.packMany(emojis), + emojis: instance.privateMode && !me ? [] : await Emojis.packMany(emojis), defaultLightTheme: instance.defaultLightTheme, defaultDarkTheme: instance.defaultDarkTheme, - ads: ads.map(ad => ({ + ads: instance.privateMode && !me ? [] : ads.map(ad => ({ id: ad.id, url: ad.url, place: ad.place, @@ -390,8 +394,8 @@ export default define(meta, paramDef, async (ps, me) => { translatorAvailable: instance.deeplAuthKey != null, ...(ps.detail ? { - pinnedPages: instance.pinnedPages, - pinnedClipId: instance.pinnedClipId, + pinnedPages: instance.privateMode && !me ? [] : instance.pinnedPages, + pinnedClipId: instance.privateMode && !me ? [] : instance.pinnedClipId, cacheRemoteFiles: instance.cacheRemoteFiles, requireSetup: (await Users.countBy({ host: IsNull(), @@ -400,9 +404,11 @@ export default define(meta, paramDef, async (ps, me) => { }; if (ps.detail) { - const proxyAccount = instance.proxyAccountId ? await Users.pack(instance.proxyAccountId).catch(() => null) : null; + if (!instance.privateMode || me) { + const proxyAccount = instance.proxyAccountId ? await Users.pack(instance.proxyAccountId).catch(() => null) : null; + response.proxyAccountName = proxyAccount ? proxyAccount.username : null; + } - response.proxyAccountName = proxyAccount ? proxyAccount.username : null; response.features = { registration: !instance.disableRegistration, localTimeLine: !instance.disableLocalTimeline, diff --git a/packages/backend/src/server/api/endpoints/notes.ts b/packages/backend/src/server/api/endpoints/notes.ts index 015b0338e3..fc2bc3741f 100644 --- a/packages/backend/src/server/api/endpoints/notes.ts +++ b/packages/backend/src/server/api/endpoints/notes.ts @@ -5,6 +5,7 @@ import { makePaginationQuery } from '../common/make-pagination-query.js'; export const meta = { tags: ['notes'], + requireCredentialPrivateMode: true, res: { type: 'array', optional: false, nullable: false, diff --git a/packages/backend/src/server/api/endpoints/notes/children.ts b/packages/backend/src/server/api/endpoints/notes/children.ts index efc109105c..d27bbaefac 100644 --- a/packages/backend/src/server/api/endpoints/notes/children.ts +++ b/packages/backend/src/server/api/endpoints/notes/children.ts @@ -10,6 +10,7 @@ export const meta = { tags: ['notes'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', @@ -20,7 +21,7 @@ export const meta = { ref: 'Note', }, }, -} as const; +}; export const paramDef = { type: 'object', diff --git a/packages/backend/src/server/api/endpoints/notes/clips.ts b/packages/backend/src/server/api/endpoints/notes/clips.ts index e79f8563e8..5a4420a685 100644 --- a/packages/backend/src/server/api/endpoints/notes/clips.ts +++ b/packages/backend/src/server/api/endpoints/notes/clips.ts @@ -8,6 +8,7 @@ export const meta = { tags: ['clips', 'notes'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/notes/conversation.ts b/packages/backend/src/server/api/endpoints/notes/conversation.ts index b731d18248..28613962aa 100644 --- a/packages/backend/src/server/api/endpoints/notes/conversation.ts +++ b/packages/backend/src/server/api/endpoints/notes/conversation.ts @@ -8,6 +8,7 @@ export const meta = { tags: ['notes'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/notes/featured.ts b/packages/backend/src/server/api/endpoints/notes/featured.ts index dd9cc581aa..0e4a454d76 100644 --- a/packages/backend/src/server/api/endpoints/notes/featured.ts +++ b/packages/backend/src/server/api/endpoints/notes/featured.ts @@ -7,6 +7,7 @@ export const meta = { tags: ['notes'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts index 925318f544..6a468f1981 100644 --- a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts @@ -12,6 +12,7 @@ import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['notes'], + requireCredentialPrivateMode: true, res: { type: 'array', optional: false, nullable: false, 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 aac2a3749c..3a5c458a05 100644 --- a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts @@ -14,6 +14,7 @@ import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['notes'], + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/notes/reactions.ts b/packages/backend/src/server/api/endpoints/notes/reactions.ts index 15a62d394d..be2846d251 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions.ts @@ -8,6 +8,7 @@ export const meta = { tags: ['notes', 'reactions'], requireCredential: false, + requireCredentialPrivateMode: true, allowGet: true, cacheSec: 60, diff --git a/packages/backend/src/server/api/endpoints/notes/renotes.ts b/packages/backend/src/server/api/endpoints/notes/renotes.ts index 28be360763..4d0cd8fc60 100644 --- a/packages/backend/src/server/api/endpoints/notes/renotes.ts +++ b/packages/backend/src/server/api/endpoints/notes/renotes.ts @@ -11,6 +11,7 @@ export const meta = { tags: ['notes'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/notes/replies.ts b/packages/backend/src/server/api/endpoints/notes/replies.ts index ab0018f58e..b05ef59148 100644 --- a/packages/backend/src/server/api/endpoints/notes/replies.ts +++ b/packages/backend/src/server/api/endpoints/notes/replies.ts @@ -9,6 +9,7 @@ export const meta = { tags: ['notes'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts index 777de7221c..2319132231 100644 --- a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts +++ b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts @@ -10,6 +10,7 @@ import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['notes', 'hashtags'], + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/notes/search.ts b/packages/backend/src/server/api/endpoints/notes/search.ts index 4e2cdae801..cf3de47a3f 100644 --- a/packages/backend/src/server/api/endpoints/notes/search.ts +++ b/packages/backend/src/server/api/endpoints/notes/search.ts @@ -12,6 +12,7 @@ export const meta = { tags: ['notes'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/notes/show.ts b/packages/backend/src/server/api/endpoints/notes/show.ts index 5cd74bd2ca..470791b1b9 100644 --- a/packages/backend/src/server/api/endpoints/notes/show.ts +++ b/packages/backend/src/server/api/endpoints/notes/show.ts @@ -7,6 +7,7 @@ export const meta = { tags: ['notes'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'object', diff --git a/packages/backend/src/server/api/endpoints/notes/translate.ts b/packages/backend/src/server/api/endpoints/notes/translate.ts index 5e40e7106f..ba6e262d69 100644 --- a/packages/backend/src/server/api/endpoints/notes/translate.ts +++ b/packages/backend/src/server/api/endpoints/notes/translate.ts @@ -12,6 +12,7 @@ export const meta = { tags: ['notes'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'object', diff --git a/packages/backend/src/server/api/endpoints/pages/featured.ts b/packages/backend/src/server/api/endpoints/pages/featured.ts index 5a149a626e..75580778b6 100644 --- a/packages/backend/src/server/api/endpoints/pages/featured.ts +++ b/packages/backend/src/server/api/endpoints/pages/featured.ts @@ -5,6 +5,7 @@ export const meta = { tags: ['pages'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/pages/show.ts b/packages/backend/src/server/api/endpoints/pages/show.ts index 5d37e86b91..54ae43deb7 100644 --- a/packages/backend/src/server/api/endpoints/pages/show.ts +++ b/packages/backend/src/server/api/endpoints/pages/show.ts @@ -8,6 +8,7 @@ export const meta = { tags: ['pages'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'object', diff --git a/packages/backend/src/server/api/endpoints/pinned-users.ts b/packages/backend/src/server/api/endpoints/pinned-users.ts index 41595b47d9..d2ded60a13 100644 --- a/packages/backend/src/server/api/endpoints/pinned-users.ts +++ b/packages/backend/src/server/api/endpoints/pinned-users.ts @@ -9,6 +9,7 @@ export const meta = { tags: ['users'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/server-info.ts b/packages/backend/src/server/api/endpoints/server-info.ts index 99f3730e97..fdfbc8a6fd 100644 --- a/packages/backend/src/server/api/endpoints/server-info.ts +++ b/packages/backend/src/server/api/endpoints/server-info.ts @@ -4,6 +4,7 @@ import define from '../define.js'; export const meta = { requireCredential: false, + requireCredentialPrivateMode: true, tags: ['meta'], } as const; diff --git a/packages/backend/src/server/api/endpoints/stats.ts b/packages/backend/src/server/api/endpoints/stats.ts index cc94f8bf26..0f2fb1f412 100644 --- a/packages/backend/src/server/api/endpoints/stats.ts +++ b/packages/backend/src/server/api/endpoints/stats.ts @@ -5,6 +5,7 @@ import { IsNull } from 'typeorm'; export const meta = { requireCredential: false, + requireCredentialPrivateMode: true, tags: ['meta'], diff --git a/packages/backend/src/server/api/endpoints/users.ts b/packages/backend/src/server/api/endpoints/users.ts index 3a8211374b..d2f2ddcbf9 100644 --- a/packages/backend/src/server/api/endpoints/users.ts +++ b/packages/backend/src/server/api/endpoints/users.ts @@ -7,6 +7,7 @@ export const meta = { tags: ['users'], requireCredential: false, + requireCredentialPrivateMode: true, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/users/clips.ts b/packages/backend/src/server/api/endpoints/users/clips.ts index 09fdf27c23..becfad52de 100644 --- a/packages/backend/src/server/api/endpoints/users/clips.ts +++ b/packages/backend/src/server/api/endpoints/users/clips.ts @@ -4,6 +4,7 @@ import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['users', 'clips'], + requireCredentialPrivateMode: true, description: 'Show all clips this user owns.', diff --git a/packages/backend/src/server/api/endpoints/users/followers.ts b/packages/backend/src/server/api/endpoints/users/followers.ts index 7f9f980764..4971d21b08 100644 --- a/packages/backend/src/server/api/endpoints/users/followers.ts +++ b/packages/backend/src/server/api/endpoints/users/followers.ts @@ -9,6 +9,7 @@ export const meta = { tags: ['users'], requireCredential: false, + requireCredentialPrivateMode: true, description: 'Show everyone that follows this user.', diff --git a/packages/backend/src/server/api/endpoints/users/following.ts b/packages/backend/src/server/api/endpoints/users/following.ts index 0aaa810f76..043841aa4d 100644 --- a/packages/backend/src/server/api/endpoints/users/following.ts +++ b/packages/backend/src/server/api/endpoints/users/following.ts @@ -9,6 +9,7 @@ export const meta = { tags: ['users'], requireCredential: false, + requireCredentialPrivateMode: true, description: 'Show everyone that this user is following.', diff --git a/packages/backend/src/server/api/endpoints/users/gallery/posts.ts b/packages/backend/src/server/api/endpoints/users/gallery/posts.ts index 35bf2df598..95ca778250 100644 --- a/packages/backend/src/server/api/endpoints/users/gallery/posts.ts +++ b/packages/backend/src/server/api/endpoints/users/gallery/posts.ts @@ -4,6 +4,7 @@ import { makePaginationQuery } from '../../../common/make-pagination-query.js'; export const meta = { tags: ['users', 'gallery'], + requireCredentialPrivateMode: true, description: 'Show all gallery posts by the given user.', diff --git a/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts b/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts index 56965d3066..8cf3ea0402 100644 --- a/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts +++ b/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts @@ -9,6 +9,7 @@ export const meta = { tags: ['users'], requireCredential: false, + requireCredentialPrivateMode: true, description: 'Get a list of other users that the specified user frequently replies to.', diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts index 9fa56fe83a..1e205eec3c 100644 --- a/packages/backend/src/server/api/endpoints/users/notes.ts +++ b/packages/backend/src/server/api/endpoints/users/notes.ts @@ -11,6 +11,7 @@ import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['users', 'notes'], + requireCredentialPrivateMode: true, description: 'Show all notes that this user created.', res: { diff --git a/packages/backend/src/server/api/endpoints/users/pages.ts b/packages/backend/src/server/api/endpoints/users/pages.ts index b1d28af845..e1d876e6b2 100644 --- a/packages/backend/src/server/api/endpoints/users/pages.ts +++ b/packages/backend/src/server/api/endpoints/users/pages.ts @@ -4,6 +4,7 @@ import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['users', 'pages'], + requireCredentialPrivateMode: true, description: 'Show all pages this user created.', diff --git a/packages/backend/src/server/api/endpoints/users/reactions.ts b/packages/backend/src/server/api/endpoints/users/reactions.ts index 9668bd21b8..79cf58a414 100644 --- a/packages/backend/src/server/api/endpoints/users/reactions.ts +++ b/packages/backend/src/server/api/endpoints/users/reactions.ts @@ -8,6 +8,7 @@ export const meta = { tags: ['users', 'reactions'], requireCredential: false, + requireCredentialPrivateMode: true, description: 'Show all reactions this user made.', diff --git a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts index 6e5bc46bb5..fa1cb8761e 100644 --- a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts +++ b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts @@ -8,6 +8,7 @@ export const meta = { tags: ['users'], requireCredential: false, + requireCredentialPrivateMode: true, description: 'Search for a user by username and/or host.', diff --git a/packages/backend/src/server/api/endpoints/users/search.ts b/packages/backend/src/server/api/endpoints/users/search.ts index 01729de667..70aaa45269 100644 --- a/packages/backend/src/server/api/endpoints/users/search.ts +++ b/packages/backend/src/server/api/endpoints/users/search.ts @@ -7,6 +7,7 @@ export const meta = { tags: ['users'], requireCredential: false, + requireCredentialPrivateMode: true, description: 'Search for users.', diff --git a/packages/backend/src/server/api/endpoints/users/show.ts b/packages/backend/src/server/api/endpoints/users/show.ts index 846d83b49f..892e37bdfa 100644 --- a/packages/backend/src/server/api/endpoints/users/show.ts +++ b/packages/backend/src/server/api/endpoints/users/show.ts @@ -10,6 +10,7 @@ export const meta = { tags: ['users'], requireCredential: false, + requireCredentialPrivateMode: true, description: 'Show the properties of a user.', diff --git a/packages/backend/src/server/api/endpoints/users/stats.ts b/packages/backend/src/server/api/endpoints/users/stats.ts index 47f322ee9b..a68b6ea409 100644 --- a/packages/backend/src/server/api/endpoints/users/stats.ts +++ b/packages/backend/src/server/api/endpoints/users/stats.ts @@ -7,6 +7,7 @@ export const meta = { tags: ['users'], requireCredential: false, + requireCredentialPrivateMode: true, description: 'Show statistics about a user.', From 7caec25f0f0da41e9a2681bfc009d04fe9d15cbd Mon Sep 17 00:00:00 2001 From: nullobsi Date: Tue, 20 Jul 2021 13:08:21 -0700 Subject: [PATCH 4/5] Add secure mode settings to Security tab --- locales/ja-JP.yml | 7 ++++ .../src/server/api/endpoints/admin/meta.ts | 19 +++++++++ .../server/api/endpoints/admin/update-meta.ts | 17 ++++++++ packages/client/src/pages/admin/security.vue | 39 +++++++++++++++++++ 4 files changed, 82 insertions(+) diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index b10cce9231..42d5561aa7 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -780,6 +780,13 @@ middle: "中" low: "低" emailNotConfiguredWarning: "メールアドレスの設定がされていません。" ratio: "比率" +secureMode: "セキュアモード (Authorized Fetch)" +instanceSecurity: "インスタンスのセキュリティー" +secureModeInfo: "他のインスタンスからリクエストするときに、証明を付けなければ返送しません。他のインスタンスの設定ファイルでsignToActivityPubGetはtrueにしてください。" +privateMode: "非公開モード" +privateModeInfo: "有効にして、許可されているインスタンスのみがリクエストできます。すべてのノートが公開に非表示にします。" +allowedInstances: "許可されたインスタンス" +allowedInstancesDescription: "許可したいインスタンスのホストを改行で区切って設定します。非公開モードだけで有効です。" previewNoteText: "本文をプレビュー" customCss: "カスタムCSS" customCssWarn: "この設定は必ず知識のある方が行ってください。不適切な設定を行うとクライアントが正常に使用できなくなる恐れがあります。" diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 8746119687..8a11baf90f 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -187,6 +187,22 @@ export const meta = { optional: false, nullable: false, }, }, + allowedHosts: { + type: 'array', + optional: true, nullable: false, + items: { + type: 'string', + optional: false, nullable: false, + }, + }, + privateMode: { + type: 'boolean', + optional: false, nullable: false, + }, + secureMode: { + type: 'boolean', + optional: false, nullable: false, + }, hcaptchaSecretKey: { type: 'string', optional: true, nullable: true, @@ -388,6 +404,9 @@ export default define(meta, paramDef, async (ps, me) => { pinnedUsers: instance.pinnedUsers, hiddenTags: instance.hiddenTags, blockedHosts: instance.blockedHosts, + allowedHosts: instance.allowedHosts, + privateMode: instance.privateMode, + secureMode: instance.secureMode, hcaptchaSecretKey: instance.hcaptchaSecretKey, recaptchaSecretKey: instance.recaptchaSecretKey, sensitiveMediaDetection: instance.sensitiveMediaDetection, 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 f14aa41050..1fe68f261e 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -27,6 +27,11 @@ export const paramDef = { blockedHosts: { type: 'array', nullable: true, items: { type: 'string', } }, + allowedHosts: { type: 'array', nullable: true, items: { + type: 'string', + } }, + secureMode: { type: 'boolean', nullable: true }, + privateMode: { type: 'boolean', nullable: true }, themeColor: { type: 'string', nullable: true, pattern: '^#[0-9a-fA-F]{6}$' }, mascotImageUrl: { type: 'string', nullable: true }, bannerUrl: { type: 'string', nullable: true }, @@ -142,6 +147,18 @@ export default define(meta, paramDef, async (ps, me) => { set.themeColor = ps.themeColor; } + if (Array.isArray(ps.allowedHosts)) { + set.allowedHosts = ps.allowedHosts.filter(Boolean); + } + + if (typeof ps.privateMode === 'boolean') { + set.privateMode = ps.privateMode; + } + + if (typeof ps.secureMode === 'boolean') { + set.secureMode = ps.secureMode; + } + if (ps.mascotImageUrl !== undefined) { set.mascotImageUrl = ps.mascotImageUrl; } diff --git a/packages/client/src/pages/admin/security.vue b/packages/client/src/pages/admin/security.vue index c36cedb312..a7c9850311 100644 --- a/packages/client/src/pages/admin/security.vue +++ b/packages/client/src/pages/admin/security.vue @@ -94,6 +94,26 @@ {{ i18n.ts.save }} + + + + +
+ + + + + + + + + + + + + {{ i18n.ts.save }} +
+
@@ -112,6 +132,7 @@ import FormSuspense from '@/components/form/suspense.vue'; import FormRange from '@/components/form/range.vue'; import FormInput from '@/components/form/input.vue'; import FormButton from '@/components/MkButton.vue'; +import FormTextarea from '@/components/form/textarea.vue'; import * as os from '@/os'; import { fetchInstance } from '@/instance'; import { i18n } from '@/i18n'; @@ -127,6 +148,10 @@ let enableSensitiveMediaDetectionForVideos: boolean = $ref(false); let enableIpLogging: boolean = $ref(false); let enableActiveEmailValidation: boolean = $ref(false); +let secureMode: boolean = $ref(false); +let privateMode: boolean = $ref(false); +let allowedHosts: string = $ref(''); + async function init() { const meta = await os.api('admin/meta'); summalyProxy = meta.summalyProxy; @@ -143,6 +168,10 @@ async function init() { enableSensitiveMediaDetectionForVideos = meta.enableSensitiveMediaDetectionForVideos; enableIpLogging = meta.enableIpLogging; enableActiveEmailValidation = meta.enableActiveEmailValidation; + + secureMode = meta.secureMode; + privateMode = meta.privateMode; + allowedHosts = meta.allowedHosts.join('\n'); } function save() { @@ -165,6 +194,16 @@ function save() { }); } +function saveInstance() { + os.apiWithDialog('admin/update-meta', { + secureMode, + privateMode, + allowedHosts: allowedHosts.split('\n'), + }).then(() => { + fetchInstance(); + }); +} + const headerActions = $computed(() => []); const headerTabs = $computed(() => []); From 1c7dc4a1e8173e0a785adfe7a5ad5ff494de0d74 Mon Sep 17 00:00:00 2001 From: nullobsi Date: Wed, 25 Aug 2021 20:48:57 -0700 Subject: [PATCH 5/5] Hide private data in pug when private mode is enabled --- packages/backend/src/server/web/index.ts | 15 ++++++ .../backend/src/server/web/views/base.pug | 6 ++- .../backend/src/server/web/views/channel.pug | 16 +++--- .../backend/src/server/web/views/clip.pug | 33 ++++++------ .../src/server/web/views/gallery-post.pug | 35 +++++++------ .../backend/src/server/web/views/note.pug | 51 ++++++++++--------- .../backend/src/server/web/views/page.pug | 33 ++++++------ .../backend/src/server/web/views/user.pug | 47 +++++++++-------- 8 files changed, 135 insertions(+), 101 deletions(-) diff --git a/packages/backend/src/server/web/index.ts b/packages/backend/src/server/web/index.ts index be95becb68..0968f3271c 100644 --- a/packages/backend/src/server/web/index.ts +++ b/packages/backend/src/server/web/index.ts @@ -218,6 +218,10 @@ router.get('/api.json', async ctx => { }); const getFeed = async (acct: string) => { + const meta = await fetchMeta(); + if (meta.privateMode) { + return; + } const { username, host } = Acct.parse(acct); const user = await Users.findOneBy({ usernameLower: username.toLowerCase(), @@ -290,6 +294,7 @@ router.get(['/@:user', '/@:user/:sub'], async (ctx, next) => { instanceName: meta.name || 'Misskey', icon: meta.iconUrl, themeColor: meta.themeColor, + privateMode: meta.privateMode, }); ctx.set('Cache-Control', 'public, max-age=15'); } else { @@ -333,6 +338,7 @@ router.get('/notes/:note', async (ctx, next) => { summary: getNoteSummary(_note), instanceName: meta.name || 'Misskey', icon: meta.iconUrl, + privateMode: meta.privateMode, themeColor: meta.themeColor, }); @@ -370,6 +376,7 @@ router.get('/@:user/pages/:page', async (ctx, next) => { instanceName: meta.name || 'Misskey', icon: meta.iconUrl, themeColor: meta.themeColor, + privateMode: meta.privateMode, }); if (['public'].includes(page.visibility)) { @@ -400,6 +407,7 @@ router.get('/clips/:clip', async (ctx, next) => { profile, avatarUrl: await Users.getAvatarUrl(await Users.findOneByOrFail({ id: clip.userId })), instanceName: meta.name || 'Misskey', + privateMode: meta.privateMode, icon: meta.iconUrl, themeColor: meta.themeColor, }); @@ -427,6 +435,7 @@ router.get('/gallery/:post', async (ctx, next) => { instanceName: meta.name || 'Misskey', icon: meta.iconUrl, themeColor: meta.themeColor, + privateMode: meta.privateMode, }); ctx.set('Cache-Control', 'public, max-age=15'); @@ -451,6 +460,7 @@ router.get('/channels/:channel', async (ctx, next) => { instanceName: meta.name || 'Misskey', icon: meta.iconUrl, themeColor: meta.themeColor, + privateMode: meta.privateMode, }); ctx.set('Cache-Control', 'public, max-age=15'); @@ -464,6 +474,10 @@ router.get('/channels/:channel', async (ctx, next) => { router.get('/_info_card_', async ctx => { const meta = await fetchMeta(true); + if (meta.privateMode) { + ctx.status = 403; + return; + } ctx.remove('X-Frame-Options'); @@ -511,6 +525,7 @@ router.get('(.*)', async ctx => { desc: meta.description, icon: meta.iconUrl, themeColor: meta.themeColor, + privateMode: meta.privateMode, }); ctx.set('Cache-Control', 'public, max-age=15'); }); diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug index 5bb156f0f4..effa0743b0 100644 --- a/packages/backend/src/server/web/views/base.pug +++ b/packages/backend/src/server/web/views/base.pug @@ -51,10 +51,12 @@ html meta(name='description' content= desc || '✨🌎✨ A interplanetary communication platform ✨🚀✨') block meta + if privateMode + meta(name='robots' content='noindex') block og - meta(property='og:title' content= title || 'Misskey') - meta(property='og:description' content= desc || '✨🌎✨ A interplanetary communication platform ✨🚀✨') + meta(property='og:title' content= title || 'Misskey') + meta(property='og:description' content= desc || '✨🌎✨ A interplanetary communication platform ✨🚀✨') meta(property='og:image' content= img) style diff --git a/packages/backend/src/server/web/views/channel.pug b/packages/backend/src/server/web/views/channel.pug index 486f0ecc47..c4594b7666 100644 --- a/packages/backend/src/server/web/views/channel.pug +++ b/packages/backend/src/server/web/views/channel.pug @@ -1,18 +1,20 @@ extends ./base block vars - - const title = channel.name; + - const title = privateMode ? instanceName : channel.name; - const url = `${config.url}/channels/${channel.id}`; block title = `${title} | ${instanceName}` block desc - meta(name='description' content= channel.description) + unless privateMode + meta(name='description' content=channel.description) block og - meta(property='og:type' content='article') - meta(property='og:title' content= title) - meta(property='og:description' content= channel.description) - meta(property='og:url' content= url) - meta(property='og:image' content= channel.bannerUrl) + unless privateMode + meta(property='og:type' content='article') + meta(property='og:title' content= title) + meta(property='og:description' content= channel.description) + meta(property='og:url' content= url) + meta(property='og:image' content= channel.bannerUrl) diff --git a/packages/backend/src/server/web/views/clip.pug b/packages/backend/src/server/web/views/clip.pug index 4c692bf59b..2432470c10 100644 --- a/packages/backend/src/server/web/views/clip.pug +++ b/packages/backend/src/server/web/views/clip.pug @@ -2,30 +2,33 @@ extends ./base block vars - const user = clip.user; - - const title = clip.name; + - const title = privateMode ? instanceName : clip.name; - const url = `${config.url}/clips/${clip.id}`; block title = `${title} | ${instanceName}` block desc - meta(name='description' content= clip.description) + unless privateMode + meta(name='description' content= clip.description) block og - meta(property='og:type' content='article') - meta(property='og:title' content= title) - meta(property='og:description' content= clip.description) - meta(property='og:url' content= url) - meta(property='og:image' content= avatarUrl) + unless privateMode + meta(property='og:type' content='article') + meta(property='og:title' content= title) + meta(property='og:description' content= clip.description) + meta(property='og:url' content= url) + meta(property='og:image' content= avatarUrl) block meta - if profile.noCrawle - meta(name='robots' content='noindex') + unless privateMode + if profile.noCrawle + meta(name='robots' content='noindex') - meta(name='misskey:user-username' content=user.username) - meta(name='misskey:user-id' content=user.id) - meta(name='misskey:clip-id' content=clip.id) + meta(name='misskey:user-username' content=user.username) + meta(name='misskey:user-id' content=user.id) + meta(name='misskey:clip-id' content=clip.id) - // todo - if user.twitter - meta(name='twitter:creator' content=`@${user.twitter.screenName}`) + // todo + if user.twitter + meta(name='twitter:creator' content=`@${user.twitter.screenName}`) diff --git a/packages/backend/src/server/web/views/gallery-post.pug b/packages/backend/src/server/web/views/gallery-post.pug index ca0663a481..1b1c2fbfbd 100644 --- a/packages/backend/src/server/web/views/gallery-post.pug +++ b/packages/backend/src/server/web/views/gallery-post.pug @@ -2,32 +2,35 @@ extends ./base block vars - const user = post.user; - - const title = post.title; + - const title = privateMode ? instanceName : post.title; - const url = `${config.url}/gallery/${post.id}`; block title = `${title} | ${instanceName}` block desc - meta(name='description' content= post.description) + unless privateMode + meta(name='description' content= post.description) block og - meta(property='og:type' content='article') - meta(property='og:title' content= title) - meta(property='og:description' content= post.description) - meta(property='og:url' content= url) - meta(property='og:image' content= post.files[0].thumbnailUrl) + unless privateMode + meta(property='og:type' content='article') + meta(property='og:title' content= title) + meta(property='og:description' content= post.description) + meta(property='og:url' content= url) + meta(property='og:image' content= post.files[0].thumbnailUrl) block meta - if user.host || profile.noCrawle - meta(name='robots' content='noindex') + unless privateMode + if user.host || profile.noCrawle + meta(name='robots' content='noindex') - meta(name='misskey:user-username' content=user.username) - meta(name='misskey:user-id' content=user.id) + meta(name='misskey:user-username' content=user.username) + meta(name='misskey:user-id' content=user.id) - // todo - if user.twitter - meta(name='twitter:creator' content=`@${user.twitter.screenName}`) + // todo + if user.twitter + meta(name='twitter:creator' content=`@${user.twitter.screenName}`) - if !user.host - link(rel='alternate' href=url type='application/activity+json') + if !user.host + link(rel='alternate' href=url type='application/activity+json') diff --git a/packages/backend/src/server/web/views/note.pug b/packages/backend/src/server/web/views/note.pug index 65696ea138..6b55f6ba03 100644 --- a/packages/backend/src/server/web/views/note.pug +++ b/packages/backend/src/server/web/views/note.pug @@ -2,7 +2,7 @@ extends ./base block vars - const user = note.user; - - const title = user.name ? `${user.name} (@${user.username})` : `@${user.username}`; + - const title = privateMode ? instanceName : (user.name ? `${user.name} (@${user.username})` : `@${user.username}`); - const url = `${config.url}/notes/${note.id}`; - const isRenote = note.renote && note.text == null && note.fileIds.length == 0 && note.poll == null; @@ -10,33 +10,36 @@ block title = `${title} | ${instanceName}` block desc - meta(name='description' content= summary) + unless privateMode + meta(name='description' content= summary) block og - meta(property='og:type' content='article') - meta(property='og:title' content= title) - meta(property='og:description' content= summary) - meta(property='og:url' content= url) - meta(property='og:image' content= avatarUrl) + unless privateMode + meta(property='og:type' content='article') + meta(property='og:title' content= title) + meta(property='og:description' content= summary) + meta(property='og:url' content= url) + meta(property='og:image' content= avatarUrl) block meta - if user.host || isRenote || profile.noCrawle - meta(name='robots' content='noindex') + unless privateMode + if user.host || isRenote || profile.noCrawle + meta(name='robots' content='noindex') - meta(name='misskey:user-username' content=user.username) - meta(name='misskey:user-id' content=user.id) - meta(name='misskey:note-id' content=note.id) - - // todo - if user.twitter - meta(name='twitter:creator' content=`@${user.twitter.screenName}`) + meta(name='misskey:user-username' content=user.username) + meta(name='misskey:user-id' content=user.id) + meta(name='misskey:note-id' content=note.id) - if note.prev - link(rel='prev' href=`${config.url}/notes/${note.prev}`) - if note.next - link(rel='next' href=`${config.url}/notes/${note.next}`) + // todo + if user.twitter + meta(name='twitter:creator' content=`@${user.twitter.screenName}`) - if !user.host - link(rel='alternate' href=url type='application/activity+json') - if note.uri - link(rel='alternate' href=note.uri type='application/activity+json') + if note.prev + link(rel='prev' href=`${config.url}/notes/${note.prev}`) + if note.next + link(rel='next' href=`${config.url}/notes/${note.next}`) + + if !user.host + link(rel='alternate' href=url type='application/activity+json') + if note.uri + link(rel='alternate' href=note.uri type='application/activity+json') diff --git a/packages/backend/src/server/web/views/page.pug b/packages/backend/src/server/web/views/page.pug index 4219e76a52..1095282131 100644 --- a/packages/backend/src/server/web/views/page.pug +++ b/packages/backend/src/server/web/views/page.pug @@ -2,30 +2,33 @@ extends ./base block vars - const user = page.user; - - const title = page.title; + - const title = privateMode ? instanceName : page.title; - const url = `${config.url}/@${user.username}/${page.name}`; block title = `${title} | ${instanceName}` block desc - meta(name='description' content= page.summary) + unless privateMode + meta(name='description' content= page.summary) block og - meta(property='og:type' content='article') - meta(property='og:title' content= title) - meta(property='og:description' content= page.summary) - meta(property='og:url' content= url) - meta(property='og:image' content= page.eyeCatchingImage ? page.eyeCatchingImage.thumbnailUrl : avatarUrl) + unless privateMode + meta(property='og:type' content='article') + meta(property='og:title' content= title) + meta(property='og:description' content= page.summary) + meta(property='og:url' content= url) + meta(property='og:image' content= page.eyeCatchingImage ? page.eyeCatchingImage.thumbnailUrl : avatarUrl) block meta - if profile.noCrawle - meta(name='robots' content='noindex') + unless privateMode + if profile.noCrawle + meta(name='robots' content='noindex') - meta(name='misskey:user-username' content=user.username) - meta(name='misskey:user-id' content=user.id) - meta(name='misskey:page-id' content=page.id) + meta(name='misskey:user-username' content=user.username) + meta(name='misskey:user-id' content=user.id) + meta(name='misskey:page-id' content=page.id) - // todo - if user.twitter - meta(name='twitter:creator' content=`@${user.twitter.screenName}`) + // todo + if user.twitter + meta(name='twitter:creator' content=`@${user.twitter.screenName}`) diff --git a/packages/backend/src/server/web/views/user.pug b/packages/backend/src/server/web/views/user.pug index 119993fdb5..cc14dedb3a 100644 --- a/packages/backend/src/server/web/views/user.pug +++ b/packages/backend/src/server/web/views/user.pug @@ -1,39 +1,42 @@ extends ./base block vars - - const title = user.name ? `${user.name} (@${user.username})` : `@${user.username}`; + - const title = privateMode ? instanceName : (user.name ? `${user.name} (@${user.username})` : `@${user.username}`); - const url = `${config.url}/@${(user.host ? `${user.username}@${user.host}` : user.username)}`; block title = `${title} | ${instanceName}` block desc - meta(name='description' content= profile.description) + unless privateMode + meta(name='description' content= profile.description) block og - meta(property='og:type' content='blog') - meta(property='og:title' content= title) - meta(property='og:description' content= profile.description) - meta(property='og:url' content= url) - meta(property='og:image' content= avatarUrl) + unless privateMode + meta(property='og:type' content='blog') + meta(property='og:title' content= title) + meta(property='og:description' content= profile.description) + meta(property='og:url' content= url) + meta(property='og:image' content= avatarUrl) block meta - if user.host || profile.noCrawle - meta(name='robots' content='noindex') + unless privateMode + if user.host || profile.noCrawle + meta(name='robots' content='noindex') - meta(name='misskey:user-username' content=user.username) - meta(name='misskey:user-id' content=user.id) + meta(name='misskey:user-username' content=user.username) + meta(name='misskey:user-id' content=user.id) - if profile.twitter - meta(name='twitter:creator' content=`@${profile.twitter.screenName}`) + if profile.twitter + meta(name='twitter:creator' content=`@${profile.twitter.screenName}`) - if !sub - if !user.host - link(rel='alternate' href=`${config.url}/users/${user.id}` type='application/activity+json') - if user.uri - link(rel='alternate' href=user.uri type='application/activity+json') - if profile.url - link(rel='alternate' href=profile.url type='text/html') + if !sub + if !user.host + link(rel='alternate' href=`${config.url}/users/${user.id}` type='application/activity+json') + if user.uri + link(rel='alternate' href=user.uri type='application/activity+json') + if profile.url + link(rel='alternate' href=profile.url type='text/html') - each m in me - link(rel='me' href=`${m}`) + each m in me + link(rel='me' href=`${m}`)