storj/satellite/console/consoleweb/consoleapi/common.go
Jeremy Wharton 9d13c649a2 satellite/{console,satellitedb}: Forbid creating users with used email
This change disallows creation of users possessing the same email.
If a user attempts to create an account with an email address
that's already used - whether it belongs to an active account or not -
he will be notified of unsuccessful account creation. If he attempts to
log in using an email address belonging to an inactive account,
he will be presented with a link allowing him to re-send the
verification email. Attempting to register with an email address
belonging to an existing account triggers a password reset email.

Change-Id: Iefd8c3bef00ecb1dd9e8504594607aa0dca7d82e
2021-12-15 17:24:35 +00:00

102 lines
2.3 KiB
Go

// Copyright (C) 2021 Storj Labs, Inc.
// See LICENSE for copying information.
package consoleapi
import (
"context"
"encoding/json"
"net/http"
"sync"
"github.com/zeebo/errs"
"go.uber.org/zap"
)
var (
// ErrUtils - console utils error type.
ErrUtils = errs.Class("console api utils")
)
// serveJSONError writes a JSON error to the response output stream.
func serveJSONError(log *zap.Logger, w http.ResponseWriter, status int, err error) {
serveCustomJSONError(log, w, status, err, err.Error())
}
// serveCustomJSONError writes a JSON error with a custom message to the response output stream.
func serveCustomJSONError(log *zap.Logger, w http.ResponseWriter, status int, err error, msg string) {
fields := []zap.Field{
zap.Int("code", status),
zap.String("message", msg),
zap.Error(err),
}
switch status {
case http.StatusNoContent:
return
case http.StatusInternalServerError:
log.Error("returning error to client", fields...)
case http.StatusBadRequest:
log.Debug("returning error to client", fields...)
default:
log.Info("returning error to client", fields...)
}
w.WriteHeader(status)
err = json.NewEncoder(w).Encode(map[string]string{
"error": msg,
})
if err != nil {
log.Error("failed to write json error response", zap.Error(ErrUtils.Wrap(err)))
}
}
// ContextChannel is a generic, context-aware channel.
type ContextChannel struct {
mu sync.Mutex
channel chan interface{}
initialized bool
}
// Get waits until a value is sent and returns it, or returns an error if the context has closed.
func (c *ContextChannel) Get(ctx context.Context) (interface{}, error) {
c.initialize()
select {
case val := <-c.channel:
return val, nil
default:
select {
case <-ctx.Done():
return nil, ErrUtils.New("context closed")
case val := <-c.channel:
return val, nil
}
}
}
// Send waits until a value can be sent and sends it, or returns an error if the context has closed.
func (c *ContextChannel) Send(ctx context.Context, val interface{}) error {
c.initialize()
select {
case c.channel <- val:
return nil
default:
select {
case <-ctx.Done():
return ErrUtils.New("context closed")
case c.channel <- val:
return nil
}
}
}
func (c *ContextChannel) initialize() {
c.mu.Lock()
defer c.mu.Unlock()
if c.initialized {
return
}
c.channel = make(chan interface{})
c.initialized = true
}