mirror of
https://github.com/elyby/chrly.git
synced 2024-12-23 13:40:11 +05:30
The configuration file was deleted in favor of using environment variables.
Token generation functionality remove. Secret token now provided via CHRLY_SECRET env variable.
This commit is contained in:
parent
235f65f11c
commit
778bc615aa
28
Gopkg.lock
generated
28
Gopkg.lock
generated
@ -55,12 +55,6 @@
|
||||
packages = [".","hcl/ast","hcl/parser","hcl/scanner","hcl/strconv","hcl/token","json/parser","json/scanner","json/token"]
|
||||
revision = "8f6b1344a92ff8877cf24a5de9177bf7d0a2a187"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/howeyc/gopass"
|
||||
packages = ["."]
|
||||
revision = "bf9dde6d0d2c004a008c27aaee91170c786f6db8"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/inconshreveable/mousetrap"
|
||||
packages = ["."]
|
||||
@ -79,12 +73,6 @@
|
||||
packages = ["cluster","pool","redis","util"]
|
||||
revision = "d234cfb904a91daafa4e1f92599a893b349cc0c2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/mitchellh/go-homedir"
|
||||
packages = ["."]
|
||||
revision = "b8bc1bf767474819792c23f32d8286a45736f1c6"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/mitchellh/mapstructure"
|
||||
@ -121,12 +109,6 @@
|
||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/segmentio/go-prompt"
|
||||
packages = ["."]
|
||||
revision = "f0d19b6901ade831d5a3204edc0d6a7d6457fbb2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/spf13/afero"
|
||||
@ -176,16 +158,10 @@
|
||||
revision = "59055296916bb3c6ad9cf3b21d5f2cf7059f8e76"
|
||||
source = "https://github.com/erickskrauch/govalidator.git"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = ["ssh/terminal"]
|
||||
revision = "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix","windows"]
|
||||
packages = ["unix"]
|
||||
revision = "7ddbeae9ae08c6a06a59597f0c9edbc5ff2444ce"
|
||||
|
||||
[[projects]]
|
||||
@ -203,6 +179,6 @@
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "85c318cc67a4e78dd3608297ae189cc70b07968ba6e0e1a04cc21b264fddf1eb"
|
||||
inputs-digest = "e6bd87f630333e3e5b03bea33720c3281a9094551bd5ced436062157fe51ab71"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
11
Gopkg.toml
11
Gopkg.toml
@ -24,22 +24,11 @@ ignored = ["elyby/minecraft-skinsystem"]
|
||||
name = "github.com/SermoDigital/jose"
|
||||
version = "~1.1.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/mitchellh/go-homedir"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/segmentio/go-prompt"
|
||||
branch = "master"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/thedevsaddam/govalidator"
|
||||
source = "https://github.com/erickskrauch/govalidator.git"
|
||||
branch = "issue-18"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/spf13/afero"
|
||||
|
||||
# Testing dependencies
|
||||
|
||||
[[constraint]]
|
||||
|
112
auth/jwt.go
112
auth/jwt.go
@ -1,25 +1,17 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"math"
|
||||
"math/rand"
|
||||
"errors"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/SermoDigital/jose/crypto"
|
||||
"github.com/SermoDigital/jose/jws"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
var fs = afero.NewOsFs()
|
||||
|
||||
var hashAlg = crypto.SigningMethodHS256
|
||||
|
||||
const appHomeDirName = ".minecraft-skinsystem"
|
||||
const scopesClaim = "scopes"
|
||||
|
||||
type Scope string
|
||||
@ -29,20 +21,19 @@ var (
|
||||
)
|
||||
|
||||
type JwtAuth struct {
|
||||
signingKey []byte
|
||||
Key []byte
|
||||
}
|
||||
|
||||
func (t *JwtAuth) NewToken(scopes ...Scope) ([]byte, error) {
|
||||
key, err := t.getSigningKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if len(t.Key) == 0 {
|
||||
return nil, errors.New("signing key not available")
|
||||
}
|
||||
|
||||
claims := jws.Claims{}
|
||||
claims.Set(scopesClaim, scopes)
|
||||
claims.SetIssuedAt(time.Now())
|
||||
encoder := jws.NewJWT(claims, hashAlg)
|
||||
token, err := encoder.Serialize(key)
|
||||
token, err := encoder.Serialize(t.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -50,20 +41,11 @@ func (t *JwtAuth) NewToken(scopes ...Scope) ([]byte, error) {
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (t *JwtAuth) GenerateSigningKey() error {
|
||||
if err := createAppHomeDir(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
key := generateRandomBytes(64)
|
||||
if err := afero.WriteFile(fs, getKeyPath(), key, 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *JwtAuth) Check(req *http.Request) error {
|
||||
if len(t.Key) == 0 {
|
||||
return &Unauthorized{"Signing key not set"}
|
||||
}
|
||||
|
||||
bearerToken := req.Header.Get("Authorization")
|
||||
if bearerToken == "" {
|
||||
return &Unauthorized{"Authentication header not presented"}
|
||||
@ -79,79 +61,14 @@ func (t *JwtAuth) Check(req *http.Request) error {
|
||||
return &Unauthorized{"Cannot parse passed JWT token"}
|
||||
}
|
||||
|
||||
signKey, err := t.getSigningKey()
|
||||
err = token.Validate(t.Key, hashAlg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = token.Validate(signKey, hashAlg)
|
||||
if err != nil {
|
||||
return &Unauthorized{"JWT token have invalid signature. It corrupted or expired."}
|
||||
return &Unauthorized{"JWT token have invalid signature. It may be corrupted or expired."}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *JwtAuth) getSigningKey() ([]byte, error) {
|
||||
if t.signingKey == nil {
|
||||
path := getKeyPath()
|
||||
if _, err := fs.Stat(path); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, &SigningKeyNotAvailable{}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, err := afero.ReadFile(fs, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t.signingKey = key
|
||||
}
|
||||
|
||||
return t.signingKey, nil
|
||||
}
|
||||
|
||||
func createAppHomeDir() error {
|
||||
path := getAppHomeDirPath()
|
||||
if _, err := fs.Stat(path); os.IsNotExist(err) {
|
||||
err := fs.Mkdir(path, 0755) // rwx r-x r-x
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getAppHomeDirPath() string {
|
||||
path, err := homedir.Expand("~/" + appHomeDirName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
func getKeyPath() string {
|
||||
return getAppHomeDirPath() + "/jwt-key"
|
||||
}
|
||||
|
||||
func generateRandomBytes(n int) []byte {
|
||||
// base64 will increase length in 1.37 times
|
||||
// +1 is needed to ensure, that after base64 we will do not have any '===' characters
|
||||
randLen := int(math.Ceil(float64(n) / 1.37)) + 1
|
||||
randBytes := make([]byte, randLen)
|
||||
rand.Read(randBytes)
|
||||
// +5 is needed to have additional buffer for the next set of XX=== characters
|
||||
resBytes := make([]byte, n + 5)
|
||||
base64.URLEncoding.Encode(resBytes, randBytes)
|
||||
|
||||
return resBytes[:n]
|
||||
}
|
||||
|
||||
type Unauthorized struct {
|
||||
Reason string
|
||||
}
|
||||
@ -163,10 +80,3 @@ func (e *Unauthorized) Error() string {
|
||||
|
||||
return "Unauthorized"
|
||||
}
|
||||
|
||||
type SigningKeyNotAvailable struct {
|
||||
}
|
||||
|
||||
func (*SigningKeyNotAvailable) Error() string {
|
||||
return "Signing key not available"
|
||||
}
|
||||
|
@ -2,88 +2,36 @@ package auth
|
||||
|
||||
import (
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
|
||||
testify "github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxNTE2NjU4MTkzIiwic2NvcGVzIjoic2tpbiJ9.agbBS0qdyYMBaVfTZJAZcTTRgW1Y0kZty4H3N2JHBO8"
|
||||
|
||||
func TestJwtAuth_NewToken_Success(t *testing.T) {
|
||||
clearFs()
|
||||
assert := testify.New(t)
|
||||
|
||||
fs.Mkdir(getAppHomeDirPath(), 0755)
|
||||
afero.WriteFile(fs, getKeyPath(), []byte("secret"), 0600)
|
||||
|
||||
jwt := &JwtAuth{}
|
||||
jwt := &JwtAuth{[]byte("secret")}
|
||||
token, err := jwt.NewToken(SkinScope)
|
||||
assert.Nil(err)
|
||||
assert.NotNil(token)
|
||||
}
|
||||
|
||||
func TestJwtAuth_NewToken_KeyNotAvailable(t *testing.T) {
|
||||
clearFs()
|
||||
assert := testify.New(t)
|
||||
|
||||
fs = afero.NewMemMapFs()
|
||||
|
||||
jwt := &JwtAuth{}
|
||||
token, err := jwt.NewToken(SkinScope)
|
||||
assert.IsType(&SigningKeyNotAvailable{}, err)
|
||||
assert.Error(err, "signing key not available")
|
||||
assert.Nil(token)
|
||||
}
|
||||
|
||||
func TestJwtAuth_GenerateSigningKey_KeyNotExists(t *testing.T) {
|
||||
clearFs()
|
||||
assert := testify.New(t)
|
||||
|
||||
jwt := &JwtAuth{}
|
||||
err := jwt.GenerateSigningKey()
|
||||
assert.Nil(err)
|
||||
if _, err := fs.Stat(getAppHomeDirPath()); err != nil {
|
||||
assert.Fail("directory not created")
|
||||
}
|
||||
|
||||
if _, err := fs.Stat(getKeyPath()); err != nil {
|
||||
assert.Fail("signing file not created")
|
||||
}
|
||||
|
||||
content, _ := afero.ReadFile(fs, getKeyPath())
|
||||
assert.Len(content, 64)
|
||||
}
|
||||
|
||||
func TestJwtAuth_GenerateSigningKey_KeyExists(t *testing.T) {
|
||||
clearFs()
|
||||
assert := testify.New(t)
|
||||
|
||||
fs.Mkdir(getAppHomeDirPath(), 0755)
|
||||
afero.WriteFile(fs, getKeyPath(), []byte("secret"), 0600)
|
||||
|
||||
jwt := &JwtAuth{}
|
||||
err := jwt.GenerateSigningKey()
|
||||
assert.Nil(err)
|
||||
if _, err := fs.Stat(getAppHomeDirPath()); err != nil {
|
||||
assert.Fail("directory not created")
|
||||
}
|
||||
|
||||
if _, err := fs.Stat(getKeyPath()); err != nil {
|
||||
assert.Fail("signing file not created")
|
||||
}
|
||||
|
||||
content, _ := afero.ReadFile(fs, getKeyPath())
|
||||
assert.NotEqual([]byte("secret"), content)
|
||||
}
|
||||
|
||||
func TestJwtAuth_Check_EmptyRequest(t *testing.T) {
|
||||
clearFs()
|
||||
assert := testify.New(t)
|
||||
|
||||
req := httptest.NewRequest("POST", "http://localhost", nil)
|
||||
jwt := &JwtAuth{}
|
||||
jwt := &JwtAuth{[]byte("secret")}
|
||||
|
||||
err := jwt.Check(req)
|
||||
assert.IsType(&Unauthorized{}, err)
|
||||
@ -91,12 +39,11 @@ func TestJwtAuth_Check_EmptyRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestJwtAuth_Check_NonBearer(t *testing.T) {
|
||||
clearFs()
|
||||
assert := testify.New(t)
|
||||
|
||||
req := httptest.NewRequest("POST", "http://localhost", nil)
|
||||
req.Header.Add("Authorization", "this is not jwt")
|
||||
jwt := &JwtAuth{}
|
||||
jwt := &JwtAuth{[]byte("secret")}
|
||||
|
||||
err := jwt.Check(req)
|
||||
assert.IsType(&Unauthorized{}, err)
|
||||
@ -104,12 +51,11 @@ func TestJwtAuth_Check_NonBearer(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestJwtAuth_Check_BearerButNotJwt(t *testing.T) {
|
||||
clearFs()
|
||||
assert := testify.New(t)
|
||||
|
||||
req := httptest.NewRequest("POST", "http://localhost", nil)
|
||||
req.Header.Add("Authorization", "Bearer thisIs.Not.Jwt")
|
||||
jwt := &JwtAuth{}
|
||||
jwt := &JwtAuth{[]byte("secret")}
|
||||
|
||||
err := jwt.Check(req)
|
||||
assert.IsType(&Unauthorized{}, err)
|
||||
@ -117,7 +63,6 @@ func TestJwtAuth_Check_BearerButNotJwt(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestJwtAuth_Check_SecretNotAvailable(t *testing.T) {
|
||||
clearFs()
|
||||
assert := testify.New(t)
|
||||
|
||||
req := httptest.NewRequest("POST", "http://localhost", nil)
|
||||
@ -125,11 +70,10 @@ func TestJwtAuth_Check_SecretNotAvailable(t *testing.T) {
|
||||
jwt := &JwtAuth{}
|
||||
|
||||
err := jwt.Check(req)
|
||||
assert.IsType(&SigningKeyNotAvailable{}, err)
|
||||
assert.Error(err, "Signing key not set")
|
||||
}
|
||||
|
||||
func TestJwtAuth_Check_SecretInvalid(t *testing.T) {
|
||||
clearFs()
|
||||
assert := testify.New(t)
|
||||
|
||||
req := httptest.NewRequest("POST", "http://localhost", nil)
|
||||
@ -138,11 +82,10 @@ func TestJwtAuth_Check_SecretInvalid(t *testing.T) {
|
||||
|
||||
err := jwt.Check(req)
|
||||
assert.IsType(&Unauthorized{}, err)
|
||||
assert.EqualError(err, "JWT token have invalid signature. It corrupted or expired.")
|
||||
assert.EqualError(err, "JWT token have invalid signature. It may be corrupted or expired.")
|
||||
}
|
||||
|
||||
func TestJwtAuth_Check_Valid(t *testing.T) {
|
||||
clearFs()
|
||||
assert := testify.New(t)
|
||||
|
||||
req := httptest.NewRequest("POST", "http://localhost", nil)
|
||||
@ -152,17 +95,3 @@ func TestJwtAuth_Check_Valid(t *testing.T) {
|
||||
err := jwt.Check(req)
|
||||
assert.Nil(err)
|
||||
}
|
||||
|
||||
func TestJwtAuth_generateRandomBytes(t *testing.T) {
|
||||
assert := testify.New(t)
|
||||
lengthMap := []int{12, 20, 24, 30, 32, 48, 50, 64}
|
||||
for _, length := range lengthMap {
|
||||
bytes := generateRandomBytes(length)
|
||||
assert.Len(bytes, length)
|
||||
assert.False(strings.HasSuffix(string(bytes), "="), "secret key should not ends with '=' character")
|
||||
}
|
||||
}
|
||||
|
||||
func clearFs() {
|
||||
fs = afero.NewMemMapFs()
|
||||
}
|
||||
|
@ -62,12 +62,3 @@ func CreateLogger(statsdAddr string, sentryAddr string) (wd.Watchdog, error) {
|
||||
|
||||
return wd.New("", "").WithParams(rays.Host), nil
|
||||
}
|
||||
|
||||
type RabbitMQConfig struct {
|
||||
Username string
|
||||
Password string
|
||||
Host string
|
||||
Port int
|
||||
Vhost string
|
||||
}
|
||||
|
||||
|
19
cmd/root.go
19
cmd/root.go
@ -3,6 +3,7 @@ package cmd
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"elyby/minecraft-skinsystem/bootstrap"
|
||||
|
||||
@ -10,8 +11,6 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var cfgFile string
|
||||
|
||||
var RootCmd = &cobra.Command{
|
||||
Use: "chrly",
|
||||
Short: "Implementation of Minecraft skins system server",
|
||||
@ -29,22 +28,10 @@ func Execute() {
|
||||
|
||||
func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.test.yaml)")
|
||||
}
|
||||
|
||||
func initConfig() {
|
||||
if cfgFile != "" {
|
||||
viper.SetConfigFile(cfgFile)
|
||||
} else {
|
||||
viper.SetConfigName("config")
|
||||
viper.AddConfigPath("/etc/minecraft-skinsystem")
|
||||
viper.AddConfigPath(".")
|
||||
}
|
||||
|
||||
viper.AutomaticEnv()
|
||||
|
||||
if err := viper.ReadInConfig(); err == nil {
|
||||
// TODO: show only on verbose mode
|
||||
fmt.Println("Using config file:", viper.ConfigFileUsed())
|
||||
}
|
||||
replacer := strings.NewReplacer(".", "_")
|
||||
viper.SetEnvKeyReplacer(replacer)
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ var serveCmd = &cobra.Command{
|
||||
SkinsRepo: skinsRepo,
|
||||
CapesRepo: capesRepo,
|
||||
Logger: logger,
|
||||
Auth: &auth.JwtAuth{},
|
||||
Auth: &auth.JwtAuth{Key: []byte(viper.GetString("chrly.secret"))},
|
||||
}
|
||||
|
||||
if err := cfg.Run(); err != nil {
|
||||
@ -58,4 +58,11 @@ var serveCmd = &cobra.Command{
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(serveCmd)
|
||||
viper.SetDefault("server.host", "")
|
||||
viper.SetDefault("server.port", 80)
|
||||
viper.SetDefault("storage.redis.host", "localhost")
|
||||
viper.SetDefault("storage.redis.port", 6379)
|
||||
viper.SetDefault("storage.redis.poll", 10)
|
||||
viper.SetDefault("storage.filesystem.basePath", "data")
|
||||
viper.SetDefault("storage.filesystem.capesDirName", "capes")
|
||||
}
|
||||
|
48
cmd/token.go
48
cmd/token.go
@ -6,60 +6,24 @@ import (
|
||||
|
||||
"elyby/minecraft-skinsystem/auth"
|
||||
|
||||
"github.com/segmentio/go-prompt"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var tokenCmd = &cobra.Command{
|
||||
Use: "token",
|
||||
Short: "API tokens manipulation",
|
||||
}
|
||||
|
||||
var createCmd = &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "Creates a new token, which allows to interact with Chrly API",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
jwtAuth := &auth.JwtAuth{}
|
||||
for {
|
||||
token, err := jwtAuth.NewToken(auth.SkinScope)
|
||||
if err != nil {
|
||||
if _, ok := err.(*auth.SigningKeyNotAvailable); !ok {
|
||||
log.Fatalf("Unable to create new token. The error is %v\n", err)
|
||||
}
|
||||
|
||||
log.Println("Signing key not available. Creating...")
|
||||
err := jwtAuth.GenerateSigningKey()
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to generate new signing key. The error is %v\n", err)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("%s\n", token)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var resetCmd = &cobra.Command{
|
||||
Use: "reset",
|
||||
Short: "Re-creates the secret key, which invalidate all tokens",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if !prompt.Confirm("Do you really want to invalidate all exists tokens?") {
|
||||
fmt.Println("Aboart.")
|
||||
return
|
||||
jwtAuth := &auth.JwtAuth{Key: []byte(viper.GetString("chrly.secret"))}
|
||||
token, err := jwtAuth.NewToken(auth.SkinScope)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to create new token. The error is %v\n", err)
|
||||
}
|
||||
|
||||
jwtAuth := &auth.JwtAuth{}
|
||||
if err := jwtAuth.GenerateSigningKey(); err != nil {
|
||||
log.Fatalf("Unable to generate new signing key. The error is %v\n", err)
|
||||
}
|
||||
|
||||
fmt.Println("Token successfully regenerated.")
|
||||
fmt.Printf("%s\n", token)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
tokenCmd.AddCommand(createCmd, resetCmd)
|
||||
RootCmd.AddCommand(tokenCmd)
|
||||
}
|
||||
|
@ -236,8 +236,8 @@ func apiBadRequest(resp http.ResponseWriter, errorsPerField map[string][]string)
|
||||
func apiForbidden(resp http.ResponseWriter, reason string) {
|
||||
resp.WriteHeader(http.StatusForbidden)
|
||||
resp.Header().Set("Content-Type", "application/json")
|
||||
result, _ := json.Marshal([]interface{}{
|
||||
reason,
|
||||
result, _ := json.Marshal(map[string]interface{}{
|
||||
"error": reason,
|
||||
})
|
||||
resp.Write(result)
|
||||
}
|
||||
|
@ -345,9 +345,9 @@ func TestConfig_PostSkin_Unauthorized(t *testing.T) {
|
||||
defer resp.Body.Close()
|
||||
assert.Equal(403, resp.StatusCode)
|
||||
response, _ := ioutil.ReadAll(resp.Body)
|
||||
assert.JSONEq(`[
|
||||
"Cannot parse passed JWT token"
|
||||
]`, string(response))
|
||||
assert.JSONEq(`{
|
||||
"error": "Cannot parse passed JWT token"
|
||||
}`, string(response))
|
||||
}
|
||||
|
||||
func TestConfig_DeleteSkinByUserId_Success(t *testing.T) {
|
||||
@ -475,18 +475,20 @@ func TestConfig_Authenticate_SignatureKeyNotSet(t *testing.T) {
|
||||
req := httptest.NewRequest("POST", "http://localhost", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
mocks.Auth.EXPECT().Check(gomock.Any()).Return(&auth.SigningKeyNotAvailable{})
|
||||
mocks.Log.EXPECT().Error("Unknown error on validating api request: :err", gomock.Any())
|
||||
mocks.Auth.EXPECT().Check(gomock.Any()).Return(&auth.Unauthorized{"signing key not available"})
|
||||
mocks.Log.EXPECT().IncCounter("authentication.challenge", int64(1))
|
||||
mocks.Log.EXPECT().IncCounter("authentication.failed", int64(1))
|
||||
|
||||
res := config.Authenticate(http.HandlerFunc(func (resp http.ResponseWriter, req *http.Request) {}))
|
||||
res.ServeHTTP(w, req)
|
||||
|
||||
resp := w.Result()
|
||||
defer resp.Body.Close()
|
||||
assert.Equal(500, resp.StatusCode)
|
||||
assert.Equal(403, resp.StatusCode)
|
||||
response, _ := ioutil.ReadAll(resp.Body)
|
||||
assert.Empty(response)
|
||||
assert.JSONEq(`{
|
||||
"error": "signing key not available"
|
||||
}`, string(response))
|
||||
}
|
||||
|
||||
// base64 https://github.com/mathiasbynens/small/blob/0ca3c51/png-transparent.png
|
||||
|
Loading…
Reference in New Issue
Block a user