Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improve environment support #206

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
17 changes: 17 additions & 0 deletions cmd/consts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package cmd

const (
// Config file name and location.
configFileName = "auth.json"
appName = "dbxcli"
configBase = ".config"

// Environment variable names.
tokensEnv = "DROPBOX_TOKENS"
personalAppKeyEnv = "DROPBOX_PERSONAL_APP_KEY"
personalAppSecretEnv = "DROPBOX_PERSONAL_APP_SECRET"
teamAccessAppKeyEnv = "DROPBOX_TEAM_APP_KEY"
teamAccessAppSecretEnv = "DROPBOX_TEAM_APP_SECRET"
teamManageAppKeyEnv = "DROPBOX_MANAGE_APP_KEY"
teamManageAppSecretEnv = "DROPBOX_MANAGE_APP_SECRET"
)
43 changes: 43 additions & 0 deletions cmd/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package cmd

import (
"encoding/json"
"fmt"
"os"
"path"
)

// configFile returns the path to the config file.
func configFile() (string, error) {
dir, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("user homedir: %w", err)
}

return path.Join(dir, configBase, appName, configFileName), nil
}

// readTokens returns a token map read from either the
// DROPBOX_TOKENS environment variable or the filePath, in that
// order.
func readTokens(filePath string) (TokenMap, error) {
var data []byte
if envTokens := os.Getenv(tokensEnv); envTokens != "" {
data = []byte(envTokens)
} else {
var err error
if data, err = os.ReadFile(filePath); err != nil {
if os.IsNotExist(err) {
return make(TokenMap), nil
}
return nil, fmt.Errorf("read tokens: %w", err)
}
}

var tokens TokenMap
if err := json.Unmarshal(data, &tokens); err != nil {
return nil, fmt.Errorf("decode tokens: %w", err)
}

return tokens, nil
}
8 changes: 3 additions & 5 deletions cmd/logout.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,20 @@
package cmd

import (
"fmt"
"os"
"path"

"github.com/dropbox/dropbox-sdk-go-unofficial/v6/dropbox"
"github.com/dropbox/dropbox-sdk-go-unofficial/v6/dropbox/auth"
"github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
)

