Files
selfpost/third_party/go-milter/response.go
T
mixandClaude Opus 5.5 f1d90a2a1b
test / test (push) Waiting to run
go-milter: build it patched not to keep every header
The security documentation's last open item of panel-dkim-signing (the
owner's decision, 2026-10-16): go-milter v0.4.1 added every header of a
session to a map of its own, emptied only on ABORT, and handed it to
Headers - which no milter of the panel reads. Postfix bounds one header,
not their number, so a message of nothing but headers up to the message
size limit was held whole by the library in the sender check, the signer
and the journal milter on 465/587 and in the inbound journal milter on port
25, where strangers send; the signer's 1 MiB refusal came after it was all
in.

third_party/go-milter is v0.4.1 from the module cache (BSD 2-Clause,
LICENSE kept) with session.go changed: CodeHeader hands the header to
Header and keeps nothing, CodeEOH hands Headers an empty map. PATCHES.md
says what and why, and how to take a new upstream version. go.mod replaces
the module with it; the Dockerfile copies third_party before "go mod
download". TestTheLibraryKeepsNoHeaders holds it through the library's own
client over two messages of one connection. Comments, security.md (the
accepted risk becomes a note), development.md's library table, the plan and
CHANGELOG follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 09:19:57 +03:00

63 lines
1.7 KiB
Go

package milter
// Response represents a response structure returned by callback
// handlers to indicate how the milter server should proceed
type Response interface {
Response() *Message
Continue() bool
}
// SimpleResponse type to define list of pre-defined responses
type SimpleResponse byte
// Response returns a Message object reference
func (r SimpleResponse) Response() *Message {
return &Message{byte(r), nil}
}
// Continue to process milter messages only if current code is Continue
func (r SimpleResponse) Continue() bool {
return ActionCode(r) == ActContinue
}
// Define standard responses with no data
const (
RespAccept = SimpleResponse(ActAccept)
RespContinue = SimpleResponse(ActContinue)
RespDiscard = SimpleResponse(ActDiscard)
RespReject = SimpleResponse(ActReject)
RespTempFail = SimpleResponse(ActTempFail)
)
// CustomResponse is a response instance used by callback handlers to indicate
// how the milter should continue processing of current message
type CustomResponse struct {
code byte
data []byte
}
// Response returns message instance with data
func (c *CustomResponse) Response() *Message {
return &Message{c.code, c.data}
}
// Continue returns false if milter chain should be stopped, true otherwise
func (c *CustomResponse) Continue() bool {
for _, q := range []ActionCode{ActAccept, ActDiscard, ActReject, ActTempFail} {
if c.code == byte(q) {
return false
}
}
return true
}
// NewResponse generates a new CustomResponse suitable for WritePacket
func NewResponse(code byte, data []byte) *CustomResponse {
return &CustomResponse{code, data}
}
// NewResponseStr generates a new CustomResponse with string payload
func NewResponseStr(code byte, data string) *CustomResponse {
return NewResponse(code, []byte(data+null))
}