mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 17:05:18 +00:00
2a532ede94
#11266 PS: I first attempted a serialization trick by introducing a new `appConfigResponse` and implementing `json.Marshal` to exclude these fields but it was too hacky and hard to maintain moving forward, so I'm bitting the bullet now. Happy to hear other ideas. - [X] Changes file added for user-visible changes in `changes/` or `orbit/changes/`. See [Changes files](https://fleetdm.com/docs/contributing/committing-changes#changes-files) for more information. - ~[ ] Documented any API changes (docs/Using-Fleet/REST-API.md or docs/Contributing/API-for-contributors.md)~ - ~[ ] Documented any permissions changes~ - ~[ ] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements)~ - ~[ ] Added support on fleet's osquery simulator `cmd/osquery-perf` for new osquery data ingestion features.~ - [X] Added/updated tests - [X] Manual QA for all new/changed functionality - ~For Orbit and Fleet Desktop changes:~ - ~[ ] Manual QA must be performed in the three main OSs, macOS, Windows and Linux.~ - ~[ ] Auto-update manual QA, from released version of component to new version (see [tools/tuf/test](../tools/tuf/test/README.md)).~
172 lines
4.8 KiB
Go
172 lines
4.8 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
|
"github.com/fleetdm/fleet/v4/server/mock"
|
|
"github.com/fleetdm/fleet/v4/server/ptr"
|
|
"github.com/fleetdm/fleet/v4/server/test"
|
|
"github.com/stretchr/testify/require"
|
|
"gopkg.in/guregu/null.v3"
|
|
)
|
|
|
|
type notTestFoundError struct{}
|
|
|
|
func (e *notTestFoundError) Error() string {
|
|
return "not found"
|
|
}
|
|
|
|
func (e *notTestFoundError) IsNotFound() bool {
|
|
return true
|
|
}
|
|
|
|
func newTestNotFoundError() *notTestFoundError {
|
|
return ¬TestFoundError{}
|
|
}
|
|
|
|
// Is is implemented so that errors.Is(err, sql.ErrNoRows) returns true for an
|
|
// error of type *notFoundError, without having to wrap sql.ErrNoRows
|
|
// explicitly.
|
|
func (e *notTestFoundError) Is(other error) bool {
|
|
return other == sql.ErrNoRows
|
|
}
|
|
|
|
func TestMailService(t *testing.T) {
|
|
// This mail test requires mailpit running on localhost:1026.
|
|
if _, ok := os.LookupEnv("MAIL_TEST"); !ok {
|
|
t.Skip("Mail tests are disabled")
|
|
}
|
|
|
|
ds := new(mock.Store)
|
|
svc, ctx := newTestService(t, ds, nil, nil, &TestServerOpts{
|
|
UseMailService: true,
|
|
})
|
|
|
|
ds.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) {
|
|
return &fleet.AppConfig{
|
|
SMTPSettings: &fleet.SMTPSettings{
|
|
SMTPEnabled: true,
|
|
SMTPConfigured: true,
|
|
SMTPAuthenticationType: fleet.AuthTypeNameUserNamePassword,
|
|
SMTPAuthenticationMethod: fleet.AuthMethodNamePlain,
|
|
SMTPUserName: "mailpit-username",
|
|
SMTPPassword: "mailpit-password",
|
|
SMTPEnableTLS: true,
|
|
SMTPVerifySSLCerts: true,
|
|
SMTPPort: 1026,
|
|
SMTPServer: "localhost",
|
|
SMTPSenderAddress: "foobar@example.com",
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
ds.UserByEmailFunc = func(ctx context.Context, email string) (*fleet.User, error) {
|
|
return nil, newTestNotFoundError()
|
|
}
|
|
|
|
var invite *fleet.Invite
|
|
ds.NewInviteFunc = func(ctx context.Context, i *fleet.Invite) (*fleet.Invite, error) {
|
|
invite = i
|
|
return invite, nil
|
|
}
|
|
|
|
ds.SaveAppConfigFunc = func(ctx context.Context, info *fleet.AppConfig) error {
|
|
return nil
|
|
}
|
|
|
|
ds.InviteFunc = func(ctx context.Context, id uint) (*fleet.Invite, error) {
|
|
return invite, nil
|
|
}
|
|
|
|
ctx = test.UserContext(ctx, test.UserAdmin)
|
|
|
|
// (1) Modifying the app config `sender_address` field to trigger a test e-mail send.
|
|
_, err := svc.ModifyAppConfig(ctx, []byte(`{
|
|
"org_info": {
|
|
"org_name": "Acme"
|
|
},
|
|
"server_settings": {
|
|
"server_url": "http://someurl"
|
|
},
|
|
"smtp_settings": {
|
|
"enable_smtp": true,
|
|
"configured": true,
|
|
"authentication_type": "authtype_username_password",
|
|
"authentication_method": "authmethod_plain",
|
|
"user_name": "mailpit-username",
|
|
"password": "mailpit-password",
|
|
"enable_ssl_tls": true,
|
|
"verify_ssl_certs": true,
|
|
"port": 1026,
|
|
"server": "127.0.0.1",
|
|
"sender_address": "foobar_updated@example.com"
|
|
}
|
|
}`), fleet.ApplySpecOptions{})
|
|
require.NoError(t, err)
|
|
|
|
getLastMailPitMessage := func() map[string]interface{} {
|
|
resp, err := http.Get("http://localhost:8026/api/v1/messages?limit=1")
|
|
require.NoError(t, err)
|
|
defer resp.Body.Close()
|
|
b, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
var m map[string]interface{}
|
|
err = json.Unmarshal(b, &m)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, m["messages"])
|
|
require.Len(t, m["messages"], 1)
|
|
lm := (m["messages"]).([]interface{})[0]
|
|
require.NotNil(t, lm)
|
|
lastMessage := lm.(map[string]interface{})
|
|
fmt.Printf("%+v\n", lastMessage)
|
|
return lastMessage
|
|
}
|
|
|
|
lastMessage := getLastMailPitMessage()
|
|
require.Equal(t, "Hello from Fleet", lastMessage["Subject"])
|
|
|
|
// (2) Inviting a user should send an e-mail to join.
|
|
_, err = svc.InviteNewUser(ctx, fleet.InvitePayload{
|
|
Email: ptr.String("foobar_recipient@example.com"),
|
|
Name: ptr.String("Foobar"),
|
|
GlobalRole: null.NewString("observer", true),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
lastMessage = getLastMailPitMessage()
|
|
require.Equal(t, "You are Invited to Fleet", lastMessage["Subject"])
|
|
|
|
ds.UserByIDFunc = func(ctx context.Context, id uint) (*fleet.User, error) {
|
|
if id == 1 {
|
|
return test.UserAdmin, nil
|
|
}
|
|
return nil, newNotFoundError()
|
|
}
|
|
ds.InviteByEmailFunc = func(ctx context.Context, email string) (*fleet.Invite, error) {
|
|
return nil, newTestNotFoundError()
|
|
}
|
|
ds.PendingEmailChangeFunc = func(ctx context.Context, userID uint, newEmail, token string) error {
|
|
return nil
|
|
}
|
|
ds.SaveUserFunc = func(ctx context.Context, user *fleet.User) error {
|
|
return nil
|
|
}
|
|
|
|
// (3) Changing e-mail address should send an e-mail for confirmation.
|
|
_, err = svc.ModifyUser(ctx, 1, fleet.UserPayload{
|
|
Email: ptr.String("useradmin_2@example.com"),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
lastMessage = getLastMailPitMessage()
|
|
require.Equal(t, "Confirm Fleet Email Change", lastMessage["Subject"])
|
|
}
|