Skip to content

Commit

Permalink
Merge pull request #2 from visiperf/feat/vercel-serverless-function
Browse files Browse the repository at this point in the history
Feat/vercel serverless function
  • Loading branch information
romain-jeannoutot authored Oct 6, 2022
2 parents 626d3b0 + c7e612a commit 651a4e9
Show file tree
Hide file tree
Showing 14 changed files with 330 additions and 14 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
.idea/

# environment
.env
.env
.vercel
37 changes: 37 additions & 0 deletions api/me.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package api

import (
"net/http"
"net/url"

"github.com/visiperf/visiauth/v3"
"github.com/visiperf/visiauth/v3/api/renderer"
"github.com/visiperf/visiauth/v3/errors"
"github.com/visiperf/visiauth/v3/neo4j"
"github.com/visiperf/visiauth/v3/redis"
)

const (
accessTokenQueryParamsKey = "token"
)

func MeHandler(w http.ResponseWriter, r *http.Request) {
authenticable, err := func() (visiauth.Authenticable, error) {
vs, err := url.ParseQuery(r.URL.RawQuery)
if err != nil {
return nil, errors.InvalidArgument(err.Error(), "INVALID_QUERY_PARAMS")
}

if len(vs.Get(accessTokenQueryParamsKey)) <= 0 {
return nil, errors.InvalidArgument("token in query params is required", "TOKEN_QUERY_PARAMS_REQUIRED")
}

return visiauth.NewService(redis.NewJwkFetcher(), neo4j.NewUserRepository()).DecodeAccessToken(r.Context(), vs.Get(accessTokenQueryParamsKey))
}()
if err != nil {
renderer.Error(err, w)
return
}

renderer.Success(authenticable, http.StatusOK, w)
}
39 changes: 39 additions & 0 deletions api/renderer/render.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package renderer

import (
"encoding/json"
"errors"
"net/http"
)

func Success(v interface{}, statusCode int, rw http.ResponseWriter) {
data, err := json.Marshal(map[string]interface{}{"data": v})
if err != nil {
Error(err, rw)
return
}

render(data, statusCode, "application/json", rw)
}

func Error(err error, rw http.ResponseWriter) {
data, _ := json.Marshal(map[string]interface{}{"error": err})

var sce interface {
error
StatusCode() int
}

sc := http.StatusInternalServerError
if errors.As(err, &sce) {
sc = sce.StatusCode()
}

render(data, sc, "application/json", rw)
}

func render(data []byte, statusCode int, contentType string, rw http.ResponseWriter) {
rw.Header().Set("Content-Type", contentType)
rw.WriteHeader(statusCode)
rw.Write(data)
}
10 changes: 10 additions & 0 deletions app.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package visiauth

import "encoding/json"

type App struct {
id string
}
Expand All @@ -11,3 +13,11 @@ func NewApp(id string) *App {
func (a App) ID() string {
return a.id
}

func (a App) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
ID string `json:"id"`
}{
ID: a.ID(),
})
}
44 changes: 44 additions & 0 deletions errors/internal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package errors

import (
"encoding/json"
"errors"
"net/http"
)

type internal struct {
err error
}

func Internal(err error) error {
return internal{err}
}

func (i internal) Message() string {
return i.err.Error()
}

func (i internal) StatusCode() int {
return http.StatusInternalServerError
}

func (i internal) String() string {
return i.Message()
}

func (i internal) Error() string {
return i.String()
}

func (i internal) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Message string `json:"message"`
}{
Message: i.Message(),
})
}

func IsInternal(err error) bool {
var i internal
return errors.As(err, &i)
}
50 changes: 50 additions & 0 deletions errors/invalid-argument.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package errors

import (
"encoding/json"
"errors"
"net/http"
)

type invalidArgument struct {
reason, code string
}

func InvalidArgument(reason, code string) error {
return invalidArgument{reason, code}
}

func (ia invalidArgument) Message() string {
return ia.reason
}

func (ia invalidArgument) Code() string {
return ia.code
}

func (ia invalidArgument) StatusCode() int {
return http.StatusBadRequest
}

func (ia invalidArgument) String() string {
return ia.Message()
}

func (ia invalidArgument) Error() string {
return ia.String()
}

func (ia invalidArgument) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Message string `json:"message"`
Code string `json:"code"`
}{
Message: ia.Message(),
Code: ia.Code(),
})
}

func IsInvalidArgument(err error) bool {
var ia invalidArgument
return errors.As(err, &ia)
}
43 changes: 43 additions & 0 deletions errors/not-found.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package errors

