upd: Note Length customization

note length is now configurable through the config file

Closes #281

falls back to 3000 (misskey default) if not used/included in config
This commit is contained in:
Marie 2023-12-31 18:22:02 +01:00
parent 031d748d0c
commit b1c26201ca
No known key found for this signature in database
GPG key ID: 56569BBE47D2C828
8 changed files with 43 additions and 12 deletions

View file

@ -167,6 +167,9 @@ id: 'aidx'
# IP address family used for outgoing request (ipv4, ipv6 or dual) # IP address family used for outgoing request (ipv4, ipv6 or dual)
#outgoingAddressFamily: ipv4 #outgoingAddressFamily: ipv4
# Amount of characters that can be used when writing notes (maximum: 8192, minimum: 1)
maxNoteLength: 3000
# Proxy for HTTP/HTTPS # Proxy for HTTP/HTTPS
#proxy: http://127.0.0.1:3128 #proxy: http://127.0.0.1:3128
@ -197,6 +200,8 @@ proxyRemoteFiles: true
# Sign to ActivityPub GET request (default: true) # Sign to ActivityPub GET request (default: true)
signToActivityPubGet: true signToActivityPubGet: true
# check that inbound ActivityPub GET requests are signed ("authorized fetch")
checkActivityPubGetSignature: false
# For security reasons, uploading attachments from the intranet is prohibited, # For security reasons, uploading attachments from the intranet is prohibited,
# but exceptions can be made from the following settings. Default value is "undefined". # but exceptions can be made from the following settings. Default value is "undefined".

View file

@ -179,6 +179,9 @@ id: 'aidx'
# IP address family used for outgoing request (ipv4, ipv6 or dual) # IP address family used for outgoing request (ipv4, ipv6 or dual)
#outgoingAddressFamily: ipv4 #outgoingAddressFamily: ipv4
# Amount of characters that can be used when writing notes (maximum: 8192, minimum: 1)
maxNoteLength: 3000
# Proxy for HTTP/HTTPS # Proxy for HTTP/HTTPS
#proxy: http://127.0.0.1:3128 #proxy: http://127.0.0.1:3128

View file

