~netlandish/gobwebs-oauth2

0d5923b376aac0d72e7c624daf9bd0467e77c417 — Peter Sanchez 1 year, 6 months ago 92718ac
Adding personal access tokens
3 files changed, 103 insertions(+), 16 deletions(-)

M input.go
M models.go
M routes.go
M input.go => input.go +18 -7
@@ 1,12 1,27 @@
package oauth2

import (
	"fmt"

	"github.com/labstack/echo/v4"
	"hg.code.netlandish.com/~netlandish/gobwebs/validate"
)

type AddPersonalTokenForm struct {
	Comment string `form:"comment" validate:"-"`
}

func (a *AddPersonalTokenForm) Validate(c echo.Context) error {
	// Binding each field specifically to use BindErrors
	errs := validate.FormFieldBinder(c, a).
		FailFast(false).
		String("comment", &a.Comment).
		BindErrors()
	if errs != nil {
		return validate.GetInputErrors(errs)
	}

	return c.Validate(a)
}

type AddClientForm struct {
	Name        string `form:"name" validate:"required"`
	Description string `form:"description" validate:"-"`


@@ 27,9 42,5 @@ func (a *AddClientForm) Validate(c echo.Context) error {
		return validate.GetInputErrors(errs)
	}

	if err := c.Validate(a); err != nil {
		return err
	}
	fmt.Println("foo")
	return nil
	return c.Validate(a)
}

M models.go => models.go +11 -8
@@ 1,6 1,9 @@
package oauth2

import "time"
import (
	"database/sql"
	"time"
)

// Client ...
type Client struct {


@@ 20,11 23,11 @@ type Client struct {

// Grant ...
type Grant struct {
	ID        int       `db:"id"`
	Issued    time.Time `db:"issued"`
	Expires   time.Time `db:"expires"`
	Comment   time.Time `db:"comment"`
	TokenHash string    `db:"token_hash"`
	UserID    int       `db:"user_id"`
	ClientID  int       `db:"client_id"`
	ID        int           `db:"id"`
	Issued    time.Time     `db:"issued"`
	Expires   time.Time     `db:"expires"`
	Comment   string        `db:"comment"`
	TokenHash string        `db:"token_hash"`
	UserID    int           `db:"user_id"`
	ClientID  sql.NullInt64 `db:"client_id"`
}

M routes.go => routes.go +74 -1
@@ 1,8 1,11 @@
package oauth2

import (
	"crypto/sha512"
	"encoding/hex"
	"fmt"
	"net/http"
	"time"

	sq "github.com/Masterminds/squirrel"
	"github.com/labstack/echo/v4"


@@ 24,11 27,81 @@ func (s *Service) RegisterRoutes() {
	s.eg.POST("/introspect", s.Introspect).Name = s.RouteName("introspect_post")

	s.eg.Use(auth.AuthRequired())
	s.eg.GET("/personal", s.ListPersonal).Name = s.RouteName("list_personal")
	s.eg.GET("/personal/add", s.AddPersonal).Name = s.RouteName("add_personal")
	s.eg.POST("/personal/add", s.AddPersonal).Name = s.RouteName("add_personal_post")
	s.eg.GET("/clients", s.ListClients).Name = s.RouteName("list_clients")
	s.eg.GET("/clients/add", s.AddClient).Name = s.RouteName("add_client")
	s.eg.POST("/clients/add", s.AddClient).Name = s.RouteName("add_client_post")
}

// ListPersonal ...
func (s *Service) ListPersonal(c echo.Context) error {
	gctx := c.(*server.Context)
	opts := &database.FilterOptions{
		Filter: sq.And{
			sq.Eq{"user_id": gctx.User.GetID()},
			sq.Expr("client_id IS NULL"),
			sq.Expr("expires > NOW() at time zone 'UTC'"),
		},
	}
	tokens, err := GetGrants(c.Request().Context(), opts)
	if err != nil {
		return err
	}
	return gctx.Render(http.StatusOK, "oauth2_personal_list.html", gobwebs.Map{
		"tokens": tokens,
	})
}

// AddPersonal ...
func (s *Service) AddPersonal(c echo.Context) error {
	gctx := c.(*server.Context)
	form := &AddPersonalTokenForm{}
	gmap := gobwebs.Map{
		"form": form,
	}

	req := c.Request()
	if req.Method == "POST" {
		if err := form.Validate(c); err != nil {
			gmap["errors"] = err
			return gctx.Render(http.StatusOK, "oauth2_add_personal.html", gmap)
		}

		issued := time.Now().UTC()
		expires := issued.Add(366 * 24 * time.Hour)

		grant := BearerToken{
			Version:  TokenVersion,
			Issued:   ToTimestamp(issued),
			Expires:  ToTimestamp(expires),
			Grants:   "",
			UserID:   int(gctx.User.GetID()),
			ClientID: "",
		}
		token := grant.Encode(c.Request().Context())
		hash := sha512.Sum512([]byte(token))
		tokenHash := hex.EncodeToString(hash[:])

		dbgrant := &Grant{
			Issued:    issued,
			Expires:   expires,
			Comment:   form.Comment,
			TokenHash: tokenHash,
			UserID:    int(gctx.User.GetID()),
		}

		if err := dbgrant.Store(c.Request().Context()); err != nil {
			return err
		}
		gmap["token"] = token
		return gctx.Render(http.StatusOK, "oauth2_add_personal_done.html", gmap)
	}

	return gctx.Render(http.StatusOK, "oauth2_add_personal.html", gmap)
}

// ListClients ...
func (s *Service) ListClients(c echo.Context) error {
	gctx := c.(*server.Context)


@@ 44,7 117,7 @@ func (s *Service) ListClients(c echo.Context) error {
	})
}

// AddClient
// AddClient ...
func (s *Service) AddClient(c echo.Context) error {
	gctx := c.(*server.Context)
	form := &AddClientForm{}