MFA fix, added IP blacklist, update webmail client

This commit is contained in:
2026-08-14 13:04:55 +01:00
parent 6063f95504
commit 892f366a16
122 changed files with 13362 additions and 251 deletions
+91 -4
View File
@@ -1,6 +1,9 @@
package db
import "time"
import (
"encoding/json"
"time"
)
// Mailbox is a real, IMAP-retrievable local mailbox — distinct from Sender (which is
// relay/auth-only). PasswordHash authenticates the self-service web portal only;
@@ -68,6 +71,8 @@ type MailboxAllowBlockEntry struct {
}
// MailboxFilterRule is one priority-ordered, first-match-wins delivery rule.
// ConditionField/Op/Value are the legacy single-condition columns; ConditionsJSON
// (when non-empty) is the current multi-condition representation — see Conditions().
type MailboxFilterRule struct {
ID int64
MailboxID int64
@@ -75,12 +80,40 @@ type MailboxFilterRule struct {
ConditionField string // "from" | "to" | "subject"
ConditionOp string // "contains" | "equals" | "starts_with"
ConditionValue string
Action string // "move_to_folder" | "delete" | "mark_read"
Action string // "move_to_folder" | "delete" | "mark_read" | "mark_as_spam"
ActionValue string
IsActive bool
ConditionsJSON string
MatchType string // "all" (AND, default) | "any" (OR)
CreatedAt time.Time
}
// RuleCondition is one condition within a filter rule's "if" clause.
type RuleCondition struct {
Field string `json:"field"`
Op string `json:"op"`
Value string `json:"value"`
}
// Conditions returns this rule's conditions and how they combine ("all"=AND,
// "any"=OR) — parses ConditionsJSON when present, falling back to the single legacy
// condition_field/op/value columns for rules created before multi-condition support
// existed. Shared by mailstore.ApplyRules (evaluation) and the webui (display), so
// both stay in sync with the same fallback rule.
func (r MailboxFilterRule) Conditions() ([]RuleCondition, string) {
if r.ConditionsJSON != "" {
var parsed []RuleCondition
if err := json.Unmarshal([]byte(r.ConditionsJSON), &parsed); err == nil && len(parsed) > 0 {
matchType := r.MatchType
if matchType != "any" {
matchType = "all"
}
return parsed, matchType
}
}
return []RuleCondition{{Field: r.ConditionField, Op: r.ConditionOp, Value: r.ConditionValue}}, "all"
}
// MailboxAppPassword is the only credential an IMAP/SMTP client ever uses. Plaintext
// is shown once at creation and never stored. ExpiresAt is nil for a password that
// never expires (the default).
@@ -95,8 +128,10 @@ type MailboxAppPassword struct {
ExpiresAt *time.Time
}
// MailboxMessage is one stored message. CachedFrom/CachedSubject are plaintext by
// design (see schema.go); the rest of the message lives encrypted at StoragePath.
// MailboxMessage is one stored message. CachedFrom/CachedTo/CachedSubject are
// plaintext by design (see schema.go); the rest of the message lives encrypted at
// StoragePath. CachedTo exists purely so folder listings (e.g. Sent) can show the
// recipient without decrypting every message just to render a list.
type MailboxMessage struct {
ID int64
MailboxID int64
@@ -106,8 +141,60 @@ type MailboxMessage struct {
InternalDate time.Time
SizeBytes int64
CachedFrom string
CachedTo string
CachedSubject string
StoragePath string
Nonce []byte
CreatedAt time.Time
}
// MailboxSMIMEIdentity is one of a mailbox's own S/MIME certificate + private key
// pairs — a mailbox may hold several. Both halves are stored plain: S/MIME is
// sign-only in this codebase, so the key never protects anything beyond what the
// server already has access to.
type MailboxSMIMEIdentity struct {
ID int64
MailboxID int64
CertPEM string
KeyPEM string
NotAfter time.Time
CreatedAt time.Time
}
// MailboxSMIMEContact is another address's public certificate a mailbox owner has
// collected, either added by hand or auto-captured off a verified signature.
type MailboxSMIMEContact struct {
ID int64
MailboxID int64
Email string
CertPEM string
CreatedAt time.Time
}
// MailboxPGPIdentity is one of a mailbox's own PGP keypairs — a mailbox may hold
// several. PrivateKeyArmor is stored exactly as the pgp package serializes it,
// already passphrase-protected via OpenPGP's own native key-encryption format (no
// separate ciphertext/nonce/salt columns needed, unlike MailboxSMIMEIdentity).
// Label is a free-text user note distinguishing keys (PGP keys have no expiry).
type MailboxPGPIdentity struct {
ID int64
MailboxID int64
Label string
Email string
Fingerprint string
PublicKeyArmor string
PrivateKeyArmor string
CreatedAt time.Time
}
// MailboxPGPContact is another address's PGP public key a mailbox owner has
// collected — mirrors MailboxSMIMEContact.
type MailboxPGPContact struct {
ID int64
MailboxID int64
Email string
Label string
PublicKeyArmor string
Fingerprint string
CreatedAt time.Time
}