@ -7,8 +7,8 @@ import * as fs from 'node:fs';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import { dirname, resolve } from 'node:path'; import { dirname, resolve } from 'node:path';
import * as yaml from 'js-yaml'; import * as yaml from 'js-yaml';
import type { RedisOptions } from 'ioredis';
import { globSync } from 'glob'; import { globSync } from 'glob';
import type { RedisOptions } from 'ioredis';
type RedisOptionsSource = Partial<RedisOptions> & { type RedisOptionsSource = Partial<RedisOptions> & {
host: string; host: string;
@ -65,6 +65,7 @@ type Source = {
allowedPrivateNetworks?: string[]; allowedPrivateNetworks?: string[];
maxFileSize?: number; maxFileSize?: number;
maxNoteLength?: number;
clusterLimit?: number; clusterLimit?: number;
@ -133,6 +134,7 @@ export type Config = {
proxyBypassHosts: string[] | undefined; proxyBypassHosts: string[] | undefined;
allowedPrivateNetworks: string[] | undefined; allowedPrivateNetworks: string[] | undefined;
maxFileSize: number | undefined; maxFileSize: number | undefined;
maxNoteLength: number;
clusterLimit: number | undefined; clusterLimit: number | undefined;
id: string; id: string;
outgoingAddress: string | undefined; outgoingAddress: string | undefined;
@ -249,6 +251,7 @@ export function loadConfig(): Config {
proxyBypassHosts: config.proxyBypassHosts, proxyBypassHosts: config.proxyBypassHosts,
allowedPrivateNetworks: config.allowedPrivateNetworks, allowedPrivateNetworks: config.allowedPrivateNetworks,
maxFileSize: config.maxFileSize, maxFileSize: config.maxFileSize,
maxNoteLength: config.maxNoteLength ?? 3000,
clusterLimit: config.clusterLimit, clusterLimit: config.clusterLimit,
outgoingAddress: config.outgoingAddress, outgoingAddress: config.outgoingAddress,
outgoingAddressFamily: config.outgoingAddressFamily, outgoingAddressFamily: config.outgoingAddressFamily,

View file

@ -7,7 +7,6 @@ import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import { MetaService } from '@/core/MetaService.js'; import { MetaService } from '@/core/MetaService.js';
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
import { MemorySingleCache } from '@/misc/cache.js'; import { MemorySingleCache } from '@/misc/cache.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
@ -118,7 +117,7 @@ export class NodeinfoServerService {
emailRequiredForSignup: meta.emailRequiredForSignup, emailRequiredForSignup: meta.emailRequiredForSignup,
enableHcaptcha: meta.enableHcaptcha, enableHcaptcha: meta.enableHcaptcha,
enableRecaptcha: meta.enableRecaptcha, enableRecaptcha: meta.enableRecaptcha,
maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, maxNoteTextLength: this.config.maxNoteLength,
enableEmail: meta.enableEmail, enableEmail: meta.enableEmail,
enableServiceWorker: meta.enableServiceWorker, enableServiceWorker: meta.enableServiceWorker,
proxyAccountName: proxyAccount ? proxyAccount.username : null, proxyAccountName: proxyAccount ? proxyAccount.username : null,

View file

@ -7,7 +7,6 @@ import { IsNull, LessThanOrEqual, MoreThan, Brackets } from 'typeorm';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import JSON5 from 'json5'; import JSON5 from 'json5';
import type { AdsRepository, UsersRepository } from '@/models/_.js'; import type { AdsRepository, UsersRepository } from '@/models/_.js';
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { MetaService } from '@/core/MetaService.js'; import { MetaService } from '@/core/MetaService.js';
@ -375,7 +374,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
iconUrl: instance.iconUrl, iconUrl: instance.iconUrl,
backgroundImageUrl: instance.backgroundImageUrl, backgroundImageUrl: instance.backgroundImageUrl,
logoImageUrl: instance.logoImageUrl, logoImageUrl: instance.logoImageUrl,
maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, maxNoteTextLength: this.config.maxNoteLength,
// クライアントの手間を減らすためあらかじめJSONに変換しておく // クライアントの手間を減らすためあらかじめJSONに変換しておく
defaultLightTheme: instance.defaultLightTheme ? JSON.stringify(JSON5.parse(instance.defaultLightTheme)) : null, defaultLightTheme: instance.defaultLightTheme ? JSON.stringify(JSON5.parse(instance.defaultLightTheme)) : null,
defaultDarkTheme: instance.defaultDarkTheme ? JSON.stringify(JSON5.parse(instance.defaultDarkTheme)) : null, defaultDarkTheme: instance.defaultDarkTheme ? JSON.stringify(JSON5.parse(instance.defaultDarkTheme)) : null,

View file

@ -11,7 +11,7 @@ import type { UsersRepository, NotesRepository, BlockingsRepository, DriveFilesR
import type { MiDriveFile } from '@/models/DriveFile.js'; import type { MiDriveFile } from '@/models/DriveFile.js';
import type { MiNote } from '@/models/Note.js'; import type { MiNote } from '@/models/Note.js';
import type { MiChannel } from '@/models/Channel.js'; import type { MiChannel } from '@/models/Channel.js';
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; import type { Config } from '@/config.js';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { NoteCreateService } from '@/core/NoteCreateService.js'; import { NoteCreateService } from '@/core/NoteCreateService.js';
@ -82,6 +82,12 @@ export const meta = {
id: '3ac74a84-8fd5-4bb0-870f-01804f82ce15', id: '3ac74a84-8fd5-4bb0-870f-01804f82ce15',
}, },
maxLength: {
message: 'You tried posting a note which is too long.',
code: 'MAX_LENGTH',
id: '3ac74a84-8fd5-4bb0-870f-01804f82ce16',
},
cannotCreateAlreadyExpiredPoll: { cannotCreateAlreadyExpiredPoll: {
message: 'Poll is already expired.', message: 'Poll is already expired.',
code: 'CANNOT_CREATE_ALREADY_EXPIRED_POLL', code: 'CANNOT_CREATE_ALREADY_EXPIRED_POLL',
@ -136,7 +142,6 @@ export const paramDef = {
text: { text: {
type: 'string', type: 'string',
minLength: 1, minLength: 1,
maxLength: MAX_NOTE_TEXT_LENGTH,
nullable: true, nullable: true,
}, },
fileIds: { fileIds: {
@ -184,6 +189,9 @@ export const paramDef = {
@Injectable() @Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.config)
private config: Config,
@Inject(DI.usersRepository) @Inject(DI.usersRepository)
private usersRepository: UsersRepository, private usersRepository: UsersRepository,
@ -203,6 +211,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private noteCreateService: NoteCreateService, private noteCreateService: NoteCreateService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
if (ps.text && (ps.text.length > this.config.maxNoteLength)) {
throw new ApiError(meta.errors.maxLength);
}
let visibleUsers: MiUser[] = []; let visibleUsers: MiUser[] = [];
if (ps.visibleUserIds) { if (ps.visibleUserIds) {
visibleUsers = await this.usersRepository.findBy({ visibleUsers = await this.usersRepository.findBy({

View file

@ -6,7 +6,7 @@ import type { UsersRepository, NotesRepository, BlockingsRepository, DriveFilesR
import type { MiDriveFile } from '@/models/DriveFile.js'; import type { MiDriveFile } from '@/models/DriveFile.js';
import type { MiNote } from '@/models/Note.js'; import type { MiNote } from '@/models/Note.js';
import type { MiChannel } from '@/models/Channel.js'; import type { MiChannel } from '@/models/Channel.js';
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; import type { Config } from '@/config.js';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { NoteEditService } from '@/core/NoteEditService.js'; import { NoteEditService } from '@/core/NoteEditService.js';
@ -135,6 +135,12 @@ export const meta = {
code: 'CANNOT_QUOTE_THE_CURRENT_NOTE', code: 'CANNOT_QUOTE_THE_CURRENT_NOTE',
id: '33510210-8452-094c-6227-4a6c05d99f02', id: '33510210-8452-094c-6227-4a6c05d99f02',
}, },
maxLength: {
message: 'You tried posting a note which is too long.',
code: 'MAX_LENGTH',
id: '3ac74a84-8fd5-4bb0-870f-01804f82ce16',
},
}, },
} as const; } as const;
@ -163,7 +169,6 @@ export const paramDef = {
text: { text: {
type: 'string', type: 'string',
minLength: 1, minLength: 1,
maxLength: MAX_NOTE_TEXT_LENGTH,
nullable: true, nullable: true,
}, },
fileIds: { fileIds: {
@ -205,7 +210,6 @@ export const paramDef = {
text: { text: {
type: 'string', type: 'string',
minLength: 1, minLength: 1,
maxLength: MAX_NOTE_TEXT_LENGTH,
nullable: false, nullable: false,
}, },
}, },
@ -236,6 +240,9 @@ export const paramDef = {
@Injectable() @Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.config)
private config: Config,
@Inject(DI.usersRepository) @Inject(DI.usersRepository)
private usersRepository: UsersRepository, private usersRepository: UsersRepository,
@ -255,6 +262,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private noteEditService: NoteEditService, private noteEditService: NoteEditService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
if (ps.text && (ps.text.length > this.config.maxNoteLength)) {
throw new ApiError(meta.errors.maxLength);
}
let visibleUsers: MiUser[] = []; let visibleUsers: MiUser[] = [];
if (ps.visibleUserIds) { if (ps.visibleUserIds) {
visibleUsers = await this.usersRepository.findBy({ visibleUsers = await this.usersRepository.findBy({

View file

@ -1,5 +1,5 @@
import { Entity } from 'megalodon'; import { Entity } from 'megalodon';
import { MAX_NOTE_TEXT_LENGTH, FILE_TYPE_BROWSERSAFE } from '@/const.js'; import { FILE_TYPE_BROWSERSAFE } from '@/const.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import type { MiMeta } from '@/models/Meta.js'; import type { MiMeta } from '@/models/Meta.js';
@ -35,7 +35,7 @@ export async function getInstance(
max_featured_tags: 20, max_featured_tags: 20,
}, },
statuses: { statuses: {
max_characters: MAX_NOTE_TEXT_LENGTH, max_characters: config.maxNoteLength,
max_media_attachments: 16, max_media_attachments: 16,
characters_reserved_per_url: response.uri.length, characters_reserved_per_url: response.uri.length,
}, },