diff --git a/cmd/get.go b/cmd/get.go index e973f76..6341f3b 100644 --- a/cmd/get.go +++ b/cmd/get.go @@ -64,7 +64,7 @@ var getCommand = &cobra.Command{ name = strings.ReplaceAll(strings.Replace(comps[len(comps)-1], ".yaml", "", 1), "/", ":") } - item, err := opClient.Fetch("nidito-admin", name) + item, err := opClient.Get("nidito-admin", name) if err != nil { return err } diff --git a/go.mod b/go.mod index 9ed6e59..69b9dc7 100644 --- a/go.mod +++ b/go.mod @@ -15,5 +15,10 @@ require ( github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/mattn/go-colorable v0.1.9 // indirect github.com/mattn/go-isatty v0.0.16 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect + github.com/uber/jaeger-lib v2.4.1+incompatible // indirect + go.uber.org/atomic v1.9.0 // indirect golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 // indirect ) diff --git a/go.sum b/go.sum index 377a49a..61aeb14 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,7 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/1Password/connect-sdk-go v1.5.0 h1:F0WJcLSzGg3iXEDY49/ULdszYKsQLGTzn+2cyYXqiyk= github.com/1Password/connect-sdk-go v1.5.0/go.mod h1:TdynFeyvaRoackENbJ8RfJokH+WAowAu1MLmUbdMq6s= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -32,7 +33,9 @@ github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peK github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -43,13 +46,17 @@ github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= diff --git a/internal/op-client/cli.go b/internal/op-client/cli.go new file mode 100644 index 0000000..0f9f16c --- /dev/null +++ b/internal/op-client/cli.go @@ -0,0 +1,56 @@ +// Copyright © 2022 Roberto Hidalgo +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package opClient + +import ( + "bytes" + "encoding/json" + "fmt" + "os" + "os/exec" + + op "github.com/1Password/connect-sdk-go/onepassword" +) + +type CLI struct{} + +func (b *CLI) Get(vault, name string) (*op.Item, error) { + cmd := exec.Command("op", "item", "--format", "json", "--vault", vault, "get", name) + + cmd.Env = os.Environ() + var stdout bytes.Buffer + cmd.Stdout = &stdout + var stderr bytes.Buffer + cmd.Stderr = &stderr + if err := cmd.Run(); err != nil { + return nil, err + } + if cmd.ProcessState.ExitCode() > 0 { + return nil, fmt.Errorf("op exited with %d: %s", cmd.ProcessState.ExitCode(), stderr.Bytes()) + } + + var item *op.Item + if err := json.Unmarshal(stdout.Bytes(), &item); err != nil { + return nil, err + } + + return item, nil +} + +func (b *CLI) Update(vault, name string, item *op.Item) error { + return nil +} + +func (b *CLI) List(vault, prefix string) ([]string, error) { + return nil, nil +} diff --git a/internal/op-client/connect.go b/internal/op-client/connect.go new file mode 100644 index 0000000..b6fb232 --- /dev/null +++ b/internal/op-client/connect.go @@ -0,0 +1,90 @@ +// Copyright © 2022 Roberto Hidalgo +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package opClient + +import ( + "fmt" + + "github.com/1Password/connect-sdk-go/connect" + op "github.com/1Password/connect-sdk-go/onepassword" + "github.com/sirupsen/logrus" +) + +// UUIDLength defines the required length of UUIDs +const UUIDLength = 26 + +// IsValidClientUUID returns true if the given client uuid is valid. +func IsValidClientUUID(uuid string) bool { + if len(uuid) != UUIDLength { + return false + } + + for _, c := range uuid { + valid := (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') + if !valid { + return false + } + } + + return true +} + +type Connect struct { + client connect.Client +} + +const userAgent = "nidito-joao" + +func NewConnect(host, token string) *Connect { + client := connect.NewClientWithUserAgent(host, token, userAgent) + return &Connect{client: client} +} + +func (b *Connect) getVaultId(vaultIdentifier string) (string, error) { + if !IsValidClientUUID(vaultIdentifier) { + vaults, err := b.client.GetVaultsByTitle(vaultIdentifier) + if err != nil { + return "", err + } + + if len(vaults) == 0 { + return "", fmt.Errorf("No vaults found with identifier %q", vaultIdentifier) + } + + oldestVault := vaults[0] + if len(vaults) > 1 { + for _, returnedVault := range vaults { + if returnedVault.CreatedAt.Before(oldestVault.CreatedAt) { + oldestVault = returnedVault + } + } + logrus.Infof("%v 1Password vaults found with the title %q. Will use vault %q as it is the oldest.", len(vaults), vaultIdentifier, oldestVault.ID) + } + vaultIdentifier = oldestVault.ID + } + return vaultIdentifier, nil +} + +func (b *Connect) Get(vault, name string) (*op.Item, error) { + return b.client.GetItem(name, vault) +} + +func (b *Connect) Update(item *op.Item) error { + _, err := b.client.UpdateItem(item, item.Vault.ID) + return err +} + +func (b *Connect) List(vault, prefix string) ([]string, error) { + // TODO: get this done + return nil, nil +} diff --git a/internal/op-client/op.go b/internal/op-client/op.go index 69e7363..dece000 100644 --- a/internal/op-client/op.go +++ b/internal/op-client/op.go @@ -13,38 +13,33 @@ package opClient import ( - "bytes" - "encoding/json" - "fmt" - "os" - "os/exec" - op "github.com/1Password/connect-sdk-go/onepassword" ) -func Fetch(vault, name string) (*op.Item, error) { - return fetchRemote(name, vault) +var client opClient + +type opClient interface { + Get(vault, name string) (*op.Item, error) + Update(vault, name string, item *op.Item) error + List(vault, prefix string) ([]string, error) } -func fetchRemote(name, vault string) (*op.Item, error) { - cmd := exec.Command("op", "item", "--format", "json", "--vault", vault, "get", name) - - cmd.Env = os.Environ() - var stdout bytes.Buffer - cmd.Stdout = &stdout - var stderr bytes.Buffer - cmd.Stderr = &stderr - if err := cmd.Run(); err != nil { - return nil, err - } - if cmd.ProcessState.ExitCode() > 0 { - return nil, fmt.Errorf("op exited with %d: %s", cmd.ProcessState.ExitCode(), stderr.Bytes()) - } - - var item *op.Item - if err := json.Unmarshal(stdout.Bytes(), &item); err != nil { - return nil, err - } - - return item, nil +func init() { + client = &CLI{} +} + +func Use(newClient opClient) { + client = newClient +} + +func Get(vault, name string) (*op.Item, error) { + return client.Get(vault, name) +} + +func Update(vault, name string, item *op.Item) error { + return client.Update(vault, name, item) +} + +func List(vault, prefix string) ([]string, error) { + return client.List(vault, prefix) }