2019-02-05 17:22:17 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2019-12-11 00:51:10 +00:00
|
|
|
"bufio"
|
2019-02-05 17:22:17 +00:00
|
|
|
"bytes"
|
2021-05-14 16:05:42 +01:00
|
|
|
"context"
|
2019-02-11 10:33:56 +00:00
|
|
|
"encoding/base64"
|
2019-02-05 17:22:17 +00:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2019-12-11 00:51:10 +00:00
|
|
|
"io"
|
|
|
|
"math/rand"
|
2019-02-05 17:22:17 +00:00
|
|
|
"net/http"
|
2020-08-19 13:43:56 +01:00
|
|
|
"strings"
|
2019-02-11 10:33:56 +00:00
|
|
|
"time"
|
2019-02-05 17:22:17 +00:00
|
|
|
|
|
|
|
"github.com/zeebo/errs"
|
2019-02-11 10:33:56 +00:00
|
|
|
|
2020-03-30 10:08:50 +01:00
|
|
|
"storj.io/common/uuid"
|
2019-02-11 10:33:56 +00:00
|
|
|
"storj.io/storj/satellite/console/consoleauth"
|
2020-08-19 13:43:56 +01:00
|
|
|
"storj.io/storj/satellite/payments"
|
2019-02-05 17:22:17 +00:00
|
|
|
)
|
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
func newConsoleEndpoints(address string) *consoleEndpoints {
|
|
|
|
return &consoleEndpoints{
|
2020-01-20 18:57:14 +00:00
|
|
|
client: http.DefaultClient,
|
|
|
|
base: "http://" + address,
|
|
|
|
cookieName: "_tokenKey",
|
2019-12-11 00:51:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type consoleEndpoints struct {
|
2020-01-20 18:57:14 +00:00
|
|
|
client *http.Client
|
|
|
|
base string
|
|
|
|
cookieName string
|
2019-12-11 00:51:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (ce *consoleEndpoints) appendPath(suffix string) string {
|
|
|
|
return ce.base + suffix
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ce *consoleEndpoints) RegToken() string {
|
|
|
|
return ce.appendPath("/registrationToken/?projectsLimit=1")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ce *consoleEndpoints) Register() string {
|
|
|
|
return ce.appendPath("/api/v0/auth/register")
|
|
|
|
}
|
|
|
|
|
2020-05-18 10:17:05 +01:00
|
|
|
func (ce *consoleEndpoints) SetupAccount() string {
|
|
|
|
return ce.appendPath("/api/v0/payments/account")
|
|
|
|
}
|
|
|
|
|
2020-08-19 13:43:56 +01:00
|
|
|
func (ce *consoleEndpoints) CreditCards() string {
|
|
|
|
return ce.appendPath("/api/v0/payments/cards")
|
|
|
|
}
|
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
func (ce *consoleEndpoints) Activation(token string) string {
|
2023-02-16 20:50:15 +00:00
|
|
|
return ce.appendPath("/activation?token=" + token)
|
2019-12-11 00:51:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (ce *consoleEndpoints) Token() string {
|
|
|
|
return ce.appendPath("/api/v0/auth/token")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ce *consoleEndpoints) GraphQL() string {
|
|
|
|
return ce.appendPath("/api/v0/graphql")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ce *consoleEndpoints) graphqlDo(request *http.Request, jsonResponse interface{}) error {
|
|
|
|
resp, err := ce.client.Do(request)
|
2019-02-05 17:22:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-12-11 00:51:10 +00:00
|
|
|
defer func() { err = errs.Combine(err, resp.Body.Close()) }()
|
2019-02-05 17:22:17 +00:00
|
|
|
|
2022-10-11 12:39:08 +01:00
|
|
|
b, err := io.ReadAll(resp.Body)
|
2019-02-05 17:22:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var response struct {
|
|
|
|
Data json.RawMessage
|
|
|
|
Errors []interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = json.NewDecoder(bytes.NewReader(b)).Decode(&response); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if response.Errors != nil {
|
2019-12-11 00:51:10 +00:00
|
|
|
return errs.New("inner graphql error: %v", response.Errors)
|
2019-02-05 17:22:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if jsonResponse == nil {
|
2019-12-11 00:51:10 +00:00
|
|
|
return errs.New("empty response: %q", b)
|
2019-02-05 17:22:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return json.NewDecoder(bytes.NewReader(response.Data)).Decode(jsonResponse)
|
|
|
|
}
|
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
func (ce *consoleEndpoints) createOrGetAPIKey(ctx context.Context) (string, error) {
|
|
|
|
authToken, err := ce.tryLogin(ctx)
|
2019-12-11 00:51:10 +00:00
|
|
|
if err != nil {
|
2021-05-14 16:05:42 +01:00
|
|
|
_ = ce.tryCreateAndActivateUser(ctx)
|
|
|
|
authToken, err = ce.tryLogin(ctx)
|
2019-12-11 00:51:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
2019-02-11 10:33:56 +00:00
|
|
|
}
|
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
err = ce.setupAccount(ctx, authToken)
|
2020-05-18 10:17:05 +01:00
|
|
|
if err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
err = ce.addCreditCard(ctx, authToken, "test")
|
2020-08-19 13:43:56 +01:00
|
|
|
if err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
cards, err := ce.listCreditCards(ctx, authToken)
|
2020-08-19 13:43:56 +01:00
|
|
|
if err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
|
|
|
if len(cards) == 0 {
|
|
|
|
return "", errs.New("no credit card(s) found")
|
|
|
|
}
|
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
err = ce.makeCreditCardDefault(ctx, authToken, cards[0].ID)
|
2020-08-19 13:43:56 +01:00
|
|
|
if err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
projectID, err := ce.getOrCreateProject(ctx, authToken)
|
2019-12-11 00:51:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
2019-02-11 10:33:56 +00:00
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
apiKey, err := ce.createAPIKey(ctx, authToken, projectID)
|
2019-02-11 10:33:56 +00:00
|
|
|
if err != nil {
|
2019-12-11 00:51:10 +00:00
|
|
|
return "", errs.Wrap(err)
|
2019-02-11 10:33:56 +00:00
|
|
|
}
|
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
return apiKey, nil
|
|
|
|
}
|
2019-02-11 10:33:56 +00:00
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
func (ce *consoleEndpoints) tryLogin(ctx context.Context) (string, error) {
|
2019-12-11 00:51:10 +00:00
|
|
|
var authToken struct {
|
|
|
|
Email string `json:"email"`
|
|
|
|
Password string `json:"password"`
|
|
|
|
}
|
|
|
|
|
|
|
|
authToken.Email = "alice@mail.test"
|
|
|
|
authToken.Password = "123a123"
|
|
|
|
|
|
|
|
res, err := json.Marshal(authToken)
|
2019-02-11 10:33:56 +00:00
|
|
|
if err != nil {
|
2019-12-11 00:51:10 +00:00
|
|
|
return "", errs.Wrap(err)
|
2019-02-11 10:33:56 +00:00
|
|
|
}
|
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
request, err := http.NewRequestWithContext(
|
|
|
|
ctx,
|
2019-12-11 00:51:10 +00:00
|
|
|
http.MethodPost,
|
|
|
|
ce.Token(),
|
|
|
|
bytes.NewReader(res))
|
|
|
|
if err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
2019-02-11 10:33:56 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
request.Header.Add("Content-Type", "application/json")
|
2019-02-11 10:33:56 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
resp, err := ce.client.Do(request)
|
|
|
|
if err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
|
|
|
defer func() { err = errs.Combine(err, resp.Body.Close()) }()
|
2019-02-05 17:22:17 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
return "", errs.New("unexpected status code: %d (%q)",
|
|
|
|
resp.StatusCode, tryReadLine(resp.Body))
|
2019-03-19 17:55:43 +00:00
|
|
|
}
|
|
|
|
|
2022-07-19 10:26:18 +01:00
|
|
|
var tokenInfo struct {
|
|
|
|
Token string `json:"token"`
|
|
|
|
}
|
|
|
|
err = json.NewDecoder(resp.Body).Decode(&tokenInfo)
|
2019-12-11 00:51:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
2019-03-19 17:55:43 +00:00
|
|
|
|
2022-07-19 10:26:18 +01:00
|
|
|
return tokenInfo.Token, nil
|
2019-12-11 00:51:10 +00:00
|
|
|
}
|
2019-03-19 17:55:43 +00:00
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
func (ce *consoleEndpoints) tryCreateAndActivateUser(ctx context.Context) error {
|
|
|
|
regToken, err := ce.createRegistrationToken(ctx)
|
2019-12-11 00:51:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return errs.Wrap(err)
|
|
|
|
}
|
2021-05-14 16:05:42 +01:00
|
|
|
userID, err := ce.createUser(ctx, regToken)
|
2019-12-11 00:51:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return errs.Wrap(err)
|
|
|
|
}
|
2021-05-14 16:05:42 +01:00
|
|
|
return errs.Wrap(ce.activateUser(ctx, userID))
|
2019-12-11 00:51:10 +00:00
|
|
|
}
|
2019-03-19 17:55:43 +00:00
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
func (ce *consoleEndpoints) createRegistrationToken(ctx context.Context) (string, error) {
|
|
|
|
request, err := http.NewRequestWithContext(
|
|
|
|
ctx,
|
2019-12-11 00:51:10 +00:00
|
|
|
http.MethodGet,
|
|
|
|
ce.RegToken(),
|
|
|
|
nil)
|
|
|
|
if err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
2019-03-19 17:55:43 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
resp, err := ce.client.Do(request)
|
|
|
|
if err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
2019-03-19 17:55:43 +00:00
|
|
|
}
|
2019-12-11 00:51:10 +00:00
|
|
|
defer func() { err = errs.Combine(err, resp.Body.Close()) }()
|
2019-03-19 17:55:43 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
return "", errs.New("unexpected status code: %d (%q)",
|
|
|
|
resp.StatusCode, tryReadLine(resp.Body))
|
2019-02-11 10:33:56 +00:00
|
|
|
}
|
2019-11-22 17:03:15 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
var createTokenResponse struct {
|
|
|
|
Secret string
|
|
|
|
Error string
|
|
|
|
}
|
|
|
|
if err = json.NewDecoder(resp.Body).Decode(&createTokenResponse); err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
|
|
|
if createTokenResponse.Error != "" {
|
|
|
|
return "", errs.New("unable to create registration token: %s", createTokenResponse.Error)
|
|
|
|
}
|
2019-11-22 17:03:15 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
return createTokenResponse.Secret, nil
|
|
|
|
}
|
2019-02-05 17:22:17 +00:00
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
func (ce *consoleEndpoints) createUser(ctx context.Context, regToken string) (string, error) {
|
2019-12-11 00:51:10 +00:00
|
|
|
var registerData struct {
|
|
|
|
FullName string `json:"fullName"`
|
|
|
|
ShortName string `json:"shortName"`
|
|
|
|
Email string `json:"email"`
|
|
|
|
Password string `json:"password"`
|
|
|
|
Secret string `json:"secret"`
|
|
|
|
}
|
2019-02-05 17:22:17 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
registerData.FullName = "Alice"
|
|
|
|
registerData.Email = "alice@mail.test"
|
|
|
|
registerData.Password = "123a123"
|
|
|
|
registerData.ShortName = "al"
|
|
|
|
registerData.Secret = regToken
|
2019-02-05 17:22:17 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
res, err := json.Marshal(registerData)
|
|
|
|
if err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
2019-11-22 17:03:15 +00:00
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
request, err := http.NewRequestWithContext(
|
|
|
|
ctx,
|
2019-12-11 00:51:10 +00:00
|
|
|
http.MethodPost,
|
|
|
|
ce.Register(),
|
|
|
|
bytes.NewReader(res))
|
|
|
|
if err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
|
|
|
request.Header.Add("Content-Type", "application/json")
|
2019-11-22 17:03:15 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
resp, err := ce.client.Do(request)
|
|
|
|
if err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
|
|
|
defer func() { err = errs.Combine(err, resp.Body.Close()) }()
|
2019-11-22 17:03:15 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
return "", errs.New("unexpected status code: %d (%q)",
|
|
|
|
resp.StatusCode, tryReadLine(resp.Body))
|
2019-02-05 17:22:17 +00:00
|
|
|
}
|
2019-11-22 17:03:15 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
var userID string
|
|
|
|
if err = json.NewDecoder(resp.Body).Decode(&userID); err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
2019-02-11 10:33:56 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
return userID, nil
|
|
|
|
}
|
2019-02-11 10:33:56 +00:00
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
func (ce *consoleEndpoints) activateUser(ctx context.Context, userID string) error {
|
2020-04-02 13:30:43 +01:00
|
|
|
userUUID, err := uuid.FromString(userID)
|
2019-12-11 00:51:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return errs.Wrap(err)
|
|
|
|
}
|
2019-03-08 14:01:11 +00:00
|
|
|
|
2020-04-02 13:30:43 +01:00
|
|
|
activationToken, err := generateActivationKey(userUUID, "alice@mail.test", time.Now())
|
2019-12-11 00:51:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-03-08 14:01:11 +00:00
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
request, err := http.NewRequestWithContext(
|
|
|
|
ctx,
|
2019-12-11 00:51:10 +00:00
|
|
|
http.MethodGet,
|
|
|
|
ce.Activation(activationToken),
|
|
|
|
nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-11-22 17:03:15 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
resp, err := ce.client.Do(request)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer func() { err = errs.Combine(err, resp.Body.Close()) }()
|
2019-03-08 14:01:11 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
return errs.New("unexpected status code: %d (%q)",
|
|
|
|
resp.StatusCode, tryReadLine(resp.Body))
|
|
|
|
}
|
2019-11-22 17:03:15 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
return nil
|
|
|
|
}
|
2019-03-08 14:01:11 +00:00
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
func (ce *consoleEndpoints) setupAccount(ctx context.Context, token string) error {
|
|
|
|
request, err := http.NewRequestWithContext(
|
|
|
|
ctx,
|
2020-05-18 10:17:05 +01:00
|
|
|
http.MethodPost,
|
|
|
|
ce.SetupAccount(),
|
|
|
|
nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
request.AddCookie(&http.Cookie{
|
|
|
|
Name: ce.cookieName,
|
|
|
|
Value: token,
|
|
|
|
})
|
|
|
|
|
|
|
|
resp, err := ce.client.Do(request)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer func() { err = errs.Combine(err, resp.Body.Close()) }()
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
return errs.New("unexpected status code: %d (%q)",
|
|
|
|
resp.StatusCode, tryReadLine(resp.Body))
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
func (ce *consoleEndpoints) addCreditCard(ctx context.Context, token, cctoken string) error {
|
|
|
|
request, err := http.NewRequestWithContext(
|
|
|
|
ctx,
|
2020-08-19 13:43:56 +01:00
|
|
|
http.MethodPost,
|
|
|
|
ce.CreditCards(),
|
|
|
|
strings.NewReader(cctoken))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
request.AddCookie(&http.Cookie{
|
|
|
|
Name: ce.cookieName,
|
|
|
|
Value: token,
|
|
|
|
})
|
|
|
|
|
|
|
|
resp, err := ce.client.Do(request)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer func() { err = errs.Combine(err, resp.Body.Close()) }()
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
return errs.New("unexpected status code: %d (%q)",
|
|
|
|
resp.StatusCode, tryReadLine(resp.Body))
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
func (ce *consoleEndpoints) listCreditCards(ctx context.Context, token string) ([]payments.CreditCard, error) {
|
|
|
|
request, err := http.NewRequestWithContext(
|
|
|
|
ctx,
|
2020-08-19 13:43:56 +01:00
|
|
|
http.MethodGet,
|
|
|
|
ce.CreditCards(),
|
|
|
|
nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
request.AddCookie(&http.Cookie{
|
|
|
|
Name: ce.cookieName,
|
|
|
|
Value: token,
|
|
|
|
})
|
|
|
|
|
|
|
|
resp, err := ce.client.Do(request)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer func() { err = errs.Combine(err, resp.Body.Close()) }()
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
return nil, errs.New("unexpected status code: %d (%q)",
|
|
|
|
resp.StatusCode, tryReadLine(resp.Body))
|
|
|
|
}
|
|
|
|
|
|
|
|
var list []payments.CreditCard
|
|
|
|
|
|
|
|
decoder := json.NewDecoder(resp.Body)
|
|
|
|
err = decoder.Decode(&list)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return list, nil
|
|
|
|
}
|
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
func (ce *consoleEndpoints) makeCreditCardDefault(ctx context.Context, token, ccID string) error {
|
|
|
|
request, err := http.NewRequestWithContext(
|
|
|
|
ctx,
|
2020-08-19 13:43:56 +01:00
|
|
|
http.MethodPatch,
|
|
|
|
ce.CreditCards(),
|
|
|
|
strings.NewReader(ccID))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
request.AddCookie(&http.Cookie{
|
|
|
|
Name: ce.cookieName,
|
|
|
|
Value: token,
|
|
|
|
})
|
|
|
|
|
|
|
|
resp, err := ce.client.Do(request)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer func() { err = errs.Combine(err, resp.Body.Close()) }()
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
return errs.New("unexpected status code: %d (%q)",
|
|
|
|
resp.StatusCode, tryReadLine(resp.Body))
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
func (ce *consoleEndpoints) getOrCreateProject(ctx context.Context, token string) (string, error) {
|
|
|
|
projectID, err := ce.getProject(ctx, token)
|
2019-12-11 00:51:10 +00:00
|
|
|
if err == nil {
|
|
|
|
return projectID, nil
|
|
|
|
}
|
2021-05-14 16:05:42 +01:00
|
|
|
projectID, err = ce.createProject(ctx, token)
|
2019-12-11 00:51:10 +00:00
|
|
|
if err == nil {
|
|
|
|
return projectID, nil
|
|
|
|
}
|
2021-05-14 16:05:42 +01:00
|
|
|
return ce.getProject(ctx, token)
|
2019-12-11 00:51:10 +00:00
|
|
|
}
|
2019-02-05 17:22:17 +00:00
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
func (ce *consoleEndpoints) getProject(ctx context.Context, token string) (string, error) {
|
|
|
|
request, err := http.NewRequestWithContext(
|
|
|
|
ctx,
|
2019-12-11 00:51:10 +00:00
|
|
|
http.MethodGet,
|
|
|
|
ce.GraphQL(),
|
|
|
|
nil)
|
|
|
|
if err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
2019-11-22 17:03:15 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
q := request.URL.Query()
|
|
|
|
q.Add("query", `query {myProjects{id}}`)
|
|
|
|
request.URL.RawQuery = q.Encode()
|
2019-02-05 17:22:17 +00:00
|
|
|
|
2020-01-20 18:57:14 +00:00
|
|
|
request.AddCookie(&http.Cookie{
|
|
|
|
Name: ce.cookieName,
|
|
|
|
Value: token,
|
|
|
|
})
|
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
request.Header.Add("Content-Type", "application/graphql")
|
2019-02-05 17:22:17 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
var getProjects struct {
|
|
|
|
MyProjects []struct {
|
|
|
|
ID string
|
2019-11-22 17:03:15 +00:00
|
|
|
}
|
2019-12-11 00:51:10 +00:00
|
|
|
}
|
|
|
|
if err := ce.graphqlDo(request, &getProjects); err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
|
|
|
if len(getProjects.MyProjects) == 0 {
|
|
|
|
return "", errs.New("no projects")
|
|
|
|
}
|
2019-11-22 17:03:15 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
return getProjects.MyProjects[0].ID, nil
|
|
|
|
}
|
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
func (ce *consoleEndpoints) createProject(ctx context.Context, token string) (string, error) {
|
2019-12-11 00:51:10 +00:00
|
|
|
rng := rand.NewSource(time.Now().UnixNano())
|
|
|
|
createProjectQuery := fmt.Sprintf(
|
|
|
|
`mutation {createProject(input:{name:"TestProject-%d",description:""}){id}}`,
|
|
|
|
rng.Int63())
|
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
request, err := http.NewRequestWithContext(
|
|
|
|
ctx,
|
2019-12-11 00:51:10 +00:00
|
|
|
http.MethodPost,
|
|
|
|
ce.GraphQL(),
|
|
|
|
bytes.NewReader([]byte(createProjectQuery)))
|
|
|
|
if err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
2019-02-05 17:22:17 +00:00
|
|
|
}
|
|
|
|
|
2020-01-20 18:57:14 +00:00
|
|
|
request.AddCookie(&http.Cookie{
|
|
|
|
Name: ce.cookieName,
|
|
|
|
Value: token,
|
|
|
|
})
|
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
request.Header.Add("Content-Type", "application/graphql")
|
|
|
|
|
2019-02-05 17:22:17 +00:00
|
|
|
var createProject struct {
|
|
|
|
CreateProject struct {
|
|
|
|
ID string
|
|
|
|
}
|
|
|
|
}
|
2019-12-11 00:51:10 +00:00
|
|
|
if err := ce.graphqlDo(request, &createProject); err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
2019-02-05 17:22:17 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
return createProject.CreateProject.ID, nil
|
|
|
|
}
|
2019-02-05 17:22:17 +00:00
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
func (ce *consoleEndpoints) createAPIKey(ctx context.Context, token, projectID string) (string, error) {
|
2019-12-11 00:51:10 +00:00
|
|
|
rng := rand.NewSource(time.Now().UnixNano())
|
|
|
|
createAPIKeyQuery := fmt.Sprintf(
|
|
|
|
`mutation {createAPIKey(projectID:%q,name:"TestKey-%d"){key}}`,
|
|
|
|
projectID, rng.Int63())
|
2019-02-05 17:22:17 +00:00
|
|
|
|
2021-05-14 16:05:42 +01:00
|
|
|
request, err := http.NewRequestWithContext(
|
|
|
|
ctx,
|
2019-12-11 00:51:10 +00:00
|
|
|
http.MethodPost,
|
|
|
|
ce.GraphQL(),
|
|
|
|
bytes.NewReader([]byte(createAPIKeyQuery)))
|
|
|
|
if err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
2019-02-05 17:22:17 +00:00
|
|
|
}
|
|
|
|
|
2020-01-20 18:57:14 +00:00
|
|
|
request.AddCookie(&http.Cookie{
|
|
|
|
Name: ce.cookieName,
|
|
|
|
Value: token,
|
|
|
|
})
|
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
request.Header.Add("Content-Type", "application/graphql")
|
|
|
|
|
2019-02-05 17:22:17 +00:00
|
|
|
var createAPIKey struct {
|
|
|
|
CreateAPIKey struct {
|
|
|
|
Key string
|
|
|
|
}
|
|
|
|
}
|
2019-12-11 00:51:10 +00:00
|
|
|
if err := ce.graphqlDo(request, &createAPIKey); err != nil {
|
|
|
|
return "", errs.Wrap(err)
|
|
|
|
}
|
2019-02-05 17:22:17 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
return createAPIKey.CreateAPIKey.Key, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func generateActivationKey(userID uuid.UUID, email string, createdAt time.Time) (string, error) {
|
|
|
|
claims := consoleauth.Claims{
|
|
|
|
ID: userID,
|
|
|
|
Email: email,
|
|
|
|
Expiration: createdAt.Add(24 * time.Hour),
|
|
|
|
}
|
2019-02-05 17:22:17 +00:00
|
|
|
|
2019-12-11 00:51:10 +00:00
|
|
|
// TODO: change it in future, when satellite/console secret will be changed
|
|
|
|
signer := &consoleauth.Hmac{Secret: []byte("my-suppa-secret-key")}
|
2019-02-05 17:22:17 +00:00
|
|
|
|
2020-08-19 13:43:56 +01:00
|
|
|
resJSON, err := claims.JSON()
|
2019-12-11 00:51:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
2019-02-05 17:22:17 +00:00
|
|
|
}
|
|
|
|
|
2020-08-19 13:43:56 +01:00
|
|
|
token := consoleauth.Token{Payload: resJSON}
|
2019-12-11 00:51:10 +00:00
|
|
|
encoded := base64.URLEncoding.EncodeToString(token.Payload)
|
|
|
|
|
|
|
|
signature, err := signer.Sign([]byte(encoded))
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
token.Signature = signature
|
|
|
|
|
|
|
|
return token.String(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func tryReadLine(r io.Reader) string {
|
|
|
|
scanner := bufio.NewScanner(r)
|
|
|
|
scanner.Scan()
|
|
|
|
return scanner.Text()
|
2019-02-05 17:22:17 +00:00
|
|
|
}
|