diff --git a/backend/box/box.go b/backend/box/box.go index 56bf02c39..69274e102 100644 --- a/backend/box/box.go +++ b/backend/box/box.go @@ -87,13 +87,11 @@ func init() { Description: "Box", NewFs: NewFs, Config: func(ctx context.Context, name string, m configmap.Mapper, config fs.ConfigIn) (*fs.ConfigOut, error) { - jsonFile, ok := m.Get("box_config_file") - boxSubType, boxSubTypeOk := m.Get("box_sub_type") boxAccessToken, boxAccessTokenOk := m.Get("access_token") var err error // If using box config.json, use JWT auth - if ok && boxSubTypeOk && jsonFile != "" && boxSubType != "" { - err = refreshJWTToken(ctx, jsonFile, boxSubType, name, m) + if usesJWTAuth(m) { + err = refreshJWTToken(ctx, name, m) if err != nil { return nil, fmt.Errorf("failed to configure token with jwt authentication: %w", err) } @@ -114,6 +112,11 @@ func init() { }, { Name: "box_config_file", Help: "Box App config.json location\n\nLeave blank normally." + env.ShellExpandHelp, + }, { + Name: "config_credentials", + Help: "Box App config.json contents.\n\nLeave blank normally.", + Hide: fs.OptionHideBoth, + Sensitive: true, }, { Name: "access_token", Help: "Box App Primary Access Token\n\nLeave blank normally.", @@ -184,9 +187,17 @@ See: https://developer.box.com/guides/authentication/jwt/as-user/ }) } -func refreshJWTToken(ctx context.Context, jsonFile string, boxSubType string, name string, m configmap.Mapper) error { - jsonFile = env.ShellExpand(jsonFile) - boxConfig, err := getBoxConfig(jsonFile) +func usesJWTAuth(m configmap.Mapper) bool { + jsonFile, okFile := m.Get("box_config_file") + jsonFileCredentials, okCredentials := m.Get("config_credentials") + boxSubType, boxSubTypeOk := m.Get("box_sub_type") + return (okFile || okCredentials) && boxSubTypeOk && (jsonFile != "" || jsonFileCredentials != "") && boxSubType != "" +} + +func refreshJWTToken(ctx context.Context, name string, m configmap.Mapper) error { + boxSubType, _ := m.Get("box_sub_type") + + boxConfig, err := getBoxConfig(m) if err != nil { return fmt.Errorf("get box config: %w", err) } @@ -205,12 +216,19 @@ func refreshJWTToken(ctx context.Context, jsonFile string, boxSubType string, na return err } -func getBoxConfig(configFile string) (boxConfig *api.ConfigJSON, err error) { - file, err := os.ReadFile(configFile) - if err != nil { - return nil, fmt.Errorf("box: failed to read Box config: %w", err) +func getBoxConfig(m configmap.Mapper) (boxConfig *api.ConfigJSON, err error) { + configFileCredentials, _ := m.Get("config_credentials") + configFileBytes := []byte(configFileCredentials) + + if configFileCredentials == "" { + configFile, _ := m.Get("box_config_file") + configFileBytes, err = os.ReadFile(configFile) + if err != nil { + return nil, fmt.Errorf("box: failed to read Box config: %w", err) + } } - err = json.Unmarshal(file, &boxConfig) + + err = json.Unmarshal(configFileBytes, &boxConfig) if err != nil { return nil, fmt.Errorf("box: failed to parse Box config: %w", err) } @@ -485,15 +503,12 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e f.srv.SetHeader("as-user", f.opt.Impersonate) } - jsonFile, ok := m.Get("box_config_file") - boxSubType, boxSubTypeOk := m.Get("box_sub_type") - if ts != nil { // If using box config.json and JWT, renewing should just refresh the token and // should do so whether there are uploads pending or not. - if ok && boxSubTypeOk && jsonFile != "" && boxSubType != "" { + if usesJWTAuth(m) { f.tokenRenewer = oauthutil.NewRenew(f.String(), ts, func() error { - err := refreshJWTToken(ctx, jsonFile, boxSubType, name, m) + err := refreshJWTToken(ctx, name, m) return err }) f.tokenRenewer.Start()