/
statika.go
136 lines (113 loc) · 2.96 KB
/
statika.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package api
import (
"encoding/json"
"fmt"
"github.com/cristalhq/jwt/v3"
"github.com/go-resty/resty/v2"
. "github.com/raver119/statika/wt"
"net/http"
)
/*
This "class" provides methods for tokens management
*/
type GateKeeper struct {
restClient *resty.Client
endpoint string
masterKey string
uploadKey string
}
/*
This function creates new Statika GateKeeper client, it's responsible
*/
func NewGateKeeper(endpoint string, masterKey string, uploadKey string) (GateKeeper, error) {
rc := resty.New()
return GateKeeper{
restClient: rc,
endpoint: endpoint,
masterKey: masterKey,
uploadKey: uploadKey,
}, nil
}
// IssueClient This method gets new upload token from Statika server, and returns a client instance with this token
func (gk GateKeeper) IssueClient(bucket string) (Client, error) {
token, err := gk.IssueUploadToken(bucket)
if err != nil {
return Client{}, err
}
return Client{
uploadToken: token,
bucket: bucket,
endpoint: gk.endpoint,
resty: gk.restClient,
}, nil
}
// NewClient This method creates new client with existing upload token
func (gk GateKeeper) NewClient(bucket string, uploadToken UploadToken) (Client, error) {
return Client{
uploadToken: uploadToken,
bucket: bucket,
endpoint: gk.endpoint,
resty: gk.restClient,
}, nil
}
func (gk GateKeeper) NewMultiClient(uploadToken UploadToken, buckets ...string) (MultiClient, error) {
// validate buckets
tkn, err := jwt.ParseString(string(uploadToken))
if err != nil {
return MultiClient{}, err
}
var claims UploadClaims
err = json.Unmarshal(tkn.RawClaims(), &claims)
if err != nil {
return MultiClient{}, err
}
exists := func(needle string, haystack []string) bool {
for _, h := range haystack {
if h == needle {
return true
}
}
return false
}
for _, qb := range buckets {
if !exists(qb, claims.Buckets) {
return MultiClient{}, fmt.Errorf("non-approved bucket was requested")
}
}
return MultiClient{
endpoint: gk.endpoint,
uploadToken: uploadToken,
buckets: buckets,
resty: gk.restClient,
}, nil
}
func (gk GateKeeper) IssueUploadToken(bucket ...string) (token UploadToken, err error) {
endpoint := fmt.Sprintf("%v/rest/v1/auth/upload", gk.endpoint)
client := resty.New()
upReq := UploadAuthenticationRequest{
Token: gk.uploadKey,
Buckets: bucket,
}
resp, err := client.R().
SetBody(upReq).
Post(endpoint)
if err != nil {
return
}
if resp.StatusCode() == http.StatusUnauthorized {
err = fmt.Errorf("statika authentication failed: bad token")
return
}
if resp.StatusCode() != http.StatusOK {
err = fmt.Errorf("statika request failed with statusCode %v; message: [%v]", resp.StatusCode(), resp.String())
return
}
var response AuthenticationResponse
err = json.Unmarshal(resp.Body(), &response)
if resp.StatusCode() != http.StatusOK {
err = fmt.Errorf("statika authentication failed: JSON versions mismatch")
return
}
token = UploadToken(response.Token)
return
}