// Command logout revokes all saved API tokens and deletes auth.json.
func logout(cmd *cobra.Command, args []string) error {
dir, err := homedir.Dir()
filePath, err := configFile()
if err != nil {
return err
return fmt.Errorf("config file: %w", err)
}
filePath := path.Join(dir, ".config", "dbxcli", configFileName)

tokMap, err := readTokens(filePath)
if err != nil {
Expand Down
3 changes: 1 addition & 2 deletions cmd/put.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path"
Expand Down Expand Up @@ -96,7 +95,7 @@ func uploadChunked(dbx files.Client, r io.Reader, commitInfo *files.CommitInfo,

written := int64(0)
for written < sizeTotal {
data, err := ioutil.ReadAll(&io.LimitedReader{R: r, N: chunkSize})
data, err := io.ReadAll(&io.LimitedReader{R: r, N: chunkSize})
if err != nil {
return err
}
Expand Down
85 changes: 35 additions & 50 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,19 @@ package cmd
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"

"golang.org/x/oauth2"

"github.com/dropbox/dropbox-sdk-go-unofficial/v6/dropbox"
"github.com/dropbox/dropbox-sdk-go-unofficial/v6/dropbox/files"
"github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)

const (
configFileName = "auth.json"
tokenPersonal = "personal"
tokenTeamAccess = "teamAccess"
tokenTeamManage = "teamManage"
Expand Down Expand Up @@ -107,38 +103,22 @@ func makeRelocationArg(s string, d string) (arg *files.RelocationArg, err error)
return
}

func readTokens(filePath string) (TokenMap, error) {
b, err := ioutil.ReadFile(filePath)
if err != nil {
return nil, err
}

var tokens TokenMap
if json.Unmarshal(b, &tokens) != nil {
return nil, err
}

return tokens, nil
}

func writeTokens(filePath string, tokens TokenMap) {
// Check if file exists
if _, err := os.Stat(filePath); os.IsNotExist(err) {
// Doesn't exist; lets create it
err = os.MkdirAll(filepath.Dir(filePath), 0700)
if err != nil {
return
}
func writeTokens(filePath string, tokens TokenMap) error {
// Ensure config directory exists.
if err := os.MkdirAll(filepath.Dir(filePath), 0700); err != nil {
return fmt.Errorf("create config directory: %w", err)
}

// At this point, file must exist. Lets (over)write it.
b, err := json.Marshal(tokens)
if err != nil {
return
return fmt.Errorf("encode tokens: %w", err)
}
if err = ioutil.WriteFile(filePath, b, 0600); err != nil {
return

if err = os.WriteFile(filePath, b, 0600); err != nil {
return fmt.Errorf("write config: %w", err)
}

return nil
}

func tokenType(cmd *cobra.Command) string {
Expand All @@ -151,46 +131,51 @@ func tokenType(cmd *cobra.Command) string {
return tokenPersonal
}

func initDbx(cmd *cobra.Command, args []string) (err error) {
func initDbx(cmd *cobra.Command, args []string) error {
verbose, _ := cmd.Flags().GetBool("verbose")
asMember, _ := cmd.Flags().GetString("as-member")
domain, _ := cmd.Flags().GetString("domain")

dir, err := homedir.Dir()
if err != nil {
return
}
filePath := path.Join(dir, ".config", "dbxcli", configFileName)
tokType := tokenType(cmd)
conf := oauthConfig(tokType, domain)

filePath, err := configFile()
if err != nil {
return fmt.Errorf("config file: %w", err)
}

tokenMap, err := readTokens(filePath)
if tokenMap == nil {
tokenMap = make(TokenMap)
if err != nil {
return fmt.Errorf("read tokens: %w", err)
}

if tokenMap[domain] == nil {
tokenMap[domain] = make(map[string]string)
}
tokens := tokenMap[domain]

if err != nil || tokens[tokType] == "" {
tokens := tokenMap[domain]
if tokens[tokType] == "" {
fmt.Printf("1. Go to %v\n", conf.AuthCodeURL("state"))
fmt.Printf("2. Click \"Allow\" (you might have to log in first).\n")
fmt.Printf("3. Copy the authorization code.\n")
fmt.Printf("Enter the authorization code here: ")

var code string
if _, err = fmt.Scan(&code); err != nil {
return
return fmt.Errorf("read code: %w", err)
}

var token *oauth2.Token
ctx := context.Background()
token, err = conf.Exchange(ctx, code)
if err != nil {
return
return fmt.Errorf("token exchange: %w", err)
}

tokens[tokType] = token.AccessToken
writeTokens(filePath, tokenMap)
if err := writeTokens(filePath, tokenMap); err != nil {
return err
}
}

logLevel := dropbox.LogOff
Expand All @@ -208,7 +193,7 @@ func initDbx(cmd *cobra.Command, args []string) (err error) {
URLGenerator: nil,
}

return
return nil
}

// RootCmd represents the base command when called without any subcommands
Expand Down Expand Up @@ -236,10 +221,10 @@ func init() {
RootCmd.PersistentFlags().String("domain", "", "Override default Dropbox domain, useful for testing")
RootCmd.PersistentFlags().MarkHidden("domain")

personalAppKey = getEnv("DROPBOX_PERSONAL_APP_KEY", personalAppKey)
personalAppSecret = getEnv("DROPBOX_PERSONAL_APP_SECRET", personalAppSecret)
teamAccessAppKey = getEnv("DROPBOX_TEAM_APP_KEY", teamAccessAppKey)
teamAccessAppSecret = getEnv("DROPBOX_TEAM_APP_SECRET", teamAccessAppSecret)
teamManageAppKey = getEnv("DROPBOX_MANAGE_APP_KEY", teamManageAppKey)
teamManageAppSecret = getEnv("DROPBOX_MANAGE_APP_SECRET", teamAccessAppSecret)
personalAppKey = getEnv(personalAppKeyEnv, personalAppKey)
personalAppSecret = getEnv(personalAppSecretEnv, personalAppSecret)
teamAccessAppKey = getEnv(teamAccessAppKeyEnv, teamAccessAppKey)
teamAccessAppSecret = getEnv(teamAccessAppSecretEnv, teamAccessAppSecret)
teamManageAppKey = getEnv(teamManageAppKeyEnv, teamManageAppKey)
teamManageAppSecret = getEnv(teamManageAppSecretEnv, teamAccessAppSecret)
}
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ require (
github.com/dropbox/dropbox-sdk-go-unofficial/v6 v6.0.1
github.com/dustin/go-humanize v1.0.0
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e
github.com/spf13/cobra v0.0.4-0.20190109003409-7547e83b2d85
github.com/spf13/pflag v1.0.3 // indirect
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,6 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e h1:Qa6dnn8DlasdXRnacluu8HzPts0S1I9zvvUPDbBnXFI=
github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e/go.mod h1:waEya8ee1Ro/lgxpVhkJI4BVASzkm3UZqkx/cFJiYHM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Expand Down