Skip to content

Commit

Permalink
Merge pull request #23 from moonstream-to/resource-control
Browse files Browse the repository at this point in the history
Restrict access to request signatures with resources
  • Loading branch information
kompotkot authored Dec 14, 2023
2 parents 7b9a52a + e212591 commit 3b1daea
Show file tree
Hide file tree
Showing 8 changed files with 300 additions and 40 deletions.
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,18 @@ go test ./... -v

The Waggle API Server Extension is designed to offer a RESTfull API access for `waggle` functionalities. It builds over existing waggle features, enhancing operational efficiency and automating routine tasks.

Executes `sign dropper` functionalities such as certifying drop claims for Dropper v0.2.0 by sending POST requests:
List available signers at waggle server:

```bash
curl "http://127.0.0.1:7379/signers"
```

Executes `sign dropper` functionalities such as certifying drop claims for Dropper v0.2.0 by sending POST requests to `http://127.0.0.1:7379/signers/<signer_address>/sign/dropper`:

```json
{
"chain_id": 80001,
"dropper": "0x4ec36E288E1b5d6914851a141cb041152Cf95328",
"signer": "0x629c51488a18fc75f4b8993743f3c132316951c9",
"requests": [
{
"dropId": "2",
Expand Down Expand Up @@ -290,3 +295,5 @@ Run server:
```bash
waggle server run --host 0.0.0.0 --config config.json
```

Fetch
137 changes: 137 additions & 0 deletions bugout.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,51 @@ package main
// Much of this code is copied from waggle: https://github.com/bugout-dev/waggle/blob/main/main.go

import (
"bytes"
"encoding/csv"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strconv"
"strings"
"time"

bugout "github.com/bugout-dev/bugout-go/pkg"
spire "github.com/bugout-dev/bugout-go/pkg/spire"
)

type BugoutAPIClient struct {
BroodBaseURL string
SpireBaseURL string
HTTPClient *http.Client
}

func InitBugoutAPIClient() (*BugoutAPIClient, error) {
if BROOD_API_URL == "" {
BROOD_API_URL = "https://auth.bugout.dev"
}
if SPIRE_API_URL == "" {
SPIRE_API_URL = "https://spire.bugout.dev"
}
if BUGOUT_API_TIMEOUT_SECONDS == "" {
BUGOUT_API_TIMEOUT_SECONDS = "10"
}
timeoutSeconds, conversionErr := strconv.Atoi(BUGOUT_API_TIMEOUT_SECONDS)
if conversionErr != nil {
return nil, conversionErr
}
timeout := time.Duration(timeoutSeconds) * time.Second
httpClient := http.Client{Timeout: timeout}

return &BugoutAPIClient{
BroodBaseURL: BROOD_API_URL,
SpireBaseURL: SPIRE_API_URL,
HTTPClient: &httpClient,
}, nil
}

func CleanTimestamp(rawTimestamp string) string {
return strings.ReplaceAll(rawTimestamp, " ", "T")
}
Expand Down Expand Up @@ -137,3 +171,106 @@ func ProcessDropperClaims(client *bugout.BugoutClient, bugoutToken, journalID, c

return processedErr
}

type User struct {
Id string `json:"user_id"`
Username string `json:"username"`
ApplicationId string `json:"application_id"`
}

func (c *BugoutAPIClient) GetUser(accessToken string) (User, error) {
var user User
var requestBodyBytes []byte
request, requestErr := http.NewRequest("GET", fmt.Sprintf("%s/user", c.BroodBaseURL), bytes.NewBuffer(requestBodyBytes))
if requestErr != nil {
return user, requestErr
}
request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", accessToken))
request.Header.Add("Accept", "application/json")
request.Header.Add("Content-Type", "application/json")

response, responseErr := c.HTTPClient.Do(request)
if responseErr != nil {
return user, responseErr
}
defer response.Body.Close()

responseBody, responseBodyErr := io.ReadAll(response.Body)

if response.StatusCode < 200 || response.StatusCode >= 300 {
if responseBodyErr != nil {
return user, fmt.Errorf("unexpected status code: %d -- could not read response body: %s", response.StatusCode, responseBodyErr.Error())
}
}

if responseBodyErr != nil {
return user, fmt.Errorf("could not read response body: %s", responseBodyErr.Error())
}

unmarshalErr := json.Unmarshal(responseBody, &user)
if unmarshalErr != nil {
return user, fmt.Errorf("could not parse response body: %s", unmarshalErr.Error())
}

return user, nil
}

type AccessWaggleResourceData struct {
Type string `json:"type"`
Customer string `json:"customer"`
AccessLevel string `json:"access_level"`
UserId string `json:"user_id"`
}

type AccessWaggleResource struct {
Id string `json:"id"`
ApplicationId string `json:"application_id"`
ResourceData AccessWaggleResourceData `json:"resource_data"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}

