Skip to content

Commit a86b0f4

Browse files
feat: add SMTP auth
1 parent 68ccd5f commit a86b0f4

18 files changed

+187
-95
lines changed

README.md

+8
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,20 @@ http:
8383
host: ""
8484
port: 8080
8585

86+
# Authentication is disabled if both username and password are empty
87+
username: ""
88+
password: ""
89+
8690
# SMTP server
8791
smtp:
8892
disable: false # (false, true)
8993
host: ""
9094
port: 1025
9195

96+
# Authentication is disabled if both username and password are empty
97+
username: ""
98+
password: ""
99+
92100
# Endpoints for envelopes
93101
endpoints:
94102
# Full example

config/config.go

+26-8
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ type Config struct {
2828
Endpoints []endpoints.Endpoint
2929
Rules []rules.Rule
3030
RuleEndpoints map[string][]string
31-
RetentionPolicy models.RetentionPolicy
31+
Config *models.Config
3232
}
3333

3434
func Parse(raw Raw) (Config, error) {
@@ -128,6 +128,16 @@ func Parse(raw Raw) (Config, error) {
128128
MinAge: 5 * time.Minute,
129129
}
130130

131+
authSMTP := models.Auth{
132+
Username: raw.SMTP.Username,
133+
Password: raw.SMTP.Password,
134+
}
135+
136+
authHTTP := models.Auth{
137+
Username: raw.HTTP.Username,
138+
Password: raw.HTTP.Password,
139+
}
140+
131141
return Config{
132142
DatabasePath: databasePath,
133143
AttachmentsDirectory: attachmentsDirectory,
@@ -140,7 +150,11 @@ func Parse(raw Raw) (Config, error) {
140150
Endpoints: ends,
141151
Rules: rrules,
142152
RuleEndpoints: rulesToEndpoints,
143-
RetentionPolicy: retentionPolicy,
153+
Config: &models.Config{
154+
RetentionPolicy: retentionPolicy,
155+
AuthSMTP: authSMTP,
156+
AuthHTTP: authHTTP,
157+
},
144158
}, nil
145159
}
146160

@@ -153,14 +167,18 @@ type Raw struct {
153167
AttachmentSize *string `name:"attachment_size"`
154168
} `embed:"" prefix:"retention-"`
155169
HTTP struct {
156-
Disable bool
157-
Host string
158-
Port int `default:"8080"`
170+
Disable bool
171+
Host string
172+
Port int `default:"8080"`
173+
Username string
174+
Password string
159175
} `embed:"" prefix:"http-"`
160176
SMTP struct {
161-
Disable bool
162-
Host string
163-
Port int `default:"1025"`
177+
Disable bool
178+
Host string
179+
Port int `default:"1025"`
180+
Username string
181+
Password string
164182
} `embed:"" prefix:"smtp-"`
165183
Endpoints map[string]RawEndpoint
166184
Rules map[string]RawRule

internal/core/actor.go

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package core
2+
3+
type Actor int
4+
5+
const (
6+
ActorAnonymous Actor = iota
7+
ActorUser
8+
ActorSystem
9+
)

internal/core/app.go

+31-7
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,43 @@
11
package core
22

33
import (
4+
"context"
5+
6+
"github.com/ItsNotGoodName/smtpbridge/internal/models"
47
"github.com/uptrace/bun"
58
)
69

710
type App struct {
8-
Bus *Bus
9-
DB *bun.DB
10-
File FileStore
11+
Bus *Bus
12+
DB *bun.DB
13+
File FileStore
14+
Config *models.Config
1115
}
1216

13-
func NewApp(bunDB *bun.DB, fileStore FileStore) App {
17+
func NewApp(config *models.Config, bunDB *bun.DB, fileStore FileStore) App {
1418
return App{
15-
Bus: NewBus(),
16-
DB: bunDB,
17-
File: fileStore,
19+
Config: config,
20+
Bus: NewBus(),
21+
DB: bunDB,
22+
File: fileStore,
23+
}
24+
}
25+
26+
func (a App) newContext(ctx context.Context, actor Actor) Context {
27+
return Context{
28+
Bus: a.Bus,
29+
DB: a.DB,
30+
File: a.File,
31+
Config: a.Config,
32+
ctx: ctx,
33+
Actor: actor,
1834
}
1935
}
36+
37+
func (a App) Context(ctx context.Context) Context {
38+
return a.newContext(ctx, ActorAnonymous)
39+
}
40+
41+
func (a App) SystemContext(ctx context.Context) Context {
42+
return a.newContext(ctx, ActorSystem)
43+
}

internal/core/context.go

+7-23
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,17 @@ package core
33
import (
44
"context"
55

6+
"github.com/ItsNotGoodName/smtpbridge/internal/models"
67
"github.com/uptrace/bun"
78
)
89

910
type Context struct {
10-
Actor Actor
11-
Bus *Bus
12-
DB *bun.DB
13-
File FileStore
14-
ctx context.Context
15-
}
16-
17-
func (a App) Context(ctx context.Context) Context {
18-
return Context{
19-
Actor: ActorAnon,
20-
Bus: a.Bus,
21-
DB: a.DB,
22-
File: a.File,
23-
ctx: ctx,
24-
}
11+
Actor Actor
12+
Bus *Bus
13+
DB *bun.DB
14+
File FileStore
15+
Config *models.Config
16+
ctx context.Context
2517
}
2618

2719
func (c Context) WithActor(actor Actor) Context {
@@ -32,11 +24,3 @@ func (c Context) WithActor(actor Actor) Context {
3224
func (c Context) Context() context.Context {
3325
return c.ctx
3426
}
35-
36-
type Actor int
37-
38-
const (
39-
ActorAnon Actor = iota
40-
ActorUser
41-
ActorSystem
42-
)

internal/models/auth.go

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package models
2+
3+
type Auth struct {
4+
Username string
5+
Password string
6+
}

internal/models/config.go

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package models
2+
3+
type Config struct {
4+
RetentionPolicy RetentionPolicy
5+
AuthSMTP Auth
6+
AuthHTTP Auth
7+
}

internal/procs/auth.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package procs
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/ItsNotGoodName/smtpbridge/internal/core"
8+
)
9+
10+
var ErrorLogin = fmt.Errorf("login error")
11+
12+
func HTTPLogin(cc core.Context, username, password string) error {
13+
if cc.Config.AuthHTTP.Username == "" && cc.Config.AuthHTTP.Password == "" {
14+
return nil
15+
}
16+
17+
if strings.ToLower(username) != cc.Config.AuthHTTP.Username {
18+
return ErrorLogin
19+
}
20+
21+
if strings.ToLower(password) != cc.Config.AuthHTTP.Password {
22+
return ErrorLogin
23+
}
24+
25+
return nil
26+
}
27+
28+
func SMTPLogin(cc core.Context, username, password string) error {
29+
if cc.Config.AuthSMTP.Username == "" && cc.Config.AuthHTTP.Password == "" {
30+
return nil
31+
}
32+
33+
if strings.ToLower(username) != cc.Config.AuthSMTP.Username {
34+
return ErrorLogin
35+
}
36+
37+
if strings.ToLower(password) != cc.Config.AuthSMTP.Password {
38+
return ErrorLogin
39+
}
40+
41+
return nil
42+
}

internal/procs/database.go

-10
This file was deleted.

internal/procs/mailman.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
func MailmanBackground(ctx context.Context, app core.App) {
1313
evtC := make(chan core.EventEnvelopeCreated, 25)
1414

15-
go mailman(app.Context(ctx), evtC)
15+
go mailman(app.SystemContext(ctx), evtC)
1616

1717
events.OnEnvelopeCreated(app, func(cc core.Context, evt core.EventEnvelopeCreated) {
1818
select {

internal/procs/internal.go internal/procs/procs.go

+9
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,18 @@ import (
66
"github.com/ItsNotGoodName/smtpbridge/internal/core"
77
"github.com/ItsNotGoodName/smtpbridge/internal/db"
88
"github.com/ItsNotGoodName/smtpbridge/internal/endpoints"
9+
"github.com/ItsNotGoodName/smtpbridge/internal/models"
910
"github.com/ItsNotGoodName/smtpbridge/internal/rules"
1011
)
1112

13+
func DatabaseVacuum(cc core.Context) error {
14+
return db.Vacuum(cc)
15+
}
16+
17+
func RetentionPolicyGet(cc core.Context) models.RetentionPolicy {
18+
return cc.Config.RetentionPolicy
19+
}
20+
1221
func InternalSync(cc core.Context, eendpoints []endpoints.Endpoint, rrules []rules.Rule, ruleToEndpoints map[string][]string) error {
1322
updatedAt := time.Now()
1423

internal/procs/trimmer.go

+7-8
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ func TrimStart(cc core.Context) error {
2727
}
2828
}
2929

30-
func TrimmerBackground(ctx context.Context, app core.App, policy models.RetentionPolicy) {
30+
func TrimmerBackground(ctx context.Context, app core.App) {
3131
envDeletedC := make(chan core.EventEnvelopeDeleted, 1)
3232
envCreatedC := make(chan core.EventEnvelopeCreated, 1)
3333
evtTrimStart := make(chan core.EventTrimStart, 1)
3434

35-
go trimmer(app.Context(ctx), policy, envCreatedC, envDeletedC, evtTrimStart)
35+
go trimmer(app.SystemContext(ctx), envCreatedC, envDeletedC, evtTrimStart)
3636

3737
events.OnEnvelopeCreated(app, func(cc core.Context, evt core.EventEnvelopeCreated) {
3838
select {
@@ -73,7 +73,6 @@ func TrimmerBackground(ctx context.Context, app core.App, policy models.Retentio
7373

7474
func trimmer(
7575
cc core.Context,
76-
policy models.RetentionPolicy,
7776
envCreatedC <-chan core.EventEnvelopeCreated,
7877
envDeletedC <-chan core.EventEnvelopeDeleted,
7978
evtTrimStart <-chan core.EventTrimStart,
@@ -82,7 +81,7 @@ func trimmer(
8281
ticker := time.NewTicker(30 * time.Minute)
8382

8483
clean := func() {
85-
trimmerDeleteByAge(cc, policy)
84+
trimmerDeleteByAge(cc, cc.Config.RetentionPolicy)
8685
trimmerDeleteOrphanAttachments(cc)
8786

8887
storage, err := StorageGet(cc)
@@ -91,8 +90,8 @@ func trimmer(
9190
return
9291
}
9392

94-
trimmerDeleteByEnvelopeCount(cc, policy, storage)
95-
trimmerDeleteByAttachmentSize(cc, policy, storage)
93+
trimmerDeleteByEnvelopeCount(cc, cc.Config.RetentionPolicy, storage)
94+
trimmerDeleteByAttachmentSize(cc, cc.Config.RetentionPolicy, storage)
9695
}
9796
clean()
9897

@@ -107,8 +106,8 @@ func trimmer(
107106
continue
108107
}
109108

110-
trimmerDeleteByEnvelopeCount(cc, policy, storage)
111-
trimmerDeleteByAttachmentSize(cc, policy, storage)
109+
trimmerDeleteByEnvelopeCount(cc, cc.Config.RetentionPolicy, storage)
110+
trimmerDeleteByAttachmentSize(cc, cc.Config.RetentionPolicy, storage)
112111
case <-envDeletedC:
113112
trimmerDeleteOrphanAttachments(cc)
114113
case <-ticker.C:

internal/procs/vacuum.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import (
88
"github.com/rs/zerolog/log"
99
)
1010

11-
func VacuumBackground(ctx context.Context, app core.App) {
12-
go vacuum(app.Context(ctx))
11+
func VacuumerBackground(ctx context.Context, app core.App) {
12+
go vacuum(app.SystemContext(ctx))
1313
}
1414

1515
func vacuum(cc core.Context) {

main.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,14 @@ func run(ctx context.Context, shutdown context.CancelFunc, cli config.CLI) <-cha
5656
fileStore := core.NewFileStore(cfg.AttachmentsDirectory)
5757

5858
// App
59-
app := core.NewApp(bunDB, fileStore)
60-
if err := procs.InternalSync(app.Context(ctx), cfg.Endpoints, cfg.Rules, cfg.RuleEndpoints); err != nil {
59+
app := core.NewApp(cfg.Config, bunDB, fileStore)
60+
if err := procs.InternalSync(app.SystemContext(ctx), cfg.Endpoints, cfg.Rules, cfg.RuleEndpoints); err != nil {
6161
log.Fatal().Err(err).Msg("Failed to sync app from config")
6262
}
6363

6464
procs.MailmanBackground(ctx, app)
65-
procs.TrimmerBackground(ctx, app, cfg.RetentionPolicy)
66-
procs.VacuumBackground(ctx, app)
65+
procs.TrimmerBackground(ctx, app)
66+
procs.VacuumerBackground(ctx, app)
6767

6868
var backgrounds []background.Background
6969

@@ -75,7 +75,7 @@ func run(ctx context.Context, shutdown context.CancelFunc, cli config.CLI) <-cha
7575

7676
// HTTP
7777
if !cfg.HTTPDisable {
78-
http := http.New(app, shutdown, cfg.HTTPAddress, cfg.HTTPBodyLimit, cfg.RetentionPolicy)
78+
http := http.New(app, shutdown, cfg.HTTPAddress, cfg.HTTPBodyLimit)
7979
backgrounds = append(backgrounds, http)
8080
}
8181

0 commit comments

Comments
 (0)