Compare commits
6 Commits
pkg/dev/ub
...
staging
Author | SHA1 | Date | |
---|---|---|---|
19e15d3fe7 | |||
db0a3ac98f | |||
b335a825a3 | |||
f959fdb93f | |||
6a52595fa7 | |||
450a9de82d |
@ -5,4 +5,5 @@
|
||||
/bin
|
||||
/misc/docker/Dockerfile
|
||||
/.env
|
||||
/.env.dist
|
||||
/.env.dist
|
||||
/tools
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -3,4 +3,5 @@
|
||||
/vendor
|
||||
/bin
|
||||
/node_modules
|
||||
/.env
|
||||
/.env
|
||||
/tools
|
14
Makefile
14
Makefile
@ -1,4 +1,14 @@
|
||||
DOCKER_DATE_TAG := $(shell date +%Y%m%d%H%M)
|
||||
DOCKER_DATE_TAG := $(shell date --utc +%Y.%-m.%-d%-H%-M)
|
||||
|
||||
YQ_VERSION ?= v4.30.4
|
||||
YQ_BINARY ?= yq_linux_amd64
|
||||
|
||||
tools: tools/yq/bin/yq
|
||||
|
||||
tools/yq/bin/yq:
|
||||
mkdir -p tools/yq/bin
|
||||
wget https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/${YQ_BINARY} -O tools/yq/bin/yq &&\
|
||||
chmod +x tools/yq/bin/yq
|
||||
|
||||
build:
|
||||
CGO_ENABLED=0 go build -v -o bin/fake-smtp ./cmd/fake-smtp
|
||||
@ -31,7 +41,7 @@ docker-release:
|
||||
test:
|
||||
go test -v -race ./...
|
||||
|
||||
release: dist
|
||||
release: dist tools
|
||||
@./misc/script/release.sh
|
||||
|
||||
dist:
|
||||
|
@ -2,7 +2,7 @@
|
||||
{{define "header_buttons"}}
|
||||
<button
|
||||
data-controller="restful"
|
||||
data-restful-endpoint="/emails"
|
||||
data-restful-endpoint="{{ .BaseURL }}/emails"
|
||||
data-restful-method="DELETE"
|
||||
class="button is-danger">
|
||||
🗑️ Clear
|
||||
|
7
go.sum
7
go.sum
@ -51,7 +51,6 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
|
||||
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/emersion/go-sasl v0.0.0-20190817083125-240c8404624e h1:ba7YsgX5OV8FjGi5ZWml8Jng6oBrJAb3ahqWMJ5Ce8Q=
|
||||
github.com/emersion/go-sasl v0.0.0-20190817083125-240c8404624e/go.mod h1:G/dpzLu16WtQpBfQ/z3LYiYJn3ZhKSGWn83fyoyQe/k=
|
||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ=
|
||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
|
||||
@ -104,9 +103,7 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
|
||||
github.com/gorilla/csrf v1.6.0/go.mod h1:7tSf8kmjNYr7IWDCYhd3U8Ck34iQ/Yw5CJu7bAkHEGI=
|
||||
github.com/gorilla/handlers v1.4.1/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ=
|
||||
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
@ -159,7 +156,6 @@ github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02n
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
@ -211,7 +207,6 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191105084925-a882066a44e0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
@ -235,7 +230,6 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -293,7 +287,6 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
|
||||
google.golang.org/grpc v1.25.1 h1:wdKvqQk7IttEw92GoRyKG2IDrUIpgpj6H6m81yfeMW0=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
195
internal/query/filter_emails_test.go
Normal file
195
internal/query/filter_emails_test.go
Normal file
@ -0,0 +1,195 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"net/mail"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"forge.cadoles.com/wpetit/fake-smtp/internal/model"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type emailMatcherTestCase struct {
|
||||
Name string
|
||||
Search *InboxSearch
|
||||
Email *model.Email
|
||||
Matcher emailMatcherFunc
|
||||
Expect bool
|
||||
}
|
||||
|
||||
func TestEmailMatcher(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
johnDoeAddr, err := mail.ParseAddress("john.doe@test.local")
|
||||
if err != nil {
|
||||
t.Fatal(errors.WithStack(err))
|
||||
}
|
||||
|
||||
adaLovelaceAddr, err := mail.ParseAddress("ada.lovelace@test.local")
|
||||
if err != nil {
|
||||
t.Fatal(errors.WithStack(err))
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
|
||||
testCases := []emailMatcherTestCase{
|
||||
{
|
||||
Name: "Simple matching header",
|
||||
Email: &model.Email{
|
||||
Headers: map[string][]string{
|
||||
"X-Swift-To": {johnDoeAddr.Address},
|
||||
},
|
||||
},
|
||||
Search: &InboxSearch{
|
||||
Headers: map[string]string{
|
||||
"X-Swift-To": johnDoeAddr.Address,
|
||||
},
|
||||
},
|
||||
Matcher: matchHeaders,
|
||||
Expect: true,
|
||||
},
|
||||
{
|
||||
Name: "Multiple matching header",
|
||||
Email: &model.Email{
|
||||
Headers: map[string][]string{
|
||||
"X-Swift-To": {johnDoeAddr.Address},
|
||||
"Content-Type": {"multipart/alternative; boundary=\"_=_swift_1645181013_7b80ab8ab386ba4fcaff4f6f79593adb_=_\""},
|
||||
},
|
||||
},
|
||||
Search: &InboxSearch{
|
||||
Headers: map[string]string{
|
||||
"X-Swift-To": johnDoeAddr.Address,
|
||||
"Content-Type": "multipart/alternative",
|
||||
},
|
||||
},
|
||||
Matcher: matchHeaders,
|
||||
Expect: true,
|
||||
},
|
||||
{
|
||||
Name: "Simple non matching header",
|
||||
Email: &model.Email{
|
||||
Headers: map[string][]string{
|
||||
"X-Swift-To": {johnDoeAddr.Address},
|
||||
},
|
||||
},
|
||||
Search: &InboxSearch{
|
||||
Headers: map[string]string{
|
||||
"X-Swift-To": adaLovelaceAddr.Address,
|
||||
},
|
||||
},
|
||||
Matcher: matchHeaders,
|
||||
Expect: false,
|
||||
},
|
||||
{
|
||||
Name: "Multiple non matching headers",
|
||||
Email: &model.Email{
|
||||
Headers: map[string][]string{
|
||||
"X-Swift-To": {johnDoeAddr.Address},
|
||||
"Content-Type": {"foo/bar"},
|
||||
},
|
||||
},
|
||||
Search: &InboxSearch{
|
||||
Headers: map[string]string{
|
||||
"X-Swift-To": johnDoeAddr.Address,
|
||||
"Content-Type": "multipart/alternative",
|
||||
},
|
||||
},
|
||||
Matcher: matchHeaders,
|
||||
Expect: false,
|
||||
},
|
||||
{
|
||||
Name: "Simple to",
|
||||
Email: &model.Email{
|
||||
To: []*mail.Address{johnDoeAddr},
|
||||
},
|
||||
Search: &InboxSearch{
|
||||
To: johnDoeAddr.Address,
|
||||
},
|
||||
Matcher: matchTo,
|
||||
Expect: true,
|
||||
},
|
||||
{
|
||||
Name: "Simple from",
|
||||
Email: &model.Email{
|
||||
From: []*mail.Address{johnDoeAddr},
|
||||
},
|
||||
Search: &InboxSearch{
|
||||
From: johnDoeAddr.Address,
|
||||
},
|
||||
Matcher: matchFrom,
|
||||
Expect: true,
|
||||
},
|
||||
{
|
||||
Name: "Simple after",
|
||||
Email: &model.Email{
|
||||
SentAt: now,
|
||||
},
|
||||
Search: &InboxSearch{
|
||||
After: now.Add(-5 * time.Second),
|
||||
},
|
||||
Matcher: matchAfter,
|
||||
Expect: true,
|
||||
},
|
||||
{
|
||||
Name: "Simple before",
|
||||
Email: &model.Email{
|
||||
SentAt: now,
|
||||
},
|
||||
Search: &InboxSearch{
|
||||
Before: now.Add(5 * time.Second),
|
||||
},
|
||||
Matcher: matchBefore,
|
||||
Expect: true,
|
||||
},
|
||||
{
|
||||
Name: "Matching composite",
|
||||
Email: &model.Email{
|
||||
SentAt: now,
|
||||
Headers: map[string][]string{
|
||||
"X-Swift-To": {johnDoeAddr.Address},
|
||||
"Content-Type": {"multipart/alternative; boundary=\"_=_swift_1645181013_7b80ab8ab386ba4fcaff4f6f79593adb_=_\""},
|
||||
},
|
||||
},
|
||||
Search: &InboxSearch{
|
||||
Before: now.Add(5 * time.Second),
|
||||
Headers: map[string]string{
|
||||
"X-Swift-To": johnDoeAddr.Address,
|
||||
"Content-Type": "multipart/alternative",
|
||||
},
|
||||
},
|
||||
Matcher: and(matchBefore, matchHeaders),
|
||||
Expect: true,
|
||||
},
|
||||
{
|
||||
Name: "Non matching composite",
|
||||
Email: &model.Email{
|
||||
SentAt: now,
|
||||
Headers: map[string][]string{
|
||||
"X-Swift-To": {johnDoeAddr.Address},
|
||||
"Content-Type": {"multipart/alternative; boundary=\"_=_swift_1645181013_7b80ab8ab386ba4fcaff4f6f79593adb_=_\""},
|
||||
},
|
||||
},
|
||||
Search: &InboxSearch{
|
||||
Before: now.Add(5 * time.Second),
|
||||
Headers: map[string]string{
|
||||
"X-Swift-To": adaLovelaceAddr.Address,
|
||||
"Content-Type": "multipart/alternative",
|
||||
},
|
||||
},
|
||||
Matcher: and(matchBefore, matchHeaders),
|
||||
Expect: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
func(tc emailMatcherTestCase) {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if e, g := tc.Expect, tc.Matcher(tc.Email, tc.Search); e != g {
|
||||
t.Errorf("'%s': expected '%v', got '%v'", tc.Name, e, g)
|
||||
}
|
||||
})
|
||||
}(tc)
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ type InboxSearch struct {
|
||||
From string
|
||||
Body string
|
||||
Subject string
|
||||
Headers map[string]string
|
||||
After time.Time
|
||||
Before time.Time
|
||||
}
|
||||
@ -104,55 +105,135 @@ func HandleGetInbox(ctx context.Context, qry cqrs.Query) (interface{}, error) {
|
||||
return &InboxData{emails}, nil
|
||||
}
|
||||
|
||||
filtered := make([]*model.Email, 0, len(emails))
|
||||
|
||||
for _, eml := range emails {
|
||||
match := true
|
||||
|
||||
if req.Search.To != "" {
|
||||
found := false
|
||||
|
||||
for _, addr := range eml.To {
|
||||
if strings.Contains(addr.Name, req.Search.To) || strings.Contains(addr.Address, req.Search.To) {
|
||||
found = true
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
match = false
|
||||
}
|
||||
}
|
||||
|
||||
if req.Search.From != "" {
|
||||
found := false
|
||||
|
||||
for _, addr := range eml.From {
|
||||
if strings.Contains(addr.Name, req.Search.From) || strings.Contains(addr.Address, req.Search.From) {
|
||||
found = true
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
match = false
|
||||
}
|
||||
}
|
||||
|
||||
if !req.Search.After.IsZero() && !eml.SentAt.After(req.Search.After) {
|
||||
match = false
|
||||
}
|
||||
|
||||
if !req.Search.Before.IsZero() && !eml.SentAt.Before(req.Search.Before) {
|
||||
match = false
|
||||
}
|
||||
|
||||
if match {
|
||||
filtered = append(filtered, eml)
|
||||
}
|
||||
}
|
||||
filtered := filterEmails(emails, req.Search)
|
||||
|
||||
return &InboxData{filtered}, nil
|
||||
}
|
||||
|
||||
var matchers = []emailMatcherFunc{
|
||||
matchTo,
|
||||
matchFrom,
|
||||
matchBefore,
|
||||
matchAfter,
|
||||
matchHeaders,
|
||||
}
|
||||
|
||||
type emailMatcherFunc func(*model.Email, *InboxSearch) bool
|
||||
|
||||
func matchTo(eml *model.Email, search *InboxSearch) bool {
|
||||
if search.To == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
found := false
|
||||
|
||||
for _, addr := range eml.To {
|
||||
if strings.Contains(addr.Name, search.To) || strings.Contains(addr.Address, search.To) {
|
||||
found = true
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return found
|
||||
}
|
||||
|
||||
func matchFrom(eml *model.Email, search *InboxSearch) bool {
|
||||
if search.From == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
found := false
|
||||
|
||||
for _, addr := range eml.From {
|
||||
if strings.Contains(addr.Name, search.From) || strings.Contains(addr.Address, search.From) {
|
||||
found = true
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return found
|
||||
}
|
||||
|
||||
func matchAfter(eml *model.Email, search *InboxSearch) bool {
|
||||
if search.After.IsZero() {
|
||||
return true
|
||||
}
|
||||
|
||||
return eml.SentAt.After(search.After)
|
||||
}
|
||||
|
||||
func matchBefore(eml *model.Email, search *InboxSearch) bool {
|
||||
if search.Before.IsZero() {
|
||||
return true
|
||||
}
|
||||
|
||||
return eml.SentAt.Before(search.Before)
|
||||
}
|
||||
|
||||
func matchHeaders(eml *model.Email, search *InboxSearch) bool {
|
||||
if eml.Headers == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
matches := true
|
||||
|
||||
for searchKey, searchValue := range search.Headers {
|
||||
for headerKey, headerValues := range eml.Headers {
|
||||
if searchKey != headerKey {
|
||||
continue
|
||||
}
|
||||
|
||||
matchesHeader := true
|
||||
|
||||
for _, hv := range headerValues {
|
||||
if !strings.Contains(hv, searchValue) {
|
||||
matchesHeader = false
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !matchesHeader {
|
||||
matches = false
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !matches {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return matches
|
||||
}
|
||||
|
||||
func and(matchers ...emailMatcherFunc) emailMatcherFunc {
|
||||
return func(eml *model.Email, search *InboxSearch) bool {
|
||||
for _, match := range matchers {
|
||||
if !match(eml, search) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func filterEmails(emails []*model.Email, search *InboxSearch) []*model.Email {
|
||||
filtered := make([]*model.Email, 0)
|
||||
|
||||
match := and(matchers...)
|
||||
|
||||
for _, eml := range emails {
|
||||
if !match(eml, search) {
|
||||
continue
|
||||
}
|
||||
|
||||
filtered = append(filtered, eml)
|
||||
}
|
||||
|
||||
return filtered
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
@ -75,6 +76,16 @@ func createInboxQueryFromRequest(r *http.Request) (*query.GetInboxRequest, error
|
||||
}
|
||||
}
|
||||
|
||||
var headers map[string]string
|
||||
|
||||
rawHeaders := r.URL.Query().Get("headers")
|
||||
if rawHeaders != "" {
|
||||
headers = make(map[string]string)
|
||||
if err := json.Unmarshal([]byte(rawHeaders), &headers); err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
}
|
||||
|
||||
search := &query.InboxSearch{}
|
||||
if to != "" {
|
||||
search.To = to
|
||||
@ -96,6 +107,10 @@ func createInboxQueryFromRequest(r *http.Request) (*query.GetInboxRequest, error
|
||||
search.Before = before
|
||||
}
|
||||
|
||||
if rawHeaders != "" {
|
||||
search.Headers = headers
|
||||
}
|
||||
|
||||
inboxRequest := &query.GetInboxRequest{
|
||||
OrderBy: orderBy,
|
||||
Reverse: reverse == "y",
|
||||
|
5
misc/api.http
Normal file
5
misc/api.http
Normal file
@ -0,0 +1,5 @@
|
||||
@baseURL = http://localhost:8080
|
||||
|
||||
### Filter emails via headers
|
||||
|
||||
GET {{ baseURL }}/api/v1/emails?headers={"Mime-Version":"1.0"}
|
@ -1,4 +1,4 @@
|
||||
FROM golang:1.15 AS build
|
||||
FROM golang:1.19 AS build
|
||||
|
||||
ARG HTTP_PROXY=
|
||||
ARG HTTPS_PROXY=
|
||||
@ -7,20 +7,15 @@ ARG https_proxy=
|
||||
|
||||
RUN apt-get update && apt-get install -y build-essential git bash curl
|
||||
|
||||
RUN curl -sL https://deb.nodesource.com/setup_12.x | bash - \
|
||||
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - \
|
||||
&& apt-get install -y nodejs
|
||||
|
||||
COPY . /src
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
RUN cp -f misc/docker/config-patch.yml misc/release/config-patch.yml
|
||||
|
||||
RUN go get github.com/krishicks/yaml-patch/cmd/yaml-patch
|
||||
|
||||
RUN npm install \
|
||||
&& make vendor \
|
||||
&& echo "---" > ./misc/release/config-patch.yml \
|
||||
RUN cp -f misc/docker/config-patch.txt misc/release/config-patch.txt \
|
||||
&& npm install \
|
||||
&& make ARCH_TARGETS=amd64 release
|
||||
|
||||
FROM busybox
|
||||
@ -31,4 +26,6 @@ WORKDIR /app
|
||||
|
||||
RUN mkdir -p /app
|
||||
|
||||
EXPOSE 8080 2525
|
||||
|
||||
CMD ["bin/fake-smtp", "--config", "config.yml"]
|
1
misc/docker/config-patch.txt
Normal file
1
misc/docker/config-patch.txt
Normal file
@ -0,0 +1 @@
|
||||
.smtp.debug = false
|
@ -1,4 +0,0 @@
|
||||
---
|
||||
- op: replace
|
||||
path: /smtp/debug
|
||||
value: false
|
3
misc/release/config-patch.txt
Normal file
3
misc/release/config-patch.txt
Normal file
@ -0,0 +1,3 @@
|
||||
.data.path = "/var/lib/fake-smtp/data.db"
|
||||
.smtp.address = "127.0.0.1:2525"
|
||||
.smtp.debug = false
|
@ -1,10 +0,0 @@
|
||||
---
|
||||
- op: replace
|
||||
path: /data/path
|
||||
value: /var/lib/fake-smtp/data.db
|
||||
- op: replace
|
||||
path: /smtp/address
|
||||
value: 127.0.0.1:2525
|
||||
- op: replace
|
||||
path: /smtp/debug
|
||||
value: false
|
@ -73,13 +73,17 @@ function dump_default_conf {
|
||||
local command=$1
|
||||
local os=$2
|
||||
local arch=$3
|
||||
local tmp_conf=$(mktemp)
|
||||
local patched_conf=$(mktemp)
|
||||
|
||||
go run "$PROJECT_DIR/cmd/$command" -dump-config > "$tmp_conf"
|
||||
cat "$tmp_conf" | yaml-patch -o misc/release/config-patch.yml > "$patched_conf"
|
||||
go run "$PROJECT_DIR/cmd/$command" -dump-config > "$patched_conf"
|
||||
|
||||
while IFS= read -r yq_cmd; do
|
||||
echo "patching configuration with '$yq_cmd'..."
|
||||
tools/yq/bin/yq -i "$yq_cmd" "$patched_conf"
|
||||
done < misc/release/config-patch.txt
|
||||
|
||||
copy "$command" $os $arch "$patched_conf" "config.yml"
|
||||
rm -f "$tmp_conf" "$patched_conf"
|
||||
rm -f "$patched_conf"
|
||||
}
|
||||
|
||||
function compress {
|
||||
|
Reference in New Issue
Block a user