Skip to content
This repository was archived by the owner on Oct 22, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPACE_ROOT=https://deta.space/api
SPACE_ACCESS_TOKEN=YOUR_ACCESS_TOKEN
SPACE_PROJECT_ID=YOUR_PROJECT_ID
2 changes: 2 additions & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# dotenv .env.staging
dotenv .env.prod
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ starters

.env
.env.*
!.env.template
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ You can also set the `SPACE_ROOT` environment variable in a `.env` file in the r
Other configuration options can be set in the .env file as well:

- SPACE_ACCESS_TOKEN
- SPACE_PROJECT_ID
- SPACE_PROJECT_KEY

A good way to manage different environment is too use the [direnv](https://direnv.net/). Exampleas `.envrc` and `.env.template` file are provided.

To use them:

- Copy `.env.template` to `.env.prod` or `.env.<your-env-name>`
- Fill in the values
- Comment out the proper line in `.envrc` to load the correct file

## Running unit tests

Expand Down
2 changes: 1 addition & 1 deletion cmd/dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ func GetFreePort(start int) (int, error) {
}

func dev(projectDir string, projectID string, host string, port int, open bool) error {
routeDir := filepath.Join(projectDir, ".space", "micros")
spacefile, err := spacefile.LoadSpacefile(projectDir)
if err != nil {
utils.Logger.Printf("%s Failed to parse Spacefile: %s", emoji.ErrorExclamation, err)
Expand All @@ -134,6 +133,7 @@ func dev(projectDir string, projectID string, host string, port int, open bool)
}

utils.Logger.Printf("\n%s Checking for running micros...", emoji.Eyes)
routeDir := filepath.Join(projectDir, ".space", "micros")
var stoppedMicros []*types.Micro
for _, micro := range spacefile.Micros {
_, err := getMicroPort(micro, routeDir)
Expand Down
4 changes: 4 additions & 0 deletions cmd/utils/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ func CheckExists(flagName ...string) PreRunFunc {

func CheckProjectInitialized(dirFlag string) PreRunFunc {
return CheckAll(CheckExists(dirFlag), func(cmd *cobra.Command, args []string) error {
if os.Getenv(runtime.SpaceProjectIDEnv) != "" {
return nil
}

dir, _ := cmd.Flags().GetString(dirFlag)

if _, err := os.Stat(filepath.Join(dir, ".space", "meta")); os.IsNotExist(err) {
Expand Down
38 changes: 15 additions & 23 deletions cmd/utils/keys.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package utils

import (
"fmt"

"github.com/deta/space/internal/api"
"github.com/deta/space/internal/auth"
)
Expand All @@ -11,17 +9,29 @@ func GenerateDataKeyIfNotExists(projectID string) (string, error) {
// check if we have already stored the project key based on the project's id
projectKey, err := auth.GetProjectKey(projectID)
if err == nil {
return projectKey, nil
if err := Client.CheckProjectKey(projectKey); err == nil {
return projectKey, nil
}
}

listRes, err := Client.ListProjectKeys(projectID)
if err != nil {
return "", err
}

keyName := findAvailableKey(listRes.Keys, "space cli")
// delete the project key if it exists
keyName := "space cli"
for _, key := range listRes.Keys {
if key.Name == keyName {
err := Client.DeleteProjectKey(projectID, keyName)
if err != nil {
return "", err
}
break
}
}

// create a new project key using the api
// create a new project key
r, err := Client.CreateProjectKey(projectID, &api.CreateProjectKeyRequest{
Name: keyName,
})
Expand All @@ -37,21 +47,3 @@ func GenerateDataKeyIfNotExists(projectID string) (string, error) {

return r.Value, nil
}

func findAvailableKey(keys []api.ProjectKey, name string) string {
keyMap := make(map[string]struct{})
for _, key := range keys {
keyMap[key.Name] = struct{}{}
}

if _, ok := keyMap[name]; !ok {
return name
}

for i := 1; ; i++ {
newName := fmt.Sprintf("%s (%d)", name, i)
if _, ok := keyMap[newName]; !ok {
return newName
}
}
}
51 changes: 51 additions & 0 deletions internal/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import (
"errors"
"fmt"
"io"
"net/http"
"net/url"
"os"
"strings"

"github.com/deta/space/internal/auth"
"github.com/deta/space/shared"
Expand Down Expand Up @@ -839,6 +842,54 @@ func (c *DetaClient) ListProjectKeys(AppID string) (*ListProjectResponse, error)
return &resp, nil
}

func (c *DetaClient) CheckProjectKey(projectKey string) error {
parts := strings.Split(projectKey, "_")
if len(parts) != 2 {
return fmt.Errorf("invalid project key")
}

instanceID := parts[0]
req, err := http.NewRequest("GET", fmt.Sprintf("https://database.deta.sh/v1/%s/dummy/items/dummy", instanceID), nil)
if err != nil {
return err
}
req.Header.Set("X-API-Key", projectKey)

res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()

if res.StatusCode == 401 {
return fmt.Errorf("invalid project key")
}

return nil
}

func (c *DetaClient) DeleteProjectKey(appID string, keyName string) error {
o, err := c.request(&requestInput{
Root: spaceRoot,
Path: fmt.Sprintf("/%s/apps/%s/keys/%s", version, appID, url.QueryEscape(keyName)),
Method: "DELETE",
NeedsAuth: true,
})
if err != nil {
return err
}

if o.Status != 200 {
msg := o.Error.Detail
if msg == "" && len(o.Error.Errors) > 0 {
msg = o.Error.Errors[0]
}
return fmt.Errorf("failed to delete project key: %v", msg)
}

return nil
}

type Release struct {
ID string `json:"id"`
Tag string `json:"tag"`
Expand Down
14 changes: 12 additions & 2 deletions internal/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ import (
)

const (
spaceAccessTokenEnv = "SPACE_ACCESS_TOKEN"
SpaceAccessTokenEnv = "SPACE_ACCESS_TOKEN"
SpaceProjectKeyEnv = "SPACE_PROJECT_KEY"
DetaProjectKeyEnv = "DETA_PROJECT_KEY"
spaceTokensFile = "space_tokens"
spaceSignVersion = "v0"
spaceDir = ".detaspace"
Expand Down Expand Up @@ -62,7 +64,7 @@ func getAccessTokenFromFile(filepath string) (string, error) {
// GetAccessToken retrieves the tokens from storage or env var
func GetAccessToken() (string, error) {
// preference to env var first
spaceAccessToken := os.Getenv(spaceAccessTokenEnv)
spaceAccessToken := os.Getenv(SpaceAccessTokenEnv)
if spaceAccessToken != "" {
return spaceAccessToken, nil
}
Expand Down Expand Up @@ -167,6 +169,14 @@ type Keys map[string]string

// GetProjectKey retrieves a project key storage or env var
func GetProjectKey(projectId string) (string, error) {
if env, ok := os.LookupEnv(SpaceProjectKeyEnv); ok {
return env, nil
}

if env, ok := os.LookupEnv(DetaProjectKeyEnv); ok {
return env, nil
}

home, err := os.UserHomeDir()
if err != nil {
return "", nil
Expand Down
6 changes: 6 additions & 0 deletions internal/runtime/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const (
)

var (
SpaceProjectIDEnv = "SPACE_PROJECT_ID"

PythonSkipPattern = `__pycache__`

NodeSkipPattern = `node_modules`
Expand Down Expand Up @@ -46,6 +48,10 @@ func StoreProjectMeta(projectDir string, p *ProjectMeta) error {
}

func GetProjectID(projectDir string) (string, error) {
if env, ok := os.LookupEnv(SpaceProjectIDEnv); ok {
return env, nil
}

projectMeta, err := GetProjectMeta(projectDir)
if err != nil {
return "", err
Expand Down