Skip to content

Commit

Permalink
Refactoring to unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
vporoshok committed Jun 1, 2017
1 parent 79f6d1a commit a459dfd
Show file tree
Hide file tree
Showing 21 changed files with 739 additions and 651 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out
*.coverprofile

# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/
Expand Down
10 changes: 4 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,18 @@ sudo: false

before_install:
- go get github.com/Masterminds/glide
- go get github.com/go-playground/overalls
- go get github.com/mattn/goveralls

before_script:
- glide install

services:
- postgresql

script:
- go test -test.cover -test.coverprofile=coverage.out -test.coverpkg=./src/... ./tests/
- go test -test.race ./tests/
- go vet $(go list ./... | grep -v /vendor/)
- overalls -project=github.com/l10n-center/api -- -race -v

after_script:
- goveralls -coverprofile=coverage.out -service=travis-ci
- goveralls -coverprofile=overalls.coverprofile -service=travis-ci

notifications:
email: true
6 changes: 4 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"syscall"
"time"

"github.com/l10n-center/api/src/server"
"github.com/l10n-center/api/src/controller"

"github.com/mattes/migrate"
"github.com/mattes/migrate/database/postgres"
Expand Down Expand Up @@ -150,7 +150,9 @@ func initServer(l *zap.Logger, db *sql.DB) *http.Server {
BIND = "0.0.0.0:3000"
l.Sugar().Infof("bind not set, use default (%s)", BIND)
}
r := server.NewRouter(db, []byte(SECRET))
r := controller.NewRouter(&controller.Config{
Secret: []byte(SECRET),
}, db)

return &http.Server{
Addr: BIND,
Expand Down
31 changes: 31 additions & 0 deletions src/auth/claims.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package auth

import (
"context"

"github.com/l10n-center/api/src/model"

"github.com/dgrijalva/jwt-go"
)

type claimsCtxKey struct{}

// Claims of authorization token
type Claims struct {
jwt.StandardClaims
UserID int32 `json:"userId"`
Email string `json:"email"`
Role model.Role `json:"role"`
}

// ContextWithClaims store claims in context
func ContextWithClaims(ctx context.Context, c *Claims) context.Context {
return context.WithValue(ctx, claimsCtxKey{}, c)
}

// ClaimsFromContext try to extract authorization claims from context
func ClaimsFromContext(ctx context.Context) (*Claims, bool) {
c, ok := ctx.Value(claimsCtxKey{}).(*Claims)

return c, ok
}
49 changes: 49 additions & 0 deletions src/auth/middleware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package auth

import (
"context"
"net/http"
"strings"

"github.com/l10n-center/api/src/tracing"

"github.com/dgrijalva/jwt-go"
"github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
)

// Middleware to check Authorization header and try to parse token
func Middleware(secret []byte) func(http.Handler) http.Handler {
// WithClaims check Authorization header and try to parse token
return func(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
var c *Claims
ctx := r.Context()
authHeader := r.Header.Get("Authorization")
if len(authHeader) > 7 && strings.ToUpper(authHeader[:7]) == "BEARER " {
l := tracing.Logger(ctx)
sp := opentracing.SpanFromContext(ctx)
tokenString := authHeader[7:]
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(t *jwt.Token) (interface{}, error) {
if t.Method != jwt.SigningMethodHS256 {

return nil, errors.Errorf("unexpected signing method %q", t.Method)
}

return secret, nil
})
if err != nil {
l.Error(err.Error())
} else if token.Valid {
c = token.Claims.(*Claims)
sp.SetTag("claims", c)
ctx = context.WithValue(r.Context(), claimsCtxKey{}, c)
}
}

next.ServeHTTP(w, r.WithContext(ctx))
}

return http.HandlerFunc(fn)
}
}
37 changes: 37 additions & 0 deletions src/auth/private.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package auth

import (
"net/http"

"github.com/l10n-center/api/src/model"
"github.com/l10n-center/api/src/tracing"
)

// Private check claims and given role to access control
func Private(role model.Role) func(http.Handler) http.Handler {
// Private check claims and given role to access control
return func(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
l := tracing.Logger(ctx)
c, ok := ClaimsFromContext(ctx)

if !ok {
l.Warn("unauthorized access")
w.WriteHeader(http.StatusUnauthorized)

return
}

if role > 0 && c.Role&role == 0 {
l.Warn("forbidden access")
w.WriteHeader(http.StatusForbidden)

return
}
next.ServeHTTP(w, r)
}

return http.HandlerFunc(fn)
}
}
33 changes: 33 additions & 0 deletions src/auth/token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package auth

import (
"context"
"time"

"github.com/l10n-center/api/src/model"
"github.com/l10n-center/api/src/tracing"

"github.com/dgrijalva/jwt-go"
"github.com/pkg/errors"
)

// CreateToken from user and sign it
func CreateToken(ctx context.Context, secret []byte, u *model.User) (string, error) {
l := tracing.Logger(ctx)
c := &Claims{
UserID: u.ID,
Email: u.Email,
Role: u.Role,
}
c.ExpiresAt = time.Now().AddDate(0, 0, 14).Unix()
t := jwt.NewWithClaims(jwt.SigningMethodHS256, c)

st, err := t.SignedString(secret)
if err != nil {
l.Error(err.Error())

return "", errors.WithStack(err)
}

return st, nil
}
Loading

0 comments on commit a459dfd

Please sign in to comment.