In private mode, block access to many public APIs

This commit is contained in:
nullobsi 2021-07-20 11:51:59 -07:00 committed by Kayden Tebau
parent 2bf2eac765
commit e7f20affc9
Signed by untrusted user: nullobsi
GPG key ID: 933A1F44222C2634
68 changed files with 98 additions and 8 deletions

View file

@ -7,6 +7,8 @@ import { limiter } from './limiter.js';
import endpoints, { IEndpointMeta } from './endpoints.js'; import endpoints, { IEndpointMeta } from './endpoints.js';
import { ApiError } from './error.js'; import { ApiError } from './error.js';
import { apiLogger } from './logger.js'; import { apiLogger } from './logger.js';
import { AccessToken } from '@/models/entities/access-token.js';
import { fetchMeta } from '@/misc/fetch-meta.js';
const accessDenied = { const accessDenied = {
message: 'Access denied.', 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 // Cast non JSON input
if ((ep.meta.requireFile || ctx?.method === 'GET') && ep.params.properties) { if ((ep.meta.requireFile || ctx?.method === 'GET') && ep.params.properties) {
for (const k of Object.keys(ep.params.properties)) { for (const k of Object.keys(ep.params.properties)) {

View file

@ -706,6 +706,12 @@ export interface IEndpointMeta {
*/ */
readonly secure?: boolean; readonly secure?: boolean;
/**
*
* false
*/
readonly requireCredentialPrivateMode?: boolean;
/** /**
* *
* *

View file

@ -6,6 +6,7 @@ export const meta = {
tags: ['meta'], tags: ['meta'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -5,6 +5,7 @@ export const meta = {
tags: ['channels'], tags: ['channels'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -6,6 +6,7 @@ export const meta = {
tags: ['channels'], tags: ['channels'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'object', type: 'object',

View file

@ -8,6 +8,7 @@ export const meta = {
tags: ['notes', 'channels'], tags: ['notes', 'channels'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -4,6 +4,7 @@ import define from '../../define.js';
export const meta = { export const meta = {
tags: ['charts', 'users'], tags: ['charts', 'users'],
requireCredentialPrivateMode: true,
res: getJsonSchema(activeUsersChart.schema), res: getJsonSchema(activeUsersChart.schema),

View file

@ -4,6 +4,7 @@ import define from '../../define.js';
export const meta = { export const meta = {
tags: ['charts'], tags: ['charts'],
requireCredentialPrivateMode: true,
res: getJsonSchema(apRequestChart.schema), res: getJsonSchema(apRequestChart.schema),

View file

@ -4,6 +4,7 @@ import define from '../../define.js';
export const meta = { export const meta = {
tags: ['charts', 'drive'], tags: ['charts', 'drive'],
requireCredentialPrivateMode: true,
res: getJsonSchema(driveChart.schema), res: getJsonSchema(driveChart.schema),

View file

@ -4,6 +4,7 @@ import define from '../../define.js';
export const meta = { export const meta = {
tags: ['charts'], tags: ['charts'],
requireCredentialPrivateMode: true,
res: getJsonSchema(federationChart.schema), res: getJsonSchema(federationChart.schema),

View file

@ -4,6 +4,7 @@ import define from '../../define.js';
export const meta = { export const meta = {
tags: ['charts', 'hashtags'], tags: ['charts', 'hashtags'],
requireCredentialPrivateMode: true,
res: getJsonSchema(hashtagChart.schema), res: getJsonSchema(hashtagChart.schema),

View file

@ -4,6 +4,7 @@ import define from '../../define.js';
export const meta = { export const meta = {
tags: ['charts'], tags: ['charts'],
requireCredentialPrivateMode: true,
res: getJsonSchema(instanceChart.schema), res: getJsonSchema(instanceChart.schema),

View file

@ -4,6 +4,7 @@ import define from '../../define.js';
export const meta = { export const meta = {
tags: ['charts', 'notes'], tags: ['charts', 'notes'],
requireCredentialPrivateMode: true,
res: getJsonSchema(notesChart.schema), res: getJsonSchema(notesChart.schema),

View file

@ -4,6 +4,7 @@ import define from '../../../define.js';
export const meta = { export const meta = {
tags: ['charts', 'drive', 'users'], tags: ['charts', 'drive', 'users'],
requireCredentialPrivateMode: true,
res: getJsonSchema(perUserDriveChart.schema), res: getJsonSchema(perUserDriveChart.schema),

View file

@ -4,6 +4,7 @@ import { perUserFollowingChart } from '@/services/chart/index.js';
export const meta = { export const meta = {
tags: ['charts', 'users', 'following'], tags: ['charts', 'users', 'following'],
requireCredentialPrivateMode: true,
res: getJsonSchema(perUserFollowingChart.schema), res: getJsonSchema(perUserFollowingChart.schema),

View file

@ -4,6 +4,7 @@ import define from '../../../define.js';
export const meta = { export const meta = {
tags: ['charts', 'users', 'notes'], tags: ['charts', 'users', 'notes'],
requireCredentialPrivateMode: true,
res: getJsonSchema(perUserNotesChart.schema), res: getJsonSchema(perUserNotesChart.schema),

View file

@ -4,6 +4,7 @@ import define from '../../../define.js';
export const meta = { export const meta = {
tags: ['charts', 'users', 'reactions'], tags: ['charts', 'users', 'reactions'],
requireCredentialPrivateMode: true,
res: getJsonSchema(perUserReactionsChart.schema), res: getJsonSchema(perUserReactionsChart.schema),

View file

@ -4,6 +4,7 @@ import define from '../../define.js';
export const meta = { export const meta = {
tags: ['charts', 'users'], tags: ['charts', 'users'],
requireCredentialPrivateMode: true,
res: getJsonSchema(usersChart.schema), res: getJsonSchema(usersChart.schema),

View file

@ -10,6 +10,7 @@ export const meta = {
tags: ['account', 'notes', 'clips'], tags: ['account', 'notes', 'clips'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
kind: 'read:account', kind: 'read:account',

View file

@ -6,6 +6,7 @@ export const meta = {
tags: ['clips', 'account'], tags: ['clips', 'account'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
kind: 'read:account', kind: 'read:account',

View file

@ -6,6 +6,7 @@ export const meta = {
tags: ['federation'], tags: ['federation'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -6,6 +6,7 @@ export const meta = {
tags: ['federation'], tags: ['federation'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -7,6 +7,7 @@ export const meta = {
tags: ['federation'], tags: ['federation'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -6,6 +6,7 @@ export const meta = {
tags: ['federation'], tags: ['federation'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
oneOf: [{ oneOf: [{

View file

@ -6,6 +6,7 @@ export const meta = {
tags: ['federation'], tags: ['federation'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -5,6 +5,7 @@ export const meta = {
tags: ['gallery'], tags: ['gallery'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -5,6 +5,7 @@ export const meta = {
tags: ['gallery'], tags: ['gallery'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -4,6 +4,7 @@ import { GalleryPosts } from '@/models/index.js';
export const meta = { export const meta = {
tags: ['gallery'], tags: ['gallery'],
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -6,6 +6,7 @@ export const meta = {
tags: ['gallery'], tags: ['gallery'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
errors: { errors: {
noSuchPost: { noSuchPost: {

View file

@ -7,6 +7,7 @@ export const meta = {
tags: ['meta'], tags: ['meta'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
} as const; } as const;
export const paramDef = { export const paramDef = {

View file

@ -5,6 +5,7 @@ export const meta = {
tags: ['hashtags'], tags: ['hashtags'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -5,6 +5,7 @@ export const meta = {
tags: ['hashtags'], tags: ['hashtags'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -7,6 +7,7 @@ export const meta = {
tags: ['hashtags'], tags: ['hashtags'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'object', type: 'object',

View file

@ -24,6 +24,7 @@ export const meta = {
tags: ['hashtags'], tags: ['hashtags'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -4,6 +4,7 @@ import { normalizeForSearch } from '@/misc/normalize-for-search.js';
export const meta = { export const meta = {
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
tags: ['hashtags', 'users'], tags: ['hashtags', 'users'],

View file

@ -336,7 +336,7 @@ export default define(meta, paramDef, async (ps, me) => {
expiresAt: MoreThan(new Date()), expiresAt: MoreThan(new Date()),
}, },
}); });
// TODO: add secure mode, etc
const response: any = { const response: any = {
maintainerName: instance.maintainerName, maintainerName: instance.maintainerName,
maintainerEmail: instance.maintainerEmail, maintainerEmail: instance.maintainerEmail,
@ -350,6 +350,10 @@ export default define(meta, paramDef, async (ps, me) => {
tosUrl: instance.ToSUrl, tosUrl: instance.ToSUrl,
repositoryUrl: instance.repositoryUrl, repositoryUrl: instance.repositoryUrl,
feedbackUrl: instance.feedbackUrl, feedbackUrl: instance.feedbackUrl,
secureMode: instance.secureMode,
privateMode: instance.privateMode,
disableRegistration: instance.disableRegistration, disableRegistration: instance.disableRegistration,
disableLocalTimeline: instance.disableLocalTimeline, disableLocalTimeline: instance.disableLocalTimeline,
disableGlobalTimeline: instance.disableGlobalTimeline, disableGlobalTimeline: instance.disableGlobalTimeline,
@ -369,10 +373,10 @@ export default define(meta, paramDef, async (ps, me) => {
backgroundImageUrl: instance.backgroundImageUrl, backgroundImageUrl: instance.backgroundImageUrl,
logoImageUrl: instance.logoImageUrl, logoImageUrl: instance.logoImageUrl,
maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, // 後方互換性のため maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, // 後方互換性のため
emojis: await Emojis.packMany(emojis), emojis: instance.privateMode && !me ? [] : await Emojis.packMany(emojis),
defaultLightTheme: instance.defaultLightTheme, defaultLightTheme: instance.defaultLightTheme,
defaultDarkTheme: instance.defaultDarkTheme, defaultDarkTheme: instance.defaultDarkTheme,
ads: ads.map(ad => ({ ads: instance.privateMode && !me ? [] : ads.map(ad => ({
id: ad.id, id: ad.id,
url: ad.url, url: ad.url,
place: ad.place, place: ad.place,
@ -390,8 +394,8 @@ export default define(meta, paramDef, async (ps, me) => {
translatorAvailable: instance.deeplAuthKey != null, translatorAvailable: instance.deeplAuthKey != null,
...(ps.detail ? { ...(ps.detail ? {
pinnedPages: instance.pinnedPages, pinnedPages: instance.privateMode && !me ? [] : instance.pinnedPages,
pinnedClipId: instance.pinnedClipId, pinnedClipId: instance.privateMode && !me ? [] : instance.pinnedClipId,
cacheRemoteFiles: instance.cacheRemoteFiles, cacheRemoteFiles: instance.cacheRemoteFiles,
requireSetup: (await Users.countBy({ requireSetup: (await Users.countBy({
host: IsNull(), host: IsNull(),
@ -400,9 +404,11 @@ export default define(meta, paramDef, async (ps, me) => {
}; };
if (ps.detail) { 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 = { response.features = {
registration: !instance.disableRegistration, registration: !instance.disableRegistration,
localTimeLine: !instance.disableLocalTimeline, localTimeLine: !instance.disableLocalTimeline,

View file

@ -5,6 +5,7 @@ import { makePaginationQuery } from '../common/make-pagination-query.js';
export const meta = { export const meta = {
tags: ['notes'], tags: ['notes'],
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',
optional: false, nullable: false, optional: false, nullable: false,

View file

@ -10,6 +10,7 @@ export const meta = {
tags: ['notes'], tags: ['notes'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',
@ -20,7 +21,7 @@ export const meta = {
ref: 'Note', ref: 'Note',
}, },
}, },
} as const; };
export const paramDef = { export const paramDef = {
type: 'object', type: 'object',

View file

@ -8,6 +8,7 @@ export const meta = {
tags: ['clips', 'notes'], tags: ['clips', 'notes'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -8,6 +8,7 @@ export const meta = {
tags: ['notes'], tags: ['notes'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -7,6 +7,7 @@ export const meta = {
tags: ['notes'], tags: ['notes'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -12,6 +12,7 @@ import { generateBlockedUserQuery } from '../../common/generate-block-query.js';
export const meta = { export const meta = {
tags: ['notes'], tags: ['notes'],
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',
optional: false, nullable: false, optional: false, nullable: false,

View file

@ -14,6 +14,7 @@ import { generateBlockedUserQuery } from '../../common/generate-block-query.js';
export const meta = { export const meta = {
tags: ['notes'], tags: ['notes'],
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -8,6 +8,7 @@ export const meta = {
tags: ['notes', 'reactions'], tags: ['notes', 'reactions'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
allowGet: true, allowGet: true,
cacheSec: 60, cacheSec: 60,

View file

@ -11,6 +11,7 @@ export const meta = {
tags: ['notes'], tags: ['notes'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -9,6 +9,7 @@ export const meta = {
tags: ['notes'], tags: ['notes'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -10,6 +10,7 @@ import { generateBlockedUserQuery } from '../../common/generate-block-query.js';
export const meta = { export const meta = {
tags: ['notes', 'hashtags'], tags: ['notes', 'hashtags'],
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -12,6 +12,7 @@ export const meta = {
tags: ['notes'], tags: ['notes'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -7,6 +7,7 @@ export const meta = {
tags: ['notes'], tags: ['notes'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'object', type: 'object',

View file

@ -12,6 +12,7 @@ export const meta = {
tags: ['notes'], tags: ['notes'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'object', type: 'object',

View file

@ -5,6 +5,7 @@ export const meta = {
tags: ['pages'], tags: ['pages'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -8,6 +8,7 @@ export const meta = {
tags: ['pages'], tags: ['pages'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'object', type: 'object',

View file

@ -9,6 +9,7 @@ export const meta = {
tags: ['users'], tags: ['users'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -4,6 +4,7 @@ import define from '../define.js';
export const meta = { export const meta = {
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
tags: ['meta'], tags: ['meta'],
} as const; } as const;

View file

@ -5,6 +5,7 @@ import { IsNull } from 'typeorm';
export const meta = { export const meta = {
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
tags: ['meta'], tags: ['meta'],

View file

@ -7,6 +7,7 @@ export const meta = {
tags: ['users'], tags: ['users'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
res: { res: {
type: 'array', type: 'array',

View file

@ -4,6 +4,7 @@ import { makePaginationQuery } from '../../common/make-pagination-query.js';
export const meta = { export const meta = {
tags: ['users', 'clips'], tags: ['users', 'clips'],
requireCredentialPrivateMode: true,
description: 'Show all clips this user owns.', description: 'Show all clips this user owns.',

View file

@ -9,6 +9,7 @@ export const meta = {
tags: ['users'], tags: ['users'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
description: 'Show everyone that follows this user.', description: 'Show everyone that follows this user.',

View file

@ -9,6 +9,7 @@ export const meta = {
tags: ['users'], tags: ['users'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
description: 'Show everyone that this user is following.', description: 'Show everyone that this user is following.',

View file

@ -4,6 +4,7 @@ import { makePaginationQuery } from '../../../common/make-pagination-query.js';
export const meta = { export const meta = {
tags: ['users', 'gallery'], tags: ['users', 'gallery'],
requireCredentialPrivateMode: true,
description: 'Show all gallery posts by the given user.', description: 'Show all gallery posts by the given user.',

View file

@ -9,6 +9,7 @@ export const meta = {
tags: ['users'], tags: ['users'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
description: 'Get a list of other users that the specified user frequently replies to.', description: 'Get a list of other users that the specified user frequently replies to.',

View file

@ -11,6 +11,7 @@ import { generateBlockedUserQuery } from '../../common/generate-block-query.js';
export const meta = { export const meta = {
tags: ['users', 'notes'], tags: ['users', 'notes'],
requireCredentialPrivateMode: true,
description: 'Show all notes that this user created.', description: 'Show all notes that this user created.',
res: { res: {

View file

@ -4,6 +4,7 @@ import { makePaginationQuery } from '../../common/make-pagination-query.js';
export const meta = { export const meta = {
tags: ['users', 'pages'], tags: ['users', 'pages'],
requireCredentialPrivateMode: true,
description: 'Show all pages this user created.', description: 'Show all pages this user created.',

View file

@ -8,6 +8,7 @@ export const meta = {
tags: ['users', 'reactions'], tags: ['users', 'reactions'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
description: 'Show all reactions this user made.', description: 'Show all reactions this user made.',

View file

@ -8,6 +8,7 @@ export const meta = {
tags: ['users'], tags: ['users'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
description: 'Search for a user by username and/or host.', description: 'Search for a user by username and/or host.',

View file

@ -7,6 +7,7 @@ export const meta = {
tags: ['users'], tags: ['users'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
description: 'Search for users.', description: 'Search for users.',

View file

@ -10,6 +10,7 @@ export const meta = {
tags: ['users'], tags: ['users'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
description: 'Show the properties of a user.', description: 'Show the properties of a user.',

View file

@ -7,6 +7,7 @@ export const meta = {
tags: ['users'], tags: ['users'],
requireCredential: false, requireCredential: false,
requireCredentialPrivateMode: true,
description: 'Show statistics about a user.', description: 'Show statistics about a user.',