feat: security hardening, DB indexes, token revocation, and input validation
- SSRF protection: DNS resolution + private IP blocking on metadata fetcher - Upload security: CSP/X-Frame-Options headers, SVG forced download, nosniff - Auth hardening: JWT secret min length, password min 8 chars, token revocation via password_changed_at - Attachment ownership verification before linking to messages - Message length limit (4000 chars) enforced on client and server - Asset URL validation on avatar/banner updates - Federation instance validation (domain regex, origin scheme, length limits) - DB indexes on all FK columns for query performance - Migrations: nullable moderator columns, dm_messages reply_to FK constraint - File cleanup on avatar/banner replacement and space deletion - Fastify trustProxy, AbortController on fetches, typing map size cap
This commit is contained in:
@@ -24,8 +24,18 @@ function createTables(db: Database.Database): void {
|
||||
avatar TEXT,
|
||||
status TEXT DEFAULT 'offline',
|
||||
custom_status TEXT,
|
||||
is_admin INTEGER DEFAULT 0,
|
||||
home_instance TEXT,
|
||||
home_user_id TEXT,
|
||||
replicated_instances TEXT DEFAULT '[]',
|
||||
banner TEXT,
|
||||
accent_color TEXT,
|
||||
avatar_color TEXT,
|
||||
bio TEXT,
|
||||
is_deleted INTEGER DEFAULT 0,
|
||||
discoverable INTEGER DEFAULT 1,
|
||||
profile_updated_at INTEGER,
|
||||
password_changed_at INTEGER,
|
||||
created_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
@@ -33,8 +43,12 @@ function createTables(db: Database.Database): void {
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
icon TEXT,
|
||||
banner TEXT,
|
||||
avatar_color TEXT,
|
||||
owner_id TEXT NOT NULL REFERENCES users(id),
|
||||
invite_code TEXT UNIQUE,
|
||||
visibility TEXT DEFAULT 'private',
|
||||
description TEXT,
|
||||
created_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
@@ -46,6 +60,14 @@ function createTables(db: Database.Database): void {
|
||||
PRIMARY KEY (space_id, user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS channel_categories (
|
||||
id TEXT PRIMARY KEY,
|
||||
space_id TEXT NOT NULL REFERENCES spaces(id) ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
position INTEGER DEFAULT 0,
|
||||
created_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS channels (
|
||||
id TEXT PRIMARY KEY,
|
||||
space_id TEXT NOT NULL REFERENCES spaces(id) ON DELETE CASCADE,
|
||||
@@ -53,6 +75,7 @@ function createTables(db: Database.Database): void {
|
||||
type TEXT NOT NULL,
|
||||
topic TEXT,
|
||||
position INTEGER DEFAULT 0,
|
||||
category_id TEXT,
|
||||
created_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
@@ -69,10 +92,13 @@ function createTables(db: Database.Database): void {
|
||||
CREATE TABLE IF NOT EXISTS attachments (
|
||||
id TEXT PRIMARY KEY,
|
||||
message_id TEXT REFERENCES messages(id) ON DELETE CASCADE,
|
||||
dm_message_id TEXT,
|
||||
uploader_id TEXT,
|
||||
filename TEXT NOT NULL,
|
||||
original_name TEXT NOT NULL,
|
||||
mimetype TEXT NOT NULL,
|
||||
size INTEGER NOT NULL,
|
||||
thumbnail_filename TEXT,
|
||||
created_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
@@ -85,6 +111,7 @@ function createTables(db: Database.Database): void {
|
||||
CREATE TABLE IF NOT EXISTS dm_members (
|
||||
dm_channel_id TEXT NOT NULL REFERENCES dm_channels(id) ON DELETE CASCADE,
|
||||
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
closed INTEGER DEFAULT 0,
|
||||
PRIMARY KEY (dm_channel_id, user_id)
|
||||
);
|
||||
|
||||
@@ -92,7 +119,9 @@ function createTables(db: Database.Database): void {
|
||||
id TEXT PRIMARY KEY,
|
||||
dm_channel_id TEXT NOT NULL REFERENCES dm_channels(id) ON DELETE CASCADE,
|
||||
user_id TEXT NOT NULL REFERENCES users(id),
|
||||
reply_to_id TEXT REFERENCES dm_messages(id) ON DELETE SET NULL,
|
||||
content TEXT,
|
||||
edited_at INTEGER,
|
||||
created_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
@@ -122,7 +151,7 @@ function createTables(db: Database.Database): void {
|
||||
|
||||
CREATE TABLE IF NOT EXISTS dm_reactions (
|
||||
id TEXT PRIMARY KEY,
|
||||
dm_message_id TEXT NOT NULL,
|
||||
dm_message_id TEXT NOT NULL REFERENCES dm_messages(id) ON DELETE CASCADE,
|
||||
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
emoji TEXT NOT NULL,
|
||||
created_at INTEGER NOT NULL,
|
||||
@@ -179,10 +208,17 @@ function createTables(db: Database.Database): void {
|
||||
PRIMARY KEY (folder_id, space_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_space_layout (
|
||||
user_id TEXT PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
|
||||
layout TEXT NOT NULL DEFAULT '[]',
|
||||
updated_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS instance_settings (
|
||||
id INTEGER PRIMARY KEY DEFAULT 1 CHECK (id = 1),
|
||||
instance_name TEXT DEFAULT 'Backspace',
|
||||
worker_id INTEGER,
|
||||
discovery_enabled INTEGER NOT NULL DEFAULT 1,
|
||||
max_bitrate_kbps INTEGER NOT NULL DEFAULT 20000,
|
||||
min_bitrate_kbps INTEGER NOT NULL DEFAULT 500,
|
||||
bitrate_step_kbps INTEGER NOT NULL DEFAULT 500,
|
||||
@@ -190,8 +226,38 @@ function createTables(db: Database.Database): void {
|
||||
allowed_framerates TEXT NOT NULL DEFAULT '30,45,60',
|
||||
max_resolution INTEGER NOT NULL DEFAULT 1080,
|
||||
max_framerate INTEGER NOT NULL DEFAULT 60,
|
||||
registration_open INTEGER,
|
||||
updated_at INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS bans (
|
||||
space_id TEXT NOT NULL REFERENCES spaces(id) ON DELETE CASCADE,
|
||||
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
reason TEXT,
|
||||
banned_by TEXT REFERENCES users(id),
|
||||
created_at INTEGER NOT NULL,
|
||||
PRIMARY KEY (space_id, user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS join_requests (
|
||||
id TEXT PRIMARY KEY,
|
||||
space_id TEXT NOT NULL REFERENCES spaces(id) ON DELETE CASCADE,
|
||||
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
message TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'pending',
|
||||
decided_by TEXT REFERENCES users(id),
|
||||
created_at INTEGER NOT NULL,
|
||||
decided_at INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS voice_restrictions (
|
||||
space_id TEXT NOT NULL REFERENCES spaces(id) ON DELETE CASCADE,
|
||||
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
restriction_type TEXT NOT NULL,
|
||||
moderator_id TEXT REFERENCES users(id),
|
||||
created_at INTEGER NOT NULL,
|
||||
PRIMARY KEY (space_id, user_id, restriction_type)
|
||||
);
|
||||
`);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user