-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactored good parts of the code (#10)
* made the init/login/logout flow more robust * added signup/login timeout * removed helpers and other odd functions * created a dedicated app info struct for the config * moved some utility code the helpers package * refactored packages config and settings, lot's of name changes to functions etc * removed unused error definitions from the codebase * moved examples one level up
- Loading branch information
Showing
34 changed files
with
753 additions
and
678 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,19 +5,22 @@ import ( | |
"net/http" | ||
|
||
"github.com/labstack/echo/v4" | ||
|
||
"github.com/txsvc/stdlib/v2" | ||
|
||
"github.com/txsvc/apikit/config" | ||
"github.com/txsvc/apikit/helpers" | ||
"github.com/txsvc/apikit/internal" | ||
"github.com/txsvc/apikit/internal/auth" | ||
"github.com/txsvc/apikit/internal/settings" | ||
"github.com/txsvc/stdlib/v2" | ||
) | ||
|
||
const ( | ||
// auth routes | ||
InitRoute = "/auth" | ||
LoginRoute = "/auth/:sig/:token" | ||
LogoutRoute = "/auth/:sig" | ||
|
||
LoginExpiresAfter = 15 | ||
) | ||
|
||
func WithAuthEndpoints(e *echo.Echo) *echo.Echo { | ||
|
@@ -33,37 +36,44 @@ func WithAuthEndpoints(e *echo.Echo) *echo.Echo { | |
return e | ||
} | ||
|
||
func (c *Client) InitCommand(cfg *settings.Settings) error { | ||
func (c *Client) InitCommand(cfg *settings.DialSettings) error { | ||
_, err := c.POST(fmt.Sprintf("%s%s", NamespacePrefix, InitRoute), cfg, nil) | ||
return err | ||
} | ||
|
||
func InitEndpoint(c echo.Context) error { | ||
// get the payload | ||
var cfg *settings.Settings = new(settings.Settings) | ||
if err := c.Bind(cfg); err != nil { | ||
var cfg_ *settings.DialSettings = new(settings.DialSettings) | ||
if err := c.Bind(cfg_); err != nil { | ||
return StandardResponse(c, http.StatusBadRequest, nil) | ||
} | ||
|
||
// pre-validate the request | ||
if cfg.Credentials == nil || cfg.APIKey == "" { | ||
if cfg_.Credentials == nil || cfg_.APIKey == "" { | ||
return StandardResponse(c, http.StatusBadRequest, nil) | ||
} | ||
if cfg.Credentials.ProjectID == "" || cfg.Credentials.UserID == "" { | ||
if cfg_.Credentials.ProjectID == "" || cfg_.Credentials.UserID == "" { | ||
return StandardResponse(c, http.StatusBadRequest, nil) | ||
} | ||
|
||
// create a brand new instance so that the client can't sneak anything in we don't want | ||
cfg := settings.DialSettings{ | ||
Credentials: cfg_.Credentials.Clone(), | ||
DefaultScopes: config.GetConfig().GetScopes(), | ||
} | ||
|
||
// prepare the settings for registration | ||
cfg.Credentials.Token = internal.CreateSimpleToken() // ignore anything that was provided | ||
cfg.Credentials.Expires = stdlib.IncT(stdlib.Now(), 15) // FIXME: config, valid for 15min | ||
cfg.Status = -2 // signals init | ||
cfg.Credentials.Token = CreateSimpleToken() // ignore anything that was provided | ||
cfg.Credentials.Expires = stdlib.IncT(stdlib.Now(), LoginExpiresAfter) | ||
cfg.APIKey = cfg_.APIKey | ||
cfg.Status = settings.StateInit // signals init | ||
|
||
if err := auth.RegisterAuthorization(cfg); err != nil { | ||
if err := auth.RegisterAuthorization(&cfg); err != nil { | ||
return StandardResponse(c, http.StatusBadRequest, nil) // FIXME: or 409/Conflict ? | ||
} | ||
|
||
// all good so far, send the confirmation | ||
err := helpers.MailgunSimpleEmail("[email protected]", cfg.Credentials.UserID, "auth", fmt.Sprintf("the token: %s\n", cfg.Credentials.Token)) | ||
err := helpers.MailgunSimpleEmail("[email protected]", cfg.Credentials.UserID, fmt.Sprintf("your api access credentials (%d)", stdlib.Now()), fmt.Sprintf("the token: %s\n", cfg.Credentials.Token)) | ||
if err != nil { | ||
return StandardResponse(c, http.StatusBadRequest, nil) | ||
} | ||
|
@@ -93,24 +103,29 @@ func LoginEndpoint(c echo.Context) error { | |
} | ||
|
||
// verify the request | ||
_cfg, err := auth.LookupByToken(token) | ||
if _cfg == nil && err != nil { | ||
cfg_, err := auth.LookupByToken(token) | ||
if cfg_ == nil && err != nil { | ||
return ErrorResponse(c, http.StatusBadRequest, ErrInternalError, "token") | ||
} | ||
if _cfg == nil && err == nil { | ||
if cfg_ == nil && err == nil { | ||
return ErrorResponse(c, http.StatusBadRequest, config.ErrInitializingConfiguration, "not found") // simply not there ... | ||
} | ||
|
||
// compare provided signature with the expected signature | ||
if sig != signature(_cfg.APIKey, _cfg.Credentials.Token) { | ||
if sig != signature(cfg_.APIKey, cfg_.Credentials.Token) { | ||
return ErrorResponse(c, http.StatusBadRequest, config.ErrInitializingConfiguration, "invalid sig") | ||
} | ||
|
||
// check if the token is still valid | ||
if cfg_.Credentials.Expires < stdlib.Now() { | ||
return ErrorResponse(c, http.StatusBadRequest, auth.ErrTokenExpired, "expired") | ||
} | ||
|
||
// everything checks out, create/register the real credentials now ... | ||
cfg := _cfg.Clone() // clone, otherwise stupid things happen with pointers ! | ||
cfg := cfg_.Clone() // clone, otherwise stupid things happen with pointers ! | ||
cfg.Credentials.Expires = 0 // FIXME: really never ? | ||
cfg.Credentials.Token = internal.CreateSimpleToken() | ||
cfg.Status = 1 // FIXME: LOGGED_IN as const | ||
cfg.Credentials.Token = CreateSimpleToken() | ||
cfg.Status = settings.StateAuthorized | ||
|
||
// FIXME: what about scopes ? | ||
|
||
|
@@ -159,7 +174,7 @@ func LogoutEndpoint(c echo.Context) error { | |
} | ||
|
||
// update the cache and store | ||
cfg.Status = -1 // just set to invalid and expired | ||
cfg.Status = settings.StateUndefined // just set to invalid and expired | ||
cfg.Credentials.Expires = stdlib.Now() - 1 | ||
if err := auth.UpdateStore(cfg); err != nil { | ||
return ErrorResponse(c, http.StatusBadRequest, err, "update store") | ||
|
@@ -172,3 +187,8 @@ func LogoutEndpoint(c echo.Context) error { | |
func signature(apiKey, token string) string { | ||
return stdlib.Fingerprint(fmt.Sprintf("%s%s", apiKey, token)) | ||
} | ||
|
||
func CreateSimpleToken() string { | ||
token, _ := stdlib.UUID() | ||
return token | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.