1/*2Maddy Mail Server - Composable all-in-one email server.3Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors45This program is free software: you can redistribute it and/or modify6it under the terms of the GNU General Public License as published by7the Free Software Foundation, either version 3 of the License, or8(at your option) any later version.910This program is distributed in the hope that it will be useful,11but WITHOUT ANY WARRANTY; without even the implied warranty of12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13GNU General Public License for more details.1415You should have received a copy of the GNU General Public License16along with this program. If not, see <https://www.gnu.org/licenses/>.17*/1819package module2021import (22 "context"2324 "github.com/emersion/go-message/textproto"25 "github.com/emersion/go-msgauth/authres"26 "github.com/foxcpp/maddy/framework/buffer"27)2829// Check is the module interface that is meant for read-only (with the30// exception of the message header modifications) (meta-)data checking.31//32// Modules implementing this interface should be registered with "check."33// prefix in name.34type Check interface {35 // CheckStateForMsg initializes the "internal" check state required for36 // processing of the new message.37 //38 // NOTE: Returned CheckState object must be hashable (usable as a map key).39 // This is used to deduplicate Check* calls, the easiest way to achieve40 // this is to have CheckState as a pointer to some struct, all pointers41 // are hashable.42 CheckStateForMsg(ctx context.Context, msgMeta *MsgMetadata) (CheckState, error)43}4445// EarlyCheck is an optional module interface that can be implemented46// by module implementing Check.47//48// It is used as an optimization to reject obviously malicious connections49// before allocating resources for SMTP session.50//51// The Status of this check is accept (no error) or reject (error) only, no52// advanced handling is available (such as 'quarantine' action and headers53// prepending).54//55// If it s necessary to defer or affect further message processing56// without outright killing the session, ConnState.ModData can be57// used to store necessary information.58//59// It may be called multiple times for the same connection if TLS is negotiated60// via STARTTLS. In this case, no state will be passed between before-TLS61// context to the TLS one.62type EarlyCheck interface {63 CheckConnection(ctx context.Context, state *ConnState) error64}6566type CheckState interface {67 // CheckConnection is executed once when client sends a new message.68 CheckConnection(ctx context.Context) CheckResult6970 // CheckSender is executed once when client sends the message sender71 // information (e.g. on the MAIL FROM command).72 CheckSender(ctx context.Context, mailFrom string) CheckResult7374 // CheckRcpt is executed for each recipient when its address is received75 // from the client (e.g. on the RCPT TO command).76 CheckRcpt(ctx context.Context, rcptTo string) CheckResult7778 // CheckBody is executed once after the message body is received and79 // buffered in memory or on disk.80 //81 // Check code should use passed mutex when working with the message header.82 // Body can be read without locking it since it is read-only.83 CheckBody(ctx context.Context, header textproto.Header, body buffer.Buffer) CheckResult8485 // Close is called after the message processing ends, even if any of the86 // Check* functions return an error.87 Close() error88}8990type CheckResult struct {91 // Reason is the error that is reported to the message source92 // if check decided that the message should be rejected.93 Reason error9495 // Reject is the flag that specifies that the message96 // should be rejected.97 Reject bool9899 // Quarantine is the flag that specifies that the message100 // is considered "possibly malicious" and should be101 // put into Junk mailbox.102 //103 // This value is copied into MsgMetadata by the msgpipeline.104 Quarantine bool105106 // AuthResult is the information that is supposed to107 // be included in Authentication-Results header.108 AuthResult []authres.Result109110 // Header is the header fields that should be111 // added to the header after all checks.112 Header textproto.Header113}