type AccessWaggleResources struct {
Resources []AccessWaggleResource `json:"resources"`
}

func (c *BugoutAPIClient) GetAccessLevelFromResources() (AccessWaggleResources, error) {
var accessWaggleResources AccessWaggleResources
var requestBodyBytes []byte
request, requestErr := http.NewRequest("GET", fmt.Sprintf("%s/resources", c.BroodBaseURL), bytes.NewBuffer(requestBodyBytes))
if requestErr != nil {
return accessWaggleResources, requestErr
}
queryParameters := request.URL.Query()
queryParameters.Add("application_id", MOONSTREAM_APPLICATION_ID)
queryParameters.Add("type", BUGOUT_RESOURCE_TYPE_WAGGLE_ACCESS)

request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", MOONSTREAM_WAGGLE_ADMIN_ACCESS_TOKEN))
request.Header.Add("Accept", "application/json")
request.Header.Add("Content-Type", "application/json")

response, responseErr := c.HTTPClient.Do(request)
if responseErr != nil {
return accessWaggleResources, responseErr
}
defer response.Body.Close()

responseBody, responseBodyErr := io.ReadAll(response.Body)

if response.StatusCode < 200 || response.StatusCode >= 300 {
if responseBodyErr != nil {
return accessWaggleResources, fmt.Errorf("unexpected status code: %d -- could not read response body: %s", response.StatusCode, responseBodyErr.Error())
}
}

if responseBodyErr != nil {
return accessWaggleResources, fmt.Errorf("could not read response body: %s", responseBodyErr.Error())
}

unmarshalErr := json.Unmarshal(responseBody, &accessWaggleResources)
if unmarshalErr != nil {
return accessWaggleResources, fmt.Errorf("could not parse response body: %s", unmarshalErr.Error())
}

return accessWaggleResources, nil
}
6 changes: 5 additions & 1 deletion cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,10 @@ func CreateServerCommand() *cobra.Command {
for _, o := range strings.Split(WAGGLE_CORS_ALLOWED_ORIGINS, ",") {
corsWhitelist[o] = true
}

bugoutClient, bugoutClientErr := InitBugoutAPIClient()
if bugoutClientErr != nil {
return bugoutClientErr
}
moonstreamClient, clientErr := InitMoonstreamEngineAPIClient()
if clientErr != nil {
return clientErr
Expand All @@ -566,6 +569,7 @@ func CreateServerCommand() *cobra.Command {
Port: port,
AvailableSigners: availableSigners,
CORSWhitelist: corsWhitelist,
BugoutAPIClient: bugoutClient,
MoonstreamEngineAPIClient: moonstreamClient,
}

Expand Down
7 changes: 5 additions & 2 deletions deploy/deploy.bash
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,11 @@ echo "AWS_REGION=${AWS_DEFAULT_REGION}" >> "${PARAMETERS_ENV_PATH}"

echo
echo
echo -e "${PREFIX_INFO} Create symlink to config.json"
ln -sf "${STORAGE_PATH}/config.json" "${SECRETS_DIR}/config.json"
echo -e "${PREFIX_INFO} Prepare symlink to config"
if [ ! -f "${SECRETS_DIR}/config.json" ]; then
ln -sf "${STORAGE_PATH}/config.json" "${SECRETS_DIR}/config.json"
echo -e "${PREFIX_WARN} Created symling to config.json"
fi

echo
echo
Expand Down
2 changes: 2 additions & 0 deletions sample.env
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ export BUGOUT_ACCESS_TOKEN="<user_bugout_access_token>"

# Server related environment variables
export WAGGLE_CORS_ALLOWED_ORIGINS="http://localhost:3000,https://moonstream.to,https://portal.moonstream.to,https://www.moonstream.to"
export MOONSTREAM_APPLICATION_ID="<bugout_moonstream_application_id>"
export MOONSTREAM_WAGGLE_ADMIN_ACCESS_TOKEN="<admin_access_token>"
Loading

0 comments on commit 3b1daea

Please sign in to comment.