Files
d ab5a82372c feat: content-addressable dedup storage + limits + block shredding
Attachment deduplication (SHA-256 content-addressable storage):
- Identical files stored once globally (m8sh/sha256/<hash>)
- Reference-counted deletion: blob removed only when last ref deleted
- StoreAttachmentDedup, DeleteAttachmentDedup, StoreAttachmentFromReader

Comprehensive safety limits:
- USER_QUOTA: 5 GB default (admins unlimited, 0 = unlimited)
- MAX_ATTACHMENT_SIZE: 100 MB per file
- MAX_ATTACHMENTS_PER_MESSAGE: 50 files
- MAX_MESSAGE_SIZE: 1 MB body
- MAX_CONVERSATIONS: 1000 per user
- MAX_MESSAGES_PER_CONVERSATION: 10000

Block-domain shredding:
- ShredAttachmentsForDomain deletes all blobs + metadata for domain
- Dedup-aware: only removes blobs with no remaining references

Assisted-By: Cline:anthropic-claude-sonnet-4-20250514
2026-07-21 23:40:12 +03:00

58 lines
2.6 KiB
Go

// Copyright 2026 The M8SH Authors. All rights reserved.
// SPDX-License-Identifier: GPL-3.0
package setting
import (
"time"
"gitea.dev/modules/log"
)
// MailServer holds the configuration for the built-in M8SH SMTP server.
// Section [mail_server] in app.ini. Domain and certs are NOT configured here;
// they come from [server].DOMAIN and the existing TLS config respectively,
// so M8SH stays merge-friendly with upstream Gitea.
type MailServer struct {
Enabled bool `ini:"ENABLED"`
DKIMPrivateKey string `ini:"DKIM_PRIVATE_KEY"` // base64 PEM, auto-generated if empty
HealthcheckInterv time.Duration `ini:"HEALTHCHECK_INTERVAL"`
// Storage quota per user in bytes. Admins have unlimited quota.
// Default: 5 GB. Set to 0 for unlimited.
UserQuota int64 `ini:"USER_QUOTA"`
// Maximum attachment size in bytes per single file. Default: 100 MB.
MaxAttachmentSize int64 `ini:"MAX_ATTACHMENT_SIZE"`
// Maximum number of attachments per message. Default: 50.
MaxAttachmentsPerMessage int `ini:"MAX_ATTACHMENTS_PER_MESSAGE"`
// Maximum message body size in bytes. Default: 1 MB.
MaxMessageSize int64 `ini:"MAX_MESSAGE_SIZE"`
// Maximum number of conversations per user. Default: 1000.
MaxConversations int `ini:"MAX_CONVERSATIONS"`
// Maximum number of messages per conversation. Default: 10000.
MaxMessagesPerConversation int `ini:"MAX_MESSAGES_PER_CONVERSATION"`
}
// M8SHMailServer is the global M8SH mail server config.
var M8SHMailServer *MailServer
func loadMailServerFrom(rootCfg ConfigProvider) {
sec := rootCfg.Section("mail_server")
m := &MailServer{}
if err := sec.MapTo(m); err != nil {
log.Fatal("Unable to map [mail_server] section on to M8SHMailServer. Error: %v", err)
return
}
// Enabled by default — the mail server starts automatically.
// Set ENABLED = false to disable email delivery (HTTPS chat still works).
m.Enabled = sec.Key("ENABLED").MustBool(true)
m.HealthcheckInterv = sec.Key("HEALTHCHECK_INTERVAL").MustDuration(5 * time.Minute)
m.DKIMPrivateKey = sec.Key("DKIM_PRIVATE_KEY").String()
// Defaults: 5 GB quota, 100 MB files, 50 atts/msg, 1 MB body, 1k threads, 10k msgs/thread
m.UserQuota = sec.Key("USER_QUOTA").MustInt64(5 * 1024 * 1024 * 1024)
m.MaxAttachmentSize = sec.Key("MAX_ATTACHMENT_SIZE").MustInt64(100 * 1024 * 1024)
m.MaxAttachmentsPerMessage = sec.Key("MAX_ATTACHMENTS_PER_MESSAGE").MustInt(50)
m.MaxMessageSize = sec.Key("MAX_MESSAGE_SIZE").MustInt64(1024 * 1024)
m.MaxConversations = sec.Key("MAX_CONVERSATIONS").MustInt(1000)
m.MaxMessagesPerConversation = sec.Key("MAX_MESSAGES_PER_CONVERSATION").MustInt(10000)
M8SHMailServer = m
}