import (
"errors"
"fmt"
"net/http"
)

type notFound struct {
resource, code string
}

func NotFound(resource, code string) error {
return notFound{
resource: resource,
code: code,
}
}

func (nf notFound) Message() string {
return fmt.Sprintf("%s not found", nf.resource)
}

func (nf notFound) Code() string {
return nf.code
}

func (nf notFound) StatusCode() int {
return http.StatusNotFound
}

func (nf notFound) String() string {
return nf.Message()
}

func (nf notFound) Error() string {
return nf.String()
}

func IsNotFound(err error) bool {
var nf notFound
return errors.As(err, &nf)
}
50 changes: 50 additions & 0 deletions errors/unauthorized.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package errors

import (
"encoding/json"
"errors"
"net/http"
)

type unauthorized struct {
reason, code string
}

func Unauthorized(reason, code string) error {
return unauthorized{reason, code}
}

func (u unauthorized) Message() string {
return u.reason
}

func (u unauthorized) Code() string {
return u.code
}

func (u unauthorized) StatusCode() int {
return http.StatusUnauthorized
}

func (u unauthorized) String() string {
return u.Message()
}

func (u unauthorized) Error() string {
return u.String()
}

func (u unauthorized) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Message string `json:"message"`
Code string `json:"code"`
}{
Message: u.Message(),
Code: u.Code(),
})
}

func IsUnauthorized(err error) bool {
var u unauthorized
return errors.As(err, &u)
}
11 changes: 6 additions & 5 deletions neo4j/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/neo4j/neo4j-go-driver/v4/neo4j"
"github.com/visiperf/visiauth/v3"
"github.com/visiperf/visiauth/v3/errors"
)

type UserRepository struct {
Expand All @@ -22,7 +23,7 @@ func (r *UserRepository) FetchUserByID(ctx context.Context, userID string, scope
c.Log = neo4j.ConsoleLogger(neo4j.ERROR)
})
if err != nil {
return nil, err
return nil, errors.Internal(err)
}
defer driver.Close()

Expand All @@ -49,12 +50,12 @@ func (r *UserRepository) fetchUserLegacyID(_ context.Context, session neo4j.Sess
"user_id": userID,
})
if err != nil {
return "", err
return "", errors.Internal(err)
}

rec, err := res.Single()
if err != nil {
return "", err
return "", errors.Internal(err)
}

return rec.Values[0].(string), nil
Expand All @@ -74,7 +75,7 @@ func (r *UserRepository) fetchUserOrganizations(_ context.Context, session neo4j
"user_id": userID,
})
if err != nil {
return nil, nil, err
return nil, nil, errors.Internal(err)
}

m := make(map[string]string)
Expand All @@ -89,7 +90,7 @@ func (r *UserRepository) fetchUserOrganizations(_ context.Context, session neo4j
}

if err := res.Err(); err != nil {
return nil, nil, err
return nil, nil, errors.Internal(err)
}

return m, s, nil
Expand Down
9 changes: 9 additions & 0 deletions redis/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package redis

const (
ErrRedisNilMessage = "redis: nil"
)

func IsErrRedisNilMessage(err error) bool {
return err.Error() == ErrRedisNilMessage
}
7 changes: 6 additions & 1 deletion redis/jwk.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/go-redis/redis/v8"
"github.com/visiperf/visiauth/v3"
"github.com/visiperf/visiauth/v3/errors"
)

type JwkFetcher struct {
Expand All @@ -27,7 +28,11 @@ func (f *JwkFetcher) FetchJwk(ctx context.Context, kid string) (*visiauth.Jwk, e

var jwk visiauth.Jwk
if err := client.Get(ctx, kid).Scan(&jwk); err != nil {
return nil, err
if IsErrRedisNilMessage(err) {
return nil, errors.NotFound("jwk", "JWK_NOT_FOUND")
}

return nil, errors.Internal(err)
}

return &jwk, nil
Expand Down
6 changes: 4 additions & 2 deletions service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package visiauth

import (
"context"
"errors"
"fmt"
"strings"

"github.com/visiperf/visiauth/v3/errors"
)

type Service struct {
Expand Down Expand Up @@ -31,7 +33,7 @@ func (s *Service) DecodeAccessToken(ctx context.Context, accessToken string) (Au
return s.app(ctx, t)
}

return nil, errors.New("unknown token type")
return nil, errors.Internal(fmt.Errorf("unknown token type"))
}

func (s *Service) app(ctx context.Context, token *MachineToken) (Authenticable, error) {
Expand Down
Loading

0 comments on commit 651a4e9

Please sign in to comment.