diff --git a/system/cli/settings.go b/system/cli/settings.go index 83b0c8187..0de84abaa 100644 --- a/system/cli/settings.go +++ b/system/cli/settings.go @@ -11,7 +11,7 @@ import ( "github.com/crusttech/crust/internal/rand" "github.com/crusttech/crust/internal/settings" - service2 "github.com/crusttech/crust/system/internal/service" + systemService "github.com/crusttech/crust/system/internal/service" ) func settingsCmd(ctx context.Context, setSvc settings.Service) *cobra.Command { @@ -24,7 +24,7 @@ func settingsCmd(ctx context.Context, setSvc settings.Service) *cobra.Command { Use: "auto-configure", Short: "Run autoconfiguration", Run: func(cmd *cobra.Command, args []string) { - service2.DefaultSettings.LoadAuthSettings() + systemService.DefaultSettings.LoadAuthSettings() settingsAutoConfigure( setSvc, @@ -119,15 +119,11 @@ func settingsAutoConfigure(setSvc settings.Service, systemApiUrl, frontendUrl, f err error ) - if existing, err := setSvc.Get("name", 0); err != nil { - return - } else if setFn, ok := value.(func() interface{}); ok { - if existing == nil { - // No existing value found - if value = setFn(); value == nil { - // setFn returned nil, skip everything.. - return - } + if setFn, ok := value.(func() interface{}); ok { + // No existing value found + if value = setFn(); value == nil { + // setFn returned nil, skip everything.. + return } } @@ -148,7 +144,7 @@ func settingsAutoConfigure(setSvc settings.Service, systemApiUrl, frontendUrl, f } setIfMissing := func(name string, value interface{}) { - if existing, err := setSvc.Get(name, 0); err == nil && existing != nil { + if existing, err := setSvc.Get(name, 0); err == nil && existing == nil { set(name, value) } } @@ -192,21 +188,25 @@ func settingsAutoConfigure(setSvc settings.Service, systemApiUrl, frontendUrl, f }) setIfMissing("auth.frontend.url.email-confirmation", func() interface{} { - return frontendUrl + "/auth/email-confirmation?token=" + return frontendUrl + "/auth/confirm-email?token=" }) } - if len(fromAddress) > 0 { - setIfMissing("auth.frontend.url.email-confirmation", func() interface{} { + // Auth email (password reset, email confirmation) + setIfMissing("auth.frontend.url.email-confirmation", func() interface{} { + if len(fromAddress) > 0 { return fromAddress - }) - } + } + return "change-me@local.crust.tech" + }) - if len(fromName) > 0 { - setIfMissing("auth.frontend.url.email-confirmation", func() interface{} { + setIfMissing("auth.mail.from-name", func() interface{} { + if len(fromName) > 0 { return fromName - }) - } + } + + return "Crust" + }) // No external providers preconfigured, so disable setIfMissing("auth.external.enabled", false) @@ -215,10 +215,10 @@ func settingsAutoConfigure(setSvc settings.Service, systemApiUrl, frontendUrl, f setIfMissing("auth.internal.enabled", true) // Enable user creation - setIfMissing("auth.sign-up.enabled", true) + setIfMissing("auth.internal.signup.enabled", true) // No need to confirm email - setIfMissing("sign-up-email-confirmation-required.enabled", false) + setIfMissing("auth.internal.signup-email-confirmation-required", false) // We need password reset setIfMissing("auth.internal.password-reset.enabled", true) diff --git a/system/internal/auth/external/goth.go b/system/internal/auth/external/goth.go index 056db8d2b..d500a2213 100644 --- a/system/internal/auth/external/goth.go +++ b/system/internal/auth/external/goth.go @@ -22,7 +22,7 @@ const ( func setupGoth(eas *externalAuthSettings) { if eas == nil || !eas.enabled { - log.Printf("external authentication disabled (%v)", eas) + log.Printf("external authentication disabled") return } diff --git a/system/internal/repository/user.go b/system/internal/repository/user.go index b603116a3..82c231b78 100644 --- a/system/internal/repository/user.go +++ b/system/internal/repository/user.go @@ -42,7 +42,7 @@ type ( const ( sqlUserColumns = "id, email, username, name, handle, " + - "meta, rel_organisation, " + + "meta, rel_organisation, email_confirmed, " + "created_at, updated_at, suspended_at, deleted_at" sqlUserScope = "suspended_at IS NULL AND deleted_at IS NULL" sqlUserSelect = "SELECT " + sqlUserColumns + " FROM %s WHERE " + sqlUserScope diff --git a/system/internal/service/auth.go b/system/internal/service/auth.go index 04dba3648..817646055 100644 --- a/system/internal/service/auth.go +++ b/system/internal/service/auth.go @@ -8,7 +8,6 @@ import ( "strconv" "time" - "github.com/davecgh/go-spew/spew" "github.com/markbates/goth" "github.com/pkg/errors" "golang.org/x/crypto/bcrypt" @@ -239,7 +238,7 @@ func (svc auth) InternalSignUp(input *types.User, password string) (u *types.Use } if !svc.settings.internalSignUpEnabled { - return nil, errors.New("internal sign-up disabled") + return nil, errors.New("internal signup disabled") } if input == nil { @@ -265,8 +264,8 @@ func (svc auth) InternalSignUp(input *types.User, password string) (u *types.Use return err } - if !u.EmailConfirmed { - err = svc.sendEmailAddressConfirmationToken(u) + if !existing.EmailConfirmed { + err = svc.sendEmailAddressConfirmationToken(existing) if err != nil { return err } @@ -295,7 +294,8 @@ func (svc auth) InternalSignUp(input *types.User, password string) (u *types.Use return errors.New("could not check existing emails") } - new := &types.User{ + // Whitelisted user data to copy + u, err = svc.users.Create(&types.User{ Email: input.Email, Name: input.Name, Username: input.Username, @@ -303,10 +303,7 @@ func (svc auth) InternalSignUp(input *types.User, password string) (u *types.Use // Do we need confirmed email? EmailConfirmed: !svc.settings.internalSignUpEmailConfirmationRequired, - } - - // Whitelisted user data to copy - u, err = svc.users.Create(new) + }) if err != nil { return errors.Wrap(err, "could not create user") @@ -326,7 +323,7 @@ func (svc auth) InternalSignUp(input *types.User, password string) (u *types.Use } if !u.EmailConfirmed { - err = svc.sendEmailAddressConfirmationToken(new) + err = svc.sendEmailAddressConfirmationToken(u) if err != nil { return err } @@ -592,7 +589,7 @@ func (svc auth) sendEmailAddressConfirmationToken(u *types.User) (err error) { log.Printf("email address validation token generated: %q", token) - url = token + url = svc.settings.frontendUrlEmailConfirmation + token err = svc.notifications.EmailConfirmation(notificationLang, u.Email, url) if err != nil { @@ -635,8 +632,8 @@ func (svc auth) sendPasswordResetToken(u *types.User) (err error) { log.Printf("password reset token generated: %q", token) - url = token - spew.Dump(notificationLang, u.Email, url) + url = svc.settings.frontendUrlPasswordReset + token + err = svc.notifications.PasswordReset(notificationLang, u.Email, url) if err != nil { return errors.Wrap(err, "could not send password reset notification") @@ -654,7 +651,6 @@ func (svc auth) loadUserFromToken(token, kind string) (u *types.User, err error) } return u, svc.db.Transaction(func() error { - spew.Dump(credentialsID) c, err := svc.credentials.FindByID(credentialsID) if err == repository.ErrCredentialsNotFound { return errors.New("no such token") diff --git a/system/internal/service/auth_notification.go b/system/internal/service/auth_notification.go index c639588a7..d84fb617a 100644 --- a/system/internal/service/auth_notification.go +++ b/system/internal/service/auth_notification.go @@ -4,8 +4,8 @@ import ( "bytes" "context" "html/template" + "log" - "github.com/labstack/gommon/log" gomail "gopkg.in/mail.v2" "github.com/crusttech/crust/internal/mail" @@ -31,13 +31,12 @@ type ( } ) +// @todo Temporary email template storage var emailTemplates = map[string]string{ "email-confirmation.en.subject": `[Crust] Confirm your email address`, - "email-confirmation.en.plain": `Confirm your email address {{ .EmailAddress }}:\n{{ .URL }}`, "email-confirmation.en.html": `

Confirm your email address ({{ .EmailAddress }})

`, "password-reset.en.subject": `[Crust] Change your password`, - "password-reset.en.plain": `Use this link to change your password:\n{{ .URL }}`, "password-reset.en.html": `

Change your password

`, } @@ -54,7 +53,7 @@ func (svc authNotification) With(ctx context.Context) AuthNotificationService { } func (svc authNotification) EmailConfirmation(lang string, emailAddress string, url string) error { - return svc.send("email-notification", lang, authNotificationPayload{ + return svc.send("email-confirmation", lang, authNotificationPayload{ EmailAddress: emailAddress, URL: url, }) @@ -78,9 +77,10 @@ func (svc authNotification) send(name, lang string, payload authNotificationPayl ntf.SetAddressHeader("To", payload.EmailAddress, "") ntf.SetHeader("Subject", svc.render(emailTemplates[name+"."+lang+".subject"], payload)) - ntf.SetBody("text/plain", svc.render(emailTemplates[name+"."+lang+".plain"], payload)) ntf.SetBody("text/html", svc.render(emailTemplates[name+"."+lang+".html"], payload)) + log.Printf("sending auth notification (%s.%s) to %q", name, lang, payload.EmailAddress) + return mail.Send(ntf) } diff --git a/system/internal/service/auth_settings.go b/system/internal/service/auth_settings.go index 583b4b1bf..7e7d662ac 100644 --- a/system/internal/service/auth_settings.go +++ b/system/internal/service/auth_settings.go @@ -47,8 +47,8 @@ func AuthSettings(kv authSettingsStore) authSettings { externalEnabled: kv.Bool("auth.external.enabled"), internalEnabled: kv.Bool("auth.internal.enabled"), - internalSignUpEnabled: kv.Bool("auth.internal.sign-up.enabled"), - internalSignUpEmailConfirmationRequired: kv.Bool("auth.internal.sign-up-email-confirmation-required.enabled"), + internalSignUpEnabled: kv.Bool("auth.internal.signup.enabled"), + internalSignUpEmailConfirmationRequired: kv.Bool("auth.internal.signup-email-confirmation-required"), internalPasswordResetEnabled: kv.Bool("auth.internal.password-reset.enabled"), } diff --git a/system/internal/service/service.go b/system/internal/service/service.go index 48d480b09..89b6fd8b1 100644 --- a/system/internal/service/service.go +++ b/system/internal/service/service.go @@ -43,10 +43,6 @@ func Init() (err error) { // Authentication helpers & services DefaultAuthSettings, err = DefaultSettings.LoadAuthSettings() - DefaultAuthSettings.internalEnabled = true - DefaultAuthSettings.internalSignUpEmailConfirmationRequired = true - DefaultAuthSettings.internalPasswordResetEnabled = true - DefaultAuthSettings.mailFromAddress = "denis.arh@gmail.com" if err != nil { return } diff --git a/system/internal/service/settings.go b/system/internal/service/settings.go index ca66f6234..95180f494 100644 --- a/system/internal/service/settings.go +++ b/system/internal/service/settings.go @@ -74,12 +74,11 @@ func (svc settings) Get(name string, ownedBy uint64) (out *internalSettings.Valu return svc.internalSettings.Get(name, ownedBy) } -// Loads auth.* settings, initializes & fills auth settings struct +// Loads auth.% settings, initializes & fills auth settings struct func (svc settings) LoadAuthSettings() (authSettings, error) { - vv, err := svc.internalSettings.FindByPrefix("auth.*") + vv, err := svc.internalSettings.FindByPrefix("auth.") if err != nil { return authSettings{}, err } - return AuthSettings(vv.KV()), nil }