-
-
Notifications
You must be signed in to change notification settings - Fork 808
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'secret-store' of github.com:sam-github/wtf into sam-git…
…hub-secret-store
- Loading branch information
Showing
31 changed files
with
484 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
package cfg | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"runtime" | ||
|
||
"github.com/docker/docker-credential-helpers/client" | ||
"github.com/docker/docker-credential-helpers/credentials" | ||
"github.com/olebedev/config" | ||
"github.com/wtfutil/wtf/logger" | ||
) | ||
|
||
type Secret struct { | ||
Service string | ||
Secret string | ||
Username string | ||
Store string | ||
} | ||
|
||
// Configure the secret for a service. | ||
// | ||
// Does not overwrite explicitly configured values, so is safe to call | ||
// if username and secret were explicitly set in module config. | ||
// | ||
// Input: | ||
// * service: URL or identifier for service if configured by user. Not all | ||
// modules support or need this. Optional, defaults to serviceDefault. | ||
// * serviceDefault: Default URL or identifier for service. Must be unique, | ||
// using the API URL is customary, but using the module name is reasonable. | ||
// Required, secrets cannot be stored unless associated with a service. | ||
// | ||
// Output: | ||
// * username: If a user/subdomain/identifier specific to the service is | ||
// configurable, it can be saved as a "username". Optional. | ||
// * secret: The secret for service. Optional. | ||
func ConfigureSecret( | ||
globalConfig *config.Config, | ||
service string, | ||
serviceDefault string, | ||
username *string, | ||
secret *string, // unfortunate order dependency... | ||
) { | ||
notWanted := func(out *string) bool { | ||
return out == nil && *out != "" | ||
} | ||
|
||
// Don't try to fetch from cred store if nothing is wanted. | ||
if notWanted(secret) && notWanted(username) { | ||
return | ||
} | ||
|
||
if service == "" { | ||
service = serviceDefault | ||
} | ||
|
||
if service == "" { | ||
return | ||
} | ||
|
||
cred, err := FetchSecret(globalConfig, service) | ||
|
||
if err != nil { | ||
logger.Log(fmt.Sprintf("Loading secret failed: %s", err.Error())) | ||
return | ||
} | ||
|
||
if cred == nil { | ||
// No secret store configued. | ||
return | ||
} | ||
|
||
if username != nil && *username == "" { | ||
*username = cred.Username | ||
} | ||
|
||
if secret != nil && *secret == "" { | ||
*secret = cred.Secret | ||
} | ||
} | ||
|
||
// Fetch secret for `service`. Service is customarily a URL, but can be any | ||
// identifier uniquely used by wtf to identify the service, such as the name | ||
// of the module. nil is returned if the secretStore global property is not | ||
// present or the secret is not found in that store. | ||
func FetchSecret(globalConfig *config.Config, service string) (*Secret, error) { | ||
prog := newProgram(globalConfig) | ||
|
||
if prog == nil { | ||
// No secret store configured. | ||
return nil, nil | ||
} | ||
|
||
cred, err := client.Get(prog.runner, service) | ||
|
||
if err != nil { | ||
return nil, fmt.Errorf("get %v from %v: %w", service, prog.store, err) | ||
} | ||
|
||
return &Secret{ | ||
Service: cred.ServerURL, | ||
Secret: cred.Secret, | ||
Username: cred.Username, | ||
Store: prog.store, | ||
}, nil | ||
} | ||
|
||
func StoreSecret(globalConfig *config.Config, secret *Secret) error { | ||
prog := newProgram(globalConfig) | ||
|
||
if prog == nil { | ||
return errors.New("Cannot store secrets: wtf.secretStore is not configured") | ||
} | ||
|
||
cred := &credentials.Credentials{ | ||
ServerURL: secret.Service, | ||
Username: secret.Username, | ||
Secret: secret.Secret, | ||
} | ||
|
||
// docker-credential requires a username, but it isn't necessary for | ||
// all services. Use a default if a username was not set. | ||
if cred.Username == "" { | ||
cred.Username = "default" | ||
} | ||
|
||
err := client.Store(prog.runner, cred) | ||
|
||
if err != nil { | ||
return fmt.Errorf("store %v: %w", prog.store, err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
type program struct { | ||
store string | ||
runner client.ProgramFunc | ||
} | ||
|
||
func newProgram(globalConfig *config.Config) *program { | ||
secretStore := globalConfig.UString("wtf.secretStore", "(none)") | ||
|
||
if secretStore == "(none)" { | ||
return nil | ||
} | ||
|
||
if secretStore == "" { | ||
switch runtime.GOOS { | ||
case "windows": | ||
secretStore = "winrt" | ||
case "darwin": | ||
secretStore = "osxkeychain" | ||
default: | ||
secretStore = "secretservice" | ||
} | ||
|
||
} | ||
|
||
return &program{ | ||
secretStore, | ||
client.NewShellProgramFunc("docker-credential-" + secretStore), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.