mirror of
https://github.com/elyby/chrly.git
synced 2025-01-11 14:22:14 +05:30
Восстановлена логика для доступна к internal API Accounts Ely.by
This commit is contained in:
parent
b1dbee2310
commit
4734bfd93c
81
Gopkg.lock
generated
81
Gopkg.lock
generated
@ -2,16 +2,28 @@
|
|||||||
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
name = "github.com/davecgh/go-spew"
|
||||||
name = "github.com/fsnotify/fsnotify"
|
packages = ["spew"]
|
||||||
packages = ["."]
|
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||||
revision = "4da3e2cfbabc9f751898f250b49f2439785783a1"
|
version = "v1.1.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/fsnotify/fsnotify"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "629574ca2a5df945712d3079857300b5e4da0236"
|
||||||
|
version = "v1.4.2"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/golang/mock"
|
||||||
|
packages = ["gomock"]
|
||||||
|
revision = "13f360950a79f5864a972c786a10a50e44b69541"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
|
||||||
name = "github.com/gorilla/context"
|
name = "github.com/gorilla/context"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42"
|
revision = "1ea25387ff6f684839d82767c1733ff4d4d15d0a"
|
||||||
|
version = "v1.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/gorilla/mux"
|
name = "github.com/gorilla/mux"
|
||||||
@ -34,12 +46,14 @@
|
|||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/magiconair/properties"
|
name = "github.com/magiconair/properties"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "51463bfca2576e06c62a8504b5c0f06d61312647"
|
revision = "be5ece7dd465ab0765a9682137865547526d1dfb"
|
||||||
|
version = "v1.7.3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
name = "github.com/mediocregopher/radix.v2"
|
name = "github.com/mediocregopher/radix.v2"
|
||||||
packages = ["cluster","pool","redis","util"]
|
packages = ["cluster","pool","redis","util"]
|
||||||
revision = "dbcfd490034f823788edc555737247e9ba628b6c"
|
revision = "ae7309086d191442b36bf69f7f5eeca5fdbd329e"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@ -60,10 +74,22 @@
|
|||||||
revision = "a064bd7e3acfda563ea680b913b9ef24b7a73e15"
|
revision = "a064bd7e3acfda563ea680b913b9ef24b7a73e15"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
name = "github.com/pelletier/go-buffruneio"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "c37440a7cf42ac63b919c752ca73a85067e05992"
|
||||||
|
version = "v0.2.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
name = "github.com/pelletier/go-toml"
|
name = "github.com/pelletier/go-toml"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "69d355db5304c0f7f809a2edc054553e7142f016"
|
revision = "5ccdfb18c776b740aecaf085c4d9a2779199c279"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/pmezard/go-difflib"
|
||||||
|
packages = ["difflib"]
|
||||||
|
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@ -78,9 +104,10 @@
|
|||||||
version = "v1.1.0"
|
version = "v1.1.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
name = "github.com/spf13/cobra"
|
name = "github.com/spf13/cobra"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "4d647c8944eb42504a714e57e97f244ed6344722"
|
revision = "cb731b898346822cc0c225c28550a8a29d93c732"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@ -95,28 +122,50 @@
|
|||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
name = "github.com/spf13/viper"
|
name = "github.com/spf13/viper"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "c1de95864d73a5465492829d7cb2dd422b19ac96"
|
revision = "25b30aa063fc18e48662b86996252eabdcf2f0c7"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/streadway/amqp"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "2cbfe40c9341ad63ba23e53013b3ddc7989d801c"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/stretchr/testify"
|
||||||
|
packages = ["assert"]
|
||||||
|
revision = "69483b4bd14f5845b5a1e55bca19e954e827f1d0"
|
||||||
|
version = "v1.1.4"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
name = "golang.org/x/sys"
|
name = "golang.org/x/sys"
|
||||||
packages = ["unix"]
|
packages = ["unix"]
|
||||||
revision = "90796e5a05ce440b41c768bd9af257005e470461"
|
revision = "9f7170bcd8e9f4d3691c06401119c46a769a1e03"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
name = "golang.org/x/text"
|
name = "golang.org/x/text"
|
||||||
packages = ["internal/gen","internal/triegen","internal/ucd","transform","unicode/cldr","unicode/norm"]
|
packages = ["internal/gen","internal/triegen","internal/ucd","transform","unicode/cldr","unicode/norm"]
|
||||||
revision = "2bf8f2a19ec09c670e931282edfe6567f6be21c9"
|
revision = "e56139fd9c5bc7244c76116c68e500765bb6db6b"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
name = "gopkg.in/h2non/gock.v1"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "84d599244901620fb3eb96473eb9e50619f69b47"
|
||||||
|
version = "v1.0.6"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "v2"
|
||||||
name = "gopkg.in/yaml.v2"
|
name = "gopkg.in/yaml.v2"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b"
|
revision = "eb3733d160e74a9c7e442f435eb3bea458e1d19f"
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "ec0031edfe5ff25a05e871c72a7ae46c52cefad9f1a9fe5bb54c1b293f965c89"
|
inputs-digest = "a224232f222d77ae5bbdce4248f82a031590b863a6f34f2dd7350ffd330278e6"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
14
Gopkg.toml
14
Gopkg.toml
@ -18,3 +18,17 @@ ignored = ["elyby/minecraft-skinsystem"]
|
|||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/streadway/amqp"
|
name = "github.com/streadway/amqp"
|
||||||
|
|
||||||
|
# Testing dependencies
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/stretchr/testify"
|
||||||
|
version = "^1.1.4"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/golang/mock"
|
||||||
|
version = "^1.0.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "gopkg.in/h2non/gock.v1"
|
||||||
|
version = "^1.0.6"
|
||||||
|
166
api/accounts/accounts.go
Normal file
166
api/accounts/accounts.go
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
package accounts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Addr string
|
||||||
|
Id string
|
||||||
|
Secret string
|
||||||
|
Scopes []string
|
||||||
|
|
||||||
|
Client *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type Token struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
TokenType string `json:"token_type"`
|
||||||
|
ExpiresIn int `json:"expires_in"`
|
||||||
|
config *Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config *Config) GetToken() (*Token, error) {
|
||||||
|
form := url.Values{}
|
||||||
|
form.Add("client_id", config.Id)
|
||||||
|
form.Add("client_secret", config.Secret)
|
||||||
|
form.Add("grant_type", "client_credentials")
|
||||||
|
form.Add("scope", strings.Join(config.Scopes, ","))
|
||||||
|
|
||||||
|
response, err := config.getHttpClient().Post(config.getTokenUrl(), "application/x-www-form-urlencoded", strings.NewReader(form.Encode()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
var result *Token
|
||||||
|
responseError := handleResponse(response)
|
||||||
|
if responseError != nil {
|
||||||
|
return nil, responseError
|
||||||
|
}
|
||||||
|
|
||||||
|
body, _ := ioutil.ReadAll(response.Body)
|
||||||
|
unmarshalError := json.Unmarshal(body, &result)
|
||||||
|
if unmarshalError != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result.config = config
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config *Config) getTokenUrl() string {
|
||||||
|
return concatenateHostAndPath(config.Addr, "/api/oauth2/v1/token")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config *Config) getHttpClient() *http.Client {
|
||||||
|
if config.Client == nil {
|
||||||
|
config.Client = &http.Client{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return config.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccountInfoResponse struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
Uuid string `json:"uuid"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (token *Token) AccountInfo(attribute string, value string) (*AccountInfoResponse, error) {
|
||||||
|
request := token.newRequest("GET", token.accountInfoUrl(), nil)
|
||||||
|
|
||||||
|
query := request.URL.Query()
|
||||||
|
query.Add(attribute, value)
|
||||||
|
request.URL.RawQuery = query.Encode()
|
||||||
|
|
||||||
|
response, err := token.config.Client.Do(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
var info *AccountInfoResponse
|
||||||
|
|
||||||
|
responseError := handleResponse(response)
|
||||||
|
if responseError != nil {
|
||||||
|
return nil, responseError
|
||||||
|
}
|
||||||
|
|
||||||
|
body, _ := ioutil.ReadAll(response.Body)
|
||||||
|
json.Unmarshal(body, &info)
|
||||||
|
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (token *Token) accountInfoUrl() string {
|
||||||
|
return concatenateHostAndPath(token.config.Addr, "/api/internal/accounts/info")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (token *Token) newRequest(method string, urlStr string, body io.Reader) *http.Request {
|
||||||
|
request, err := http.NewRequest(method, urlStr, body)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
request.Header.Add("Authorization", "Bearer " + token.AccessToken)
|
||||||
|
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
func concatenateHostAndPath(host string, pathToJoin string) string {
|
||||||
|
u, _ := url.Parse(host)
|
||||||
|
u.Path = path.Join(u.Path, pathToJoin)
|
||||||
|
|
||||||
|
return u.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
type UnauthorizedResponse struct {}
|
||||||
|
|
||||||
|
func (err UnauthorizedResponse) Error() string {
|
||||||
|
return "Unauthorized response"
|
||||||
|
}
|
||||||
|
|
||||||
|
type ForbiddenResponse struct {}
|
||||||
|
|
||||||
|
func (err ForbiddenResponse) Error() string {
|
||||||
|
return "Forbidden response"
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotFoundResponse struct {}
|
||||||
|
|
||||||
|
func (err NotFoundResponse) Error() string {
|
||||||
|
return "Not found"
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotSuccessResponse struct {
|
||||||
|
StatusCode int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err NotSuccessResponse) Error() string {
|
||||||
|
return fmt.Sprintf("Response code is \"%d\"", err.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleResponse(response *http.Response) error {
|
||||||
|
switch status := response.StatusCode; status {
|
||||||
|
case 200:
|
||||||
|
return nil
|
||||||
|
case 401:
|
||||||
|
return &UnauthorizedResponse{}
|
||||||
|
case 403:
|
||||||
|
return &ForbiddenResponse{}
|
||||||
|
case 404:
|
||||||
|
return &NotFoundResponse{}
|
||||||
|
default:
|
||||||
|
return &NotSuccessResponse{status}
|
||||||
|
}
|
||||||
|
}
|
98
api/accounts/accounts_test.go
Normal file
98
api/accounts/accounts_test.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package accounts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
testify "github.com/stretchr/testify/assert"
|
||||||
|
"gopkg.in/h2non/gock.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConfig_GetToken(t *testing.T) {
|
||||||
|
assert := testify.New(t)
|
||||||
|
|
||||||
|
defer gock.Off()
|
||||||
|
gock.New("https://account.ely.by").
|
||||||
|
Post("/api/oauth2/v1/token").
|
||||||
|
Body(strings.NewReader("client_id=mock-id&client_secret=mock-secret&grant_type=client_credentials&scope=scope1%2Cscope2")).
|
||||||
|
Reply(200).
|
||||||
|
JSON(map[string]interface{}{
|
||||||
|
"access_token": "mocked-token",
|
||||||
|
"token_type": "Bearer",
|
||||||
|
"expires_in": 86400,
|
||||||
|
})
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
gock.InterceptClient(client)
|
||||||
|
|
||||||
|
config := &Config{
|
||||||
|
Addr: "https://account.ely.by",
|
||||||
|
Id: "mock-id",
|
||||||
|
Secret: "mock-secret",
|
||||||
|
Scopes: []string{"scope1", "scope2"},
|
||||||
|
Client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := config.GetToken()
|
||||||
|
if assert.NoError(err) {
|
||||||
|
assert.Equal("mocked-token", result.AccessToken)
|
||||||
|
assert.Equal("Bearer", result.TokenType)
|
||||||
|
assert.Equal(86400, result.ExpiresIn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToken_AccountInfo(t *testing.T) {
|
||||||
|
assert := testify.New(t)
|
||||||
|
|
||||||
|
defer gock.Off()
|
||||||
|
// To test valid behavior
|
||||||
|
gock.New("https://account.ely.by").
|
||||||
|
Get("/api/internal/accounts/info").
|
||||||
|
MatchParam("id", "1").
|
||||||
|
MatchHeader("Authorization", "Bearer mock-token").
|
||||||
|
Reply(200).
|
||||||
|
JSON(map[string]interface{}{
|
||||||
|
"id": 1,
|
||||||
|
"uuid": "0f657aa8-bfbe-415d-b700-5750090d3af3",
|
||||||
|
"username": "dummy",
|
||||||
|
"email": "dummy@ely.by",
|
||||||
|
})
|
||||||
|
|
||||||
|
// To test behavior on invalid or expired token
|
||||||
|
gock.New("https://account.ely.by").
|
||||||
|
Get("/api/internal/accounts/info").
|
||||||
|
MatchParam("id", "1").
|
||||||
|
MatchHeader("Authorization", "Bearer mock-token").
|
||||||
|
Reply(401).
|
||||||
|
JSON(map[string]interface{}{
|
||||||
|
"name": "Unauthorized",
|
||||||
|
"message": "Incorrect token",
|
||||||
|
"code": 0,
|
||||||
|
"status": 401,
|
||||||
|
})
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
gock.InterceptClient(client)
|
||||||
|
|
||||||
|
token := &Token{
|
||||||
|
AccessToken: "mock-token",
|
||||||
|
config: &Config{
|
||||||
|
Addr: "https://account.ely.by",
|
||||||
|
Client: client,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := token.AccountInfo("id", "1")
|
||||||
|
if assert.NoError(err) {
|
||||||
|
assert.Equal(1, result.Id)
|
||||||
|
assert.Equal("0f657aa8-bfbe-415d-b700-5750090d3af3", result.Uuid)
|
||||||
|
assert.Equal("dummy", result.Username)
|
||||||
|
assert.Equal("dummy@ely.by", result.Email)
|
||||||
|
}
|
||||||
|
|
||||||
|
result2, err2 := token.AccountInfo("id", "1")
|
||||||
|
assert.Nil(result2)
|
||||||
|
assert.Error(err2)
|
||||||
|
assert.IsType(&UnauthorizedResponse{}, err2)
|
||||||
|
}
|
9
interfaces/api.go
Normal file
9
interfaces/api.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package interfaces
|
||||||
|
|
||||||
|
import (
|
||||||
|
"elyby/minecraft-skinsystem/api/accounts"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AccountsAPI interface {
|
||||||
|
AccountInfo(attribute string, value string) (*accounts.AccountInfoResponse, error)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user