mirror of
https://github.com/mitchell/selfpass.git
synced 2025-12-13 21:07:22 +00:00
Implemented encryption functionality of spc and password generation; refactors on spc and server
This commit is contained in:
parent
c289eecd54
commit
cd24f6e848
26 changed files with 1151 additions and 1522 deletions
21
credentials/cmds/cmds.go
Normal file
21
credentials/cmds/cmds.go
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package cmds
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/mitchell/selfpass/credentials/types"
|
||||
)
|
||||
|
||||
type CredentialClientInit func(ctx context.Context) (c types.CredentialClient)
|
||||
|
||||
func check(err error) {
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
const KeyConnConfig = "connection"
|
||||
const KeyPrivateKey = "private_key"
|
||||
146
credentials/cmds/create.go
Normal file
146
credentials/cmds/create.go
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
package cmds
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/atotto/clipboard"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"gopkg.in/AlecAivazis/survey.v1"
|
||||
|
||||
"github.com/mitchell/selfpass/credentials/types"
|
||||
"github.com/mitchell/selfpass/crypto"
|
||||
)
|
||||
|
||||
func MakeCreateCmd(masterpass string, cfg *viper.Viper, initClient CredentialClientInit) *cobra.Command {
|
||||
createCmd := &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "Create a credential in Selfpass",
|
||||
Long: `Create a credential in Selfpass, and save it to the server after encrypting the
|
||||
password.`,
|
||||
|
||||
Run: func(_ *cobra.Command, args []string) {
|
||||
mdqs := []*survey.Question{
|
||||
{
|
||||
Name: "primary",
|
||||
Prompt: &survey.Input{Message: "Primary user key:"},
|
||||
},
|
||||
{
|
||||
Name: "sourceHost",
|
||||
Prompt: &survey.Input{Message: "Source host:"},
|
||||
},
|
||||
{
|
||||
Name: "loginURL",
|
||||
Prompt: &survey.Input{Message: "Login url:"},
|
||||
},
|
||||
{
|
||||
Name: "tag",
|
||||
Prompt: &survey.Input{Message: "Tag:"},
|
||||
},
|
||||
}
|
||||
cqs := []*survey.Question{
|
||||
{
|
||||
Name: "username",
|
||||
Prompt: &survey.Input{Message: "Username:"},
|
||||
},
|
||||
{
|
||||
Name: "email",
|
||||
Prompt: &survey.Input{Message: "Email:"},
|
||||
},
|
||||
}
|
||||
var ci types.CredentialInput
|
||||
|
||||
check(survey.Ask(mdqs, &ci.MetadataInput))
|
||||
check(survey.Ask(cqs, &ci))
|
||||
|
||||
var newpass bool
|
||||
prompt := &survey.Confirm{Message: "Do you want a random password?", Default: true}
|
||||
check(survey.AskOne(prompt, &newpass, nil))
|
||||
|
||||
if newpass {
|
||||
ci.Password = generatePassword(16, true, true)
|
||||
|
||||
var copypass bool
|
||||
prompt = &survey.Confirm{Message: "Copy new pass to clipboard?", Default: true}
|
||||
check(survey.AskOne(prompt, ©pass, nil))
|
||||
|
||||
if copypass {
|
||||
check(clipboard.WriteAll(ci.Password))
|
||||
}
|
||||
} else {
|
||||
prompt := &survey.Password{Message: "Password: "}
|
||||
check(survey.AskOne(prompt, &ci.Password, nil))
|
||||
|
||||
var cpass string
|
||||
prompt = &survey.Password{Message: "Confirm assword: "}
|
||||
check(survey.AskOne(prompt, &cpass, nil))
|
||||
|
||||
if ci.Password != cpass {
|
||||
fmt.Println("passwords didn't match'")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
key, err := hex.DecodeString(cfg.GetString(KeyPrivateKey))
|
||||
check(err)
|
||||
|
||||
keypass, err := crypto.CombinePasswordAndKey([]byte(masterpass), []byte(key))
|
||||
check(err)
|
||||
|
||||
cipherpass, err := crypto.CBCEncrypt(keypass, []byte(ci.Password))
|
||||
check(err)
|
||||
|
||||
ci.Password = base64.StdEncoding.EncodeToString(cipherpass)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
defer cancel()
|
||||
|
||||
c, err := initClient(ctx).Create(ctx, ci)
|
||||
check(err)
|
||||
|
||||
mdjson, err := json.MarshalIndent(c.Metadata, "", " ")
|
||||
check(err)
|
||||
fmt.Println(string(mdjson))
|
||||
},
|
||||
}
|
||||
|
||||
return createCmd
|
||||
}
|
||||
|
||||
const alphas = "abcdefghijklmnopqrstuvABCDEFGHIJKLMNOPQRSTUV"
|
||||
const alphanumerics = "abcdefghijklmnopqrstuvABCDEFGHIJKLMNOPQRSTUV1234567890"
|
||||
const alphasAndSpecials = "abcdefghijklmnopqrstuvABCDEFGHIJKLMNOPQRSTUV1234567890!@#$%^&*()"
|
||||
const alphanumericsAndSpecials = "abcdefghijklmnopqrstuvABCDEFGHIJKLMNOPQRSTUV1234567890!@#$%^&*()"
|
||||
|
||||
func generatePassword(length int, numbers, specials bool) string {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
pass := make([]byte, length)
|
||||
|
||||
switch {
|
||||
case numbers && specials:
|
||||
for idx := 0; idx < length; idx++ {
|
||||
pass[idx] = alphanumericsAndSpecials[rand.Int63()%int64(len(alphanumericsAndSpecials))]
|
||||
}
|
||||
case numbers:
|
||||
for idx := 0; idx < length; idx++ {
|
||||
pass[idx] = alphanumerics[rand.Int63()%int64(len(alphanumerics))]
|
||||
}
|
||||
case specials:
|
||||
for idx := 0; idx < length; idx++ {
|
||||
pass[idx] = alphasAndSpecials[rand.Int63()%int64(len(alphasAndSpecials))]
|
||||
}
|
||||
default:
|
||||
for idx := 0; idx < length; idx++ {
|
||||
pass[idx] = alphas[rand.Int63()%int64(len(alphas))]
|
||||
}
|
||||
}
|
||||
|
||||
return string(pass)
|
||||
}
|
||||
63
credentials/cmds/get.go
Normal file
63
credentials/cmds/get.go
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
package cmds
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/atotto/clipboard"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/mitchell/selfpass/crypto"
|
||||
)
|
||||
|
||||
func MakeGetCmd(masterpass string, cfg *viper.Viper, initClient CredentialClientInit) *cobra.Command {
|
||||
getCmd := &cobra.Command{
|
||||
Use: "get [id]",
|
||||
Short: "Get a credential info and copy password to clipboard",
|
||||
Long: `Get a credential's info and copy password to clipboard, from Selfpass server, after
|
||||
decrypting password.`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
|
||||
defer cancel()
|
||||
|
||||
cbcontents, err := clipboard.ReadAll()
|
||||
check(err)
|
||||
|
||||
restore := func(cbcontents string) {
|
||||
time.Sleep(time.Second * 5)
|
||||
clipboard.WriteAll(cbcontents)
|
||||
}
|
||||
|
||||
cred, err := initClient(ctx).Get(ctx, args[0])
|
||||
check(err)
|
||||
|
||||
key, err := hex.DecodeString(cfg.GetString(KeyPrivateKey))
|
||||
check(err)
|
||||
|
||||
passkey, err := crypto.CombinePasswordAndKey([]byte(masterpass), key)
|
||||
check(err)
|
||||
|
||||
passbytes, err := base64.StdEncoding.DecodeString(cred.Password)
|
||||
check(err)
|
||||
|
||||
plainpass, err := crypto.CBCDecrypt(passkey, passbytes)
|
||||
|
||||
check(clipboard.WriteAll(string(plainpass)))
|
||||
go restore(cbcontents)
|
||||
|
||||
cjson, err := json.MarshalIndent(cred, "", " ")
|
||||
check(err)
|
||||
fmt.Println(string(cjson))
|
||||
fmt.Println("Wrote password to clipboard.")
|
||||
},
|
||||
}
|
||||
|
||||
return getCmd
|
||||
}
|
||||
58
credentials/cmds/list.go
Normal file
58
credentials/cmds/list.go
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
package cmds
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func MakeListCmd(initClient CredentialClientInit) *cobra.Command {
|
||||
var sourceHost string
|
||||
|
||||
listCmd := &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List the metadata for all credentials",
|
||||
Long: `List the metadata for all credentials, with the option to filter by source host. Metadata
|
||||
includes almost all the information but the most sensitive.`,
|
||||
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
|
||||
defer cancel()
|
||||
|
||||
mdch, errch := initClient(ctx).GetAllMetadata(ctx, sourceHost)
|
||||
|
||||
receive:
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
check(fmt.Errorf("context timeout"))
|
||||
|
||||
case err := <-errch:
|
||||
check(err)
|
||||
|
||||
case md, ok := <-mdch:
|
||||
if !ok {
|
||||
break receive
|
||||
}
|
||||
|
||||
mdjson, err := json.MarshalIndent(md, "", " ")
|
||||
check(err)
|
||||
fmt.Println(string(mdjson))
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
listCmd.Flags().StringVarP(
|
||||
&sourceHost,
|
||||
"source-host",
|
||||
"s",
|
||||
"",
|
||||
"specify which source host to filter the results by",
|
||||
)
|
||||
|
||||
return listCmd
|
||||
}
|
||||
|
|
@ -266,6 +266,7 @@ type Metadata struct {
|
|||
Primary string `protobuf:"bytes,4,opt,name=primary,proto3" json:"primary,omitempty"`
|
||||
SourceHost string `protobuf:"bytes,5,opt,name=source_host,json=sourceHost,proto3" json:"source_host,omitempty"`
|
||||
LoginUrl string `protobuf:"bytes,6,opt,name=login_url,json=loginUrl,proto3" json:"login_url,omitempty"`
|
||||
Tag string `protobuf:"bytes,7,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
|
|
@ -338,6 +339,13 @@ func (m *Metadata) GetLoginUrl() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (m *Metadata) GetTag() string {
|
||||
if m != nil {
|
||||
return m.Tag
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Credential struct {
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
CreatedAt *timestamp.Timestamp `protobuf:"bytes,2,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
|
||||
|
|
@ -348,6 +356,7 @@ type Credential struct {
|
|||
Password string `protobuf:"bytes,7,opt,name=password,proto3" json:"password,omitempty"`
|
||||
SourceHost string `protobuf:"bytes,8,opt,name=source_host,json=sourceHost,proto3" json:"source_host,omitempty"`
|
||||
LoginUrl string `protobuf:"bytes,9,opt,name=login_url,json=loginUrl,proto3" json:"login_url,omitempty"`
|
||||
Tag string `protobuf:"bytes,10,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
|
|
@ -441,6 +450,13 @@ func (m *Credential) GetLoginUrl() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (m *Credential) GetTag() string {
|
||||
if m != nil {
|
||||
return m.Tag
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type CredentialRequest struct {
|
||||
Primary string `protobuf:"bytes,1,opt,name=primary,proto3" json:"primary,omitempty"`
|
||||
Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"`
|
||||
|
|
@ -448,6 +464,7 @@ type CredentialRequest struct {
|
|||
Password string `protobuf:"bytes,4,opt,name=password,proto3" json:"password,omitempty"`
|
||||
SourceHost string `protobuf:"bytes,5,opt,name=source_host,json=sourceHost,proto3" json:"source_host,omitempty"`
|
||||
LoginUrl string `protobuf:"bytes,6,opt,name=login_url,json=loginUrl,proto3" json:"login_url,omitempty"`
|
||||
Tag string `protobuf:"bytes,7,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
|
|
@ -520,6 +537,13 @@ func (m *CredentialRequest) GetLoginUrl() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (m *CredentialRequest) GetTag() string {
|
||||
if m != nil {
|
||||
return m.Tag
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*DeleteResponse)(nil), "selfpass.credentials.DeleteResponse")
|
||||
proto.RegisterType((*GetAllMetadataRequest)(nil), "selfpass.credentials.GetAllMetadataRequest")
|
||||
|
|
@ -535,41 +559,41 @@ func init() {
|
|||
func init() { proto.RegisterFile("credentials/protobuf/service.proto", fileDescriptor_ad34efc7bbd96e69) }
|
||||
|
||||
var fileDescriptor_ad34efc7bbd96e69 = []byte{
|
||||
// 539 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x54, 0xc1, 0x6e, 0xd3, 0x40,
|
||||
0x10, 0x95, 0x93, 0x34, 0x75, 0xa6, 0x21, 0x12, 0xab, 0x22, 0x59, 0xae, 0x44, 0xa2, 0x05, 0x89,
|
||||
0xaa, 0x48, 0x2e, 0x2a, 0x17, 0x38, 0x86, 0x16, 0xa5, 0x1c, 0x00, 0xc9, 0xa5, 0x17, 0x2e, 0xd1,
|
||||
0xd6, 0x9e, 0xa6, 0x96, 0x6c, 0xaf, 0xd9, 0x5d, 0x83, 0xfa, 0x01, 0xfc, 0x13, 0xfc, 0x11, 0x9f,
|
||||
0x81, 0xbc, 0xf6, 0x26, 0xae, 0xeb, 0x34, 0xe1, 0xc6, 0xcd, 0xb3, 0x7e, 0x6f, 0xf5, 0xde, 0xcc,
|
||||
0xce, 0x03, 0x1a, 0x08, 0x0c, 0x31, 0x55, 0x11, 0x8b, 0xe5, 0x71, 0x26, 0xb8, 0xe2, 0x57, 0xf9,
|
||||
0xf5, 0xb1, 0x44, 0xf1, 0x3d, 0x0a, 0xd0, 0xd3, 0x07, 0x64, 0x5f, 0x62, 0x7c, 0x9d, 0x31, 0x29,
|
||||
0xbd, 0x1a, 0xd8, 0x1d, 0x2f, 0x38, 0x5f, 0xc4, 0xb8, 0x22, 0xa9, 0x28, 0x41, 0xa9, 0x58, 0x92,
|
||||
0x95, 0x34, 0x7a, 0x04, 0xa3, 0x33, 0x8c, 0x51, 0xa1, 0x8f, 0x32, 0xe3, 0xa9, 0x44, 0xe2, 0xc0,
|
||||
0xae, 0xcc, 0x83, 0x00, 0xa5, 0x74, 0xac, 0x89, 0x75, 0x68, 0xfb, 0xa6, 0xa4, 0x6f, 0xe0, 0xc9,
|
||||
0x0c, 0xd5, 0x34, 0x8e, 0x3f, 0xa2, 0x62, 0x21, 0x53, 0xcc, 0xc7, 0x6f, 0x39, 0x4a, 0x45, 0xc6,
|
||||
0xb0, 0x27, 0x79, 0x2e, 0x02, 0x9c, 0xdf, 0x70, 0xa9, 0x34, 0x6d, 0xe0, 0x43, 0x79, 0x74, 0xce,
|
||||
0xa5, 0xa2, 0x07, 0x30, 0xf8, 0x10, 0x1a, 0xf4, 0x08, 0x3a, 0x51, 0x58, 0x81, 0x3a, 0x51, 0x48,
|
||||
0x6f, 0xe0, 0xd1, 0x65, 0x16, 0xb2, 0x42, 0x42, 0x2b, 0x80, 0xcc, 0x00, 0x56, 0x9e, 0x9c, 0xce,
|
||||
0xc4, 0x3a, 0xdc, 0x3b, 0x79, 0xe1, 0xb5, 0xf9, 0xf5, 0x4e, 0x97, 0xdf, 0xd5, 0x65, 0x7e, 0x8d,
|
||||
0x4a, 0x8f, 0x60, 0x78, 0x96, 0x27, 0xd9, 0xd2, 0xaa, 0x0b, 0x76, 0xc0, 0x53, 0x85, 0xa9, 0x2a,
|
||||
0xbd, 0x0e, 0xfd, 0x65, 0x4d, 0x47, 0x30, 0x7c, 0x9f, 0x64, 0xea, 0xb6, 0xba, 0x87, 0xfe, 0xb1,
|
||||
0xc0, 0x36, 0xbe, 0xef, 0x29, 0x7c, 0xab, 0x15, 0x32, 0x85, 0xe1, 0x9c, 0xa9, 0x4a, 0xa1, 0xeb,
|
||||
0x95, 0xbd, 0xf7, 0x4c, 0xef, 0xbd, 0x2f, 0xa6, 0xf7, 0xfe, 0xa0, 0x42, 0x4f, 0x55, 0x41, 0xcd,
|
||||
0xb5, 0x7b, 0x4d, 0xed, 0x6e, 0xa6, 0x56, 0xe8, 0xa9, 0x2a, 0x26, 0x95, 0x89, 0x28, 0x61, 0xe2,
|
||||
0xd6, 0xe9, 0x69, 0x29, 0xa6, 0x6c, 0x0e, 0x64, 0xa7, 0x39, 0x10, 0x72, 0x00, 0x83, 0x98, 0x2f,
|
||||
0xa2, 0x74, 0x9e, 0x8b, 0xd8, 0xe9, 0xeb, 0xdf, 0xb6, 0x3e, 0xb8, 0x14, 0x31, 0xfd, 0xd5, 0x01,
|
||||
0x58, 0x35, 0xf2, 0xbf, 0x37, 0xeb, 0x82, 0x9d, 0x4b, 0x14, 0x29, 0x4b, 0xb0, 0x72, 0xba, 0xac,
|
||||
0xc9, 0x3e, 0xec, 0x60, 0xc2, 0x22, 0xe3, 0xb1, 0x2c, 0x0a, 0x46, 0xf1, 0x72, 0x7e, 0x70, 0x11,
|
||||
0x3a, 0xbb, 0x25, 0xc3, 0xd4, 0xcd, 0xd6, 0xd9, 0x0f, 0xb7, 0x6e, 0xd0, 0x68, 0xdd, 0x6f, 0x0b,
|
||||
0x1e, 0xdf, 0x7b, 0x83, 0x75, 0xed, 0xd6, 0x7a, 0xed, 0x9d, 0x75, 0xda, 0xbb, 0xeb, 0xb4, 0xf7,
|
||||
0x1e, 0xd6, 0xfe, 0x6f, 0x63, 0x3f, 0xf9, 0xd9, 0xab, 0x6b, 0xbf, 0x28, 0xd3, 0x85, 0xcc, 0x61,
|
||||
0x74, 0x77, 0xe9, 0xc9, 0xcb, 0xf6, 0xd5, 0x6b, 0x8d, 0x06, 0xf7, 0x69, 0x3b, 0xd8, 0xc0, 0x5e,
|
||||
0x59, 0xe4, 0x1c, 0xba, 0x33, 0x54, 0x64, 0xdc, 0x0e, 0x5c, 0xc6, 0x86, 0x3b, 0xd9, 0xb4, 0xf1,
|
||||
0xe4, 0x02, 0xfa, 0xa7, 0xfa, 0xa9, 0x91, 0x6d, 0xd3, 0x61, 0x8b, 0x4b, 0x3f, 0x43, 0xbf, 0x4c,
|
||||
0x27, 0xf2, 0xac, 0x1d, 0x7b, 0x27, 0xbb, 0xb6, 0xbb, 0xb0, 0x4c, 0xdc, 0xcd, 0x96, 0x9f, 0xb7,
|
||||
0x03, 0x1a, 0x81, 0xfd, 0x09, 0x7a, 0x45, 0xaa, 0x11, 0xda, 0x8e, 0xae, 0xa7, 0x98, 0xbb, 0x06,
|
||||
0x53, 0x4f, 0xc5, 0x77, 0xf0, 0xd5, 0x36, 0xab, 0x78, 0xd5, 0xd7, 0x5f, 0xaf, 0xff, 0x06, 0x00,
|
||||
0x00, 0xff, 0xff, 0x39, 0xb2, 0x93, 0x8d, 0x82, 0x06, 0x00, 0x00,
|
||||
// 535 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x94, 0xcf, 0x6e, 0xd3, 0x40,
|
||||
0x10, 0xc6, 0xe5, 0xa4, 0x4d, 0xed, 0x69, 0x88, 0x60, 0x55, 0x24, 0xcb, 0x95, 0x48, 0x64, 0x90,
|
||||
0xa8, 0x8a, 0xe4, 0xa2, 0x72, 0x81, 0x63, 0x68, 0x51, 0xca, 0x01, 0x21, 0xb9, 0xf4, 0xc2, 0x25,
|
||||
0xda, 0xda, 0xd3, 0xd4, 0x92, 0xed, 0x35, 0xbb, 0x63, 0x50, 0x1f, 0x8c, 0x97, 0x80, 0x37, 0xe2,
|
||||
0x84, 0xbc, 0xfe, 0x93, 0x3f, 0x75, 0x9a, 0x48, 0x5c, 0xb8, 0xed, 0xac, 0xbf, 0x59, 0xcd, 0xef,
|
||||
0xdb, 0xf5, 0x07, 0x6e, 0x20, 0x31, 0xc4, 0x94, 0x22, 0x1e, 0xab, 0x93, 0x4c, 0x0a, 0x12, 0xd7,
|
||||
0xf9, 0xcd, 0x89, 0x42, 0xf9, 0x3d, 0x0a, 0xd0, 0xd3, 0x1b, 0xec, 0x40, 0x61, 0x7c, 0x93, 0x71,
|
||||
0xa5, 0xbc, 0x05, 0xb1, 0x33, 0x9c, 0x09, 0x31, 0x8b, 0x71, 0xde, 0x44, 0x51, 0x82, 0x8a, 0x78,
|
||||
0x92, 0x95, 0x6d, 0xee, 0x31, 0x0c, 0xce, 0x31, 0x46, 0x42, 0x1f, 0x55, 0x26, 0x52, 0x85, 0xcc,
|
||||
0x86, 0x3d, 0x95, 0x07, 0x01, 0x2a, 0x65, 0x1b, 0x23, 0xe3, 0xc8, 0xf4, 0xeb, 0xd2, 0x7d, 0x0b,
|
||||
0x4f, 0x27, 0x48, 0xe3, 0x38, 0xfe, 0x84, 0xc4, 0x43, 0x4e, 0xdc, 0xc7, 0x6f, 0x39, 0x2a, 0x62,
|
||||
0x43, 0xd8, 0x57, 0x22, 0x97, 0x01, 0x4e, 0x6f, 0x85, 0x22, 0xdd, 0x66, 0xf9, 0x50, 0x6e, 0x5d,
|
||||
0x08, 0x45, 0xee, 0x21, 0x58, 0x1f, 0xc3, 0x5a, 0x3d, 0x80, 0x4e, 0x14, 0x56, 0xa2, 0x4e, 0x14,
|
||||
0xba, 0xb7, 0xf0, 0xe8, 0x2a, 0x0b, 0x79, 0x31, 0x42, 0xab, 0x80, 0x4d, 0x00, 0xe6, 0x4c, 0x76,
|
||||
0x67, 0x64, 0x1c, 0xed, 0x9f, 0xbe, 0xf4, 0xda, 0x78, 0xbd, 0xb3, 0x66, 0x5d, 0x1d, 0xe6, 0x2f,
|
||||
0xb4, 0xba, 0xc7, 0xd0, 0x3f, 0xcf, 0x93, 0xac, 0x41, 0x75, 0xc0, 0x0c, 0x44, 0x4a, 0x98, 0x52,
|
||||
0xc9, 0xda, 0xf7, 0x9b, 0xda, 0x1d, 0x40, 0xff, 0x43, 0x92, 0xd1, 0x5d, 0x75, 0x8e, 0xfb, 0xc7,
|
||||
0x00, 0xb3, 0xe6, 0xbe, 0x37, 0xe1, 0x3b, 0x3d, 0x21, 0x27, 0x0c, 0xa7, 0x9c, 0xaa, 0x09, 0x1d,
|
||||
0xaf, 0xf4, 0xde, 0xab, 0xbd, 0xf7, 0xbe, 0xd4, 0xde, 0xfb, 0x56, 0xa5, 0x1e, 0x53, 0xd1, 0x9a,
|
||||
0x6b, 0x7a, 0xdd, 0xda, 0xdd, 0xdc, 0x5a, 0xa9, 0xc7, 0x54, 0xdc, 0x54, 0x26, 0xa3, 0x84, 0xcb,
|
||||
0x3b, 0x7b, 0x47, 0x8f, 0x52, 0x97, 0xab, 0x17, 0xb2, 0xbb, 0x7a, 0x21, 0xec, 0x10, 0xac, 0x58,
|
||||
0xcc, 0xa2, 0x74, 0x9a, 0xcb, 0xd8, 0xee, 0xe9, 0xcf, 0xa6, 0xde, 0xb8, 0x92, 0x31, 0x7b, 0x0c,
|
||||
0x5d, 0xe2, 0x33, 0x7b, 0x4f, 0x6f, 0x17, 0x4b, 0xf7, 0x57, 0x07, 0x60, 0x6e, 0xed, 0x7f, 0x8f,
|
||||
0xef, 0x80, 0x99, 0x2b, 0x94, 0x29, 0x4f, 0xb0, 0x62, 0x6f, 0x6a, 0x76, 0x00, 0xbb, 0x98, 0xf0,
|
||||
0xa8, 0xa6, 0x2e, 0x8b, 0xa2, 0xa3, 0x78, 0x4b, 0x3f, 0x84, 0x0c, 0x2b, 0xee, 0xa6, 0x5e, 0x35,
|
||||
0xd3, 0x7c, 0xd8, 0x4c, 0xab, 0xdd, 0x4c, 0x98, 0x9b, 0xf9, 0xdb, 0x80, 0x27, 0xf7, 0xde, 0xe9,
|
||||
0x22, 0x8d, 0xb1, 0x9e, 0xa6, 0xb3, 0x8e, 0xa6, 0xbb, 0x8e, 0x66, 0xe7, 0x61, 0x9a, 0x7f, 0x7d,
|
||||
0x1a, 0xa7, 0x3f, 0xbb, 0x8b, 0x34, 0x97, 0x65, 0x26, 0xb1, 0x29, 0x0c, 0x96, 0xa3, 0x82, 0xbd,
|
||||
0x6a, 0xff, 0x61, 0x5b, 0x03, 0xc5, 0x79, 0xd6, 0x2e, 0xae, 0x65, 0xaf, 0x0d, 0x76, 0x01, 0xdd,
|
||||
0x09, 0x12, 0x1b, 0xb6, 0x0b, 0x9b, 0xb0, 0x71, 0x46, 0x9b, 0x72, 0x82, 0x5d, 0x42, 0xef, 0x4c,
|
||||
0x3f, 0x47, 0xb6, 0x6d, 0xa6, 0x6c, 0x71, 0xe8, 0x67, 0xe8, 0x95, 0x99, 0xc6, 0x9e, 0xb7, 0x6b,
|
||||
0x97, 0x12, 0x6f, 0xbb, 0x03, 0xcb, 0x9c, 0xde, 0x8c, 0xfc, 0xa2, 0x5d, 0xb0, 0x1c, 0xf3, 0xef,
|
||||
0xe1, 0xab, 0x59, 0xff, 0x5e, 0xd7, 0x3d, 0xbd, 0x7a, 0xf3, 0x37, 0x00, 0x00, 0xff, 0xff, 0x22,
|
||||
0xb6, 0x48, 0x2d, 0x68, 0x06, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
|
@ -589,7 +613,6 @@ type CredentialServiceClient interface {
|
|||
Create(ctx context.Context, in *CredentialRequest, opts ...grpc.CallOption) (*Credential, error)
|
||||
Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*Credential, error)
|
||||
Delete(ctx context.Context, in *IdRequest, opts ...grpc.CallOption) (*DeleteResponse, error)
|
||||
Dump(ctx context.Context, in *EmptyRequest, opts ...grpc.CallOption) (*DumpResponse, error)
|
||||
}
|
||||
|
||||
type credentialServiceClient struct {
|
||||
|
|
@ -668,15 +691,6 @@ func (c *credentialServiceClient) Delete(ctx context.Context, in *IdRequest, opt
|
|||
return out, nil
|
||||
}
|
||||
|
||||
func (c *credentialServiceClient) Dump(ctx context.Context, in *EmptyRequest, opts ...grpc.CallOption) (*DumpResponse, error) {
|
||||
out := new(DumpResponse)
|
||||
err := c.cc.Invoke(ctx, "/selfpass.credentials.CredentialService/Dump", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// CredentialServiceServer is the server API for CredentialService service.
|
||||
type CredentialServiceServer interface {
|
||||
GetAllMetadata(*GetAllMetadataRequest, CredentialService_GetAllMetadataServer) error
|
||||
|
|
@ -684,7 +698,6 @@ type CredentialServiceServer interface {
|
|||
Create(context.Context, *CredentialRequest) (*Credential, error)
|
||||
Update(context.Context, *UpdateRequest) (*Credential, error)
|
||||
Delete(context.Context, *IdRequest) (*DeleteResponse, error)
|
||||
Dump(context.Context, *EmptyRequest) (*DumpResponse, error)
|
||||
}
|
||||
|
||||
// UnimplementedCredentialServiceServer can be embedded to have forward compatible implementations.
|
||||
|
|
@ -706,9 +719,6 @@ func (*UnimplementedCredentialServiceServer) Update(ctx context.Context, req *Up
|
|||
func (*UnimplementedCredentialServiceServer) Delete(ctx context.Context, req *IdRequest) (*DeleteResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented")
|
||||
}
|
||||
func (*UnimplementedCredentialServiceServer) Dump(ctx context.Context, req *EmptyRequest) (*DumpResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Dump not implemented")
|
||||
}
|
||||
|
||||
func RegisterCredentialServiceServer(s *grpc.Server, srv CredentialServiceServer) {
|
||||
s.RegisterService(&_CredentialService_serviceDesc, srv)
|
||||
|
|
@ -807,24 +817,6 @@ func _CredentialService_Delete_Handler(srv interface{}, ctx context.Context, dec
|
|||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _CredentialService_Dump_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(EmptyRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CredentialServiceServer).Dump(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/selfpass.credentials.CredentialService/Dump",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CredentialServiceServer).Dump(ctx, req.(*EmptyRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _CredentialService_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "selfpass.credentials.CredentialService",
|
||||
HandlerType: (*CredentialServiceServer)(nil),
|
||||
|
|
@ -845,10 +837,6 @@ var _CredentialService_serviceDesc = grpc.ServiceDesc{
|
|||
MethodName: "Delete",
|
||||
Handler: _CredentialService_Delete_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Dump",
|
||||
Handler: _CredentialService_Dump_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ service CredentialService {
|
|||
rpc Create (CredentialRequest) returns (Credential);
|
||||
rpc Update (UpdateRequest) returns (Credential);
|
||||
rpc Delete (IdRequest) returns (DeleteResponse);
|
||||
rpc Dump (EmptyRequest) returns (DumpResponse);
|
||||
// rpc Dump (EmptyRequest) returns (DumpResponse);
|
||||
}
|
||||
|
||||
message DeleteResponse {
|
||||
|
|
@ -46,6 +46,7 @@ message Metadata {
|
|||
string primary = 4;
|
||||
string source_host = 5;
|
||||
string login_url = 6;
|
||||
string tag = 7;
|
||||
}
|
||||
|
||||
message Credential {
|
||||
|
|
@ -58,6 +59,7 @@ message Credential {
|
|||
string password = 7;
|
||||
string source_host = 8;
|
||||
string login_url = 9;
|
||||
string tag = 10;
|
||||
}
|
||||
|
||||
message CredentialRequest {
|
||||
|
|
@ -67,4 +69,5 @@ message CredentialRequest {
|
|||
string password = 4;
|
||||
string source_host = 5;
|
||||
string login_url = 6;
|
||||
string tag = 7;
|
||||
}
|
||||
|
|
|
|||
115
credentials/repositories/grpc_client.go
Normal file
115
credentials/repositories/grpc_client.go
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/mitchell/selfpass/credentials/endpoints"
|
||||
"github.com/mitchell/selfpass/credentials/protobuf"
|
||||
"github.com/mitchell/selfpass/credentials/transport"
|
||||
"github.com/mitchell/selfpass/credentials/types"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
||||
func NewCredentialServiceClient(ctx context.Context, target, ca, cert, key string) (types.CredentialClient, error) {
|
||||
keypair, err := tls.X509KeyPair([]byte(cert), []byte(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
capool := x509.NewCertPool()
|
||||
capool.AppendCertsFromPEM([]byte(ca))
|
||||
|
||||
creds := credentials.NewTLS(&tls.Config{
|
||||
RootCAs: capool,
|
||||
Certificates: []tls.Certificate{keypair},
|
||||
})
|
||||
|
||||
conn, err := grpc.DialContext(ctx, target, grpc.WithTransportCredentials(creds), grpc.WithBlock())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return CredentialServiceClient{
|
||||
client: protobuf.NewCredentialServiceClient(conn),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type CredentialServiceClient struct {
|
||||
client protobuf.CredentialServiceClient
|
||||
}
|
||||
|
||||
func (c CredentialServiceClient) GetAllMetadata(ctx context.Context, sourceHost string) (output <-chan types.Metadata, errch chan error) {
|
||||
pbmdch := make(chan protobuf.Metadata, 1)
|
||||
errch = make(chan error, 1)
|
||||
|
||||
stream, err := transport.DecodeMetdataStreamResponse(ctx, transport.ProtobufMetadataStream{
|
||||
Metadata: pbmdch,
|
||||
Errors: errch,
|
||||
})
|
||||
|
||||
srv, err := c.client.GetAllMetadata(ctx, &protobuf.GetAllMetadataRequest{SourceHost: sourceHost})
|
||||
if err != nil {
|
||||
errch <- err
|
||||
return nil, errch
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer close(pbmdch)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
errch <- fmt.Errorf("context timeout")
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
pbmd, err := srv.Recv()
|
||||
if err == io.EOF {
|
||||
return
|
||||
} else if err != nil {
|
||||
errch <- err
|
||||
return
|
||||
}
|
||||
|
||||
pbmdch <- *pbmd
|
||||
}
|
||||
}()
|
||||
|
||||
return stream.Metadata, stream.Errors
|
||||
}
|
||||
|
||||
func (c CredentialServiceClient) Get(ctx context.Context, id string) (output types.Credential, err error) {
|
||||
req := transport.EncodeIdRequest(endpoints.IDRequest{ID: id})
|
||||
|
||||
res, err := c.client.Get(ctx, &req)
|
||||
if err != nil {
|
||||
return output, err
|
||||
}
|
||||
|
||||
return transport.DecodeCredential(*res)
|
||||
}
|
||||
|
||||
func (c CredentialServiceClient) Create(ctx context.Context, ci types.CredentialInput) (output types.Credential, err error) {
|
||||
req := transport.EncodeCredentialRequest(ci)
|
||||
|
||||
res, err := c.client.Create(ctx, &req)
|
||||
if err != nil {
|
||||
return output, err
|
||||
}
|
||||
|
||||
return transport.DecodeCredential(*res)
|
||||
}
|
||||
|
||||
func (c CredentialServiceClient) Update(ctx context.Context, id string, ci types.CredentialInput) (output types.Credential, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (c CredentialServiceClient) Delete(ctx context.Context, id string) (err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
|
@ -7,18 +7,11 @@ import (
|
|||
"github.com/mitchell/selfpass/credentials/types"
|
||||
)
|
||||
|
||||
func NewRedisConn(cfg ConnConfig) (c RedisConn, err error) {
|
||||
p, err := radix.NewPool(cfg.NetworkType, cfg.Address, int(cfg.Size), cfg.Options...)
|
||||
func NewRedisConn(networkType, address string, connCount uint, options ...radix.PoolOpt) (c RedisConn, err error) {
|
||||
p, err := radix.NewPool(networkType, address, int(connCount), options...)
|
||||
return RedisConn{p: p}, err
|
||||
}
|
||||
|
||||
type ConnConfig struct {
|
||||
NetworkType string
|
||||
Address string
|
||||
Size uint
|
||||
Options []radix.PoolOpt
|
||||
}
|
||||
|
||||
type RedisConn struct {
|
||||
p *radix.Pool
|
||||
}
|
||||
|
|
@ -30,22 +23,23 @@ func (conn RedisConn) GetAllMetadata(ctx context.Context, sourceHost string, err
|
|||
defer close(mdch)
|
||||
|
||||
var key string
|
||||
scr := radix.NewScanner(conn.p, radix.ScanOpts{Command: scan, Pattern: sourceHost + star})
|
||||
scr := radix.NewScanner(conn.p, radix.ScanOpts{Command: scan, Pattern: types.TypePrefixCred + dash + sourceHost + star})
|
||||
|
||||
for scr.Next(&key) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
var md types.Metadata
|
||||
|
||||
if err := conn.p.Do(radix.Cmd(&md, hGetAll, key)); err != nil {
|
||||
errch <- err
|
||||
return
|
||||
}
|
||||
|
||||
mdch <- md
|
||||
}
|
||||
|
||||
var md types.Metadata
|
||||
|
||||
if err := conn.p.Do(radix.Cmd(&md, hGetAll, key)); err != nil {
|
||||
errch <- err
|
||||
return
|
||||
}
|
||||
|
||||
mdch <- md
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
@ -53,41 +47,17 @@ func (conn RedisConn) GetAllMetadata(ctx context.Context, sourceHost string, err
|
|||
}
|
||||
|
||||
func (conn RedisConn) Get(ctx context.Context, id string) (output types.Credential, err error) {
|
||||
var key string
|
||||
scr := radix.NewScanner(conn.p, radix.ScanOpts{Command: scan, Pattern: star + id, Count: 1})
|
||||
|
||||
if !scr.Next(&key) {
|
||||
return output, nil
|
||||
}
|
||||
|
||||
if err = scr.Close(); err != nil {
|
||||
return output, err
|
||||
}
|
||||
|
||||
err = conn.p.Do(radix.Cmd(&output, hGetAll, key))
|
||||
|
||||
err = conn.p.Do(radix.Cmd(&output, hGetAll, id))
|
||||
return output, err
|
||||
}
|
||||
|
||||
func (conn RedisConn) Put(ctx context.Context, c types.Credential) (err error) {
|
||||
err = conn.p.Do(radix.FlatCmd(nil, hMSet, c.SourceHost+dash+c.ID, c))
|
||||
err = conn.p.Do(radix.FlatCmd(nil, hMSet, c.ID, c))
|
||||
return err
|
||||
}
|
||||
|
||||
func (conn RedisConn) Delete(ctx context.Context, id string) (err error) {
|
||||
var key string
|
||||
scr := radix.NewScanner(conn.p, radix.ScanOpts{Command: scan, Pattern: star + id, Count: 1})
|
||||
|
||||
if !scr.Next(&key) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err = scr.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = conn.p.Do(radix.Cmd(nil, del, key))
|
||||
|
||||
err = conn.p.Do(radix.Cmd(nil, del, id))
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/mitchell/selfpass/credentials/types"
|
||||
)
|
||||
|
||||
|
|
@ -38,7 +37,7 @@ func (svc Credentials) Create(ctx context.Context, ci types.CredentialInput) (ou
|
|||
}
|
||||
|
||||
var c types.Credential
|
||||
c.ID = "cred-" + uuid.New().String()
|
||||
c.ID = generateID(ci)
|
||||
c.CreatedAt = time.Now()
|
||||
c.UpdatedAt = time.Now()
|
||||
c.Primary = ci.Primary
|
||||
|
|
@ -47,6 +46,7 @@ func (svc Credentials) Create(ctx context.Context, ci types.CredentialInput) (ou
|
|||
c.Username = ci.Username
|
||||
c.Email = ci.Email
|
||||
c.Password = ci.Password
|
||||
c.Tag = ci.Tag
|
||||
|
||||
err = svc.repo.Put(ctx, c)
|
||||
|
||||
|
|
@ -57,6 +57,8 @@ func validateCredentialInput(c types.CredentialInput) (err error) {
|
|||
switch {
|
||||
case c.SourceHost == "":
|
||||
return fmt.Errorf("%s must specify source host", types.InvalidArgument)
|
||||
case c.Primary == "":
|
||||
return fmt.Errorf("%s must specify primary user key", types.InvalidArgument)
|
||||
case c.Password == "":
|
||||
return fmt.Errorf("%s must specify password", types.InvalidArgument)
|
||||
}
|
||||
|
|
@ -64,6 +66,17 @@ func validateCredentialInput(c types.CredentialInput) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
func generateID(ci types.CredentialInput) string {
|
||||
idFormat := types.TypePrefixCred + "-%s-%s"
|
||||
|
||||
if ci.Tag != "" {
|
||||
idFormat += "-%s"
|
||||
return fmt.Sprintf(idFormat, ci.SourceHost, ci.Primary, ci.Tag)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(idFormat, ci.SourceHost, ci.Primary)
|
||||
}
|
||||
|
||||
func (svc Credentials) Update(ctx context.Context, id string, ci types.CredentialInput) (output types.Credential, err error) {
|
||||
if err = validateCredentialInput(ci); err != nil {
|
||||
return output, err
|
||||
|
|
@ -78,6 +91,7 @@ func (svc Credentials) Update(ctx context.Context, id string, ci types.Credentia
|
|||
return output, err
|
||||
}
|
||||
|
||||
c.ID = generateID(ci)
|
||||
c.UpdatedAt = time.Now()
|
||||
c.Primary = ci.Primary
|
||||
c.LoginURL = ci.LoginURL
|
||||
|
|
@ -85,6 +99,7 @@ func (svc Credentials) Update(ctx context.Context, id string, ci types.Credentia
|
|||
c.Password = ci.Password
|
||||
c.Email = ci.Email
|
||||
c.Username = ci.Username
|
||||
c.Tag = ci.Tag
|
||||
|
||||
return c, svc.repo.Put(ctx, c)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,13 @@ func decodeGetAllMetadataRequest(ctx context.Context, request interface{}) (inte
|
|||
}, nil
|
||||
}
|
||||
|
||||
func EncodeGetAllMetadataRequest(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
r := request.(endpoints.GetAllMetadataRequest)
|
||||
return protobuf.GetAllMetadataRequest{
|
||||
SourceHost: r.SourceHost,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeDumpResponse(ctx context.Context, response interface{}) (interface{}, error) {
|
||||
r := response.(endpoints.DumpResponse)
|
||||
return protobuf.DumpResponse{
|
||||
|
|
@ -50,28 +57,69 @@ func encodeMetadataStreamResponse(ctx context.Context, response interface{}) (in
|
|||
SourceHost: md.SourceHost,
|
||||
Primary: md.Primary,
|
||||
LoginUrl: md.LoginURL,
|
||||
Tag: md.Tag,
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return protobufMetadataStream{
|
||||
return ProtobufMetadataStream{
|
||||
Metadata: pbmdch,
|
||||
Errors: r.Errors,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type protobufMetadataStream struct {
|
||||
func DecodeMetdataStreamResponse(ctx context.Context, r ProtobufMetadataStream) (endpoints.MetadataStream, error) {
|
||||
mdch := make(chan types.Metadata, 1)
|
||||
errch := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
defer close(mdch)
|
||||
|
||||
for pbmd := range r.Metadata {
|
||||
createdAt, err := ptypes.Timestamp(pbmd.CreatedAt)
|
||||
if err != nil {
|
||||
errch <- err
|
||||
return
|
||||
}
|
||||
|
||||
updatedAt, err := ptypes.Timestamp(pbmd.UpdatedAt)
|
||||
if err != nil {
|
||||
errch <- err
|
||||
return
|
||||
}
|
||||
|
||||
mdch <- types.Metadata{
|
||||
ID: pbmd.Id,
|
||||
SourceHost: pbmd.SourceHost,
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: updatedAt,
|
||||
Primary: pbmd.Primary,
|
||||
LoginURL: pbmd.LoginUrl,
|
||||
Tag: pbmd.Tag,
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return endpoints.MetadataStream{
|
||||
Metadata: mdch,
|
||||
Errors: errch,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type ProtobufMetadataStream struct {
|
||||
Metadata <-chan protobuf.Metadata
|
||||
Errors chan error
|
||||
}
|
||||
|
||||
func decodeCredentialRequest(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
r := request.(protobuf.CredentialRequest)
|
||||
|
||||
return types.CredentialInput{
|
||||
MetadataInput: types.MetadataInput{
|
||||
Primary: r.Primary,
|
||||
LoginURL: r.LoginUrl,
|
||||
SourceHost: r.SourceHost,
|
||||
Tag: r.Tag,
|
||||
},
|
||||
Username: r.Username,
|
||||
Email: r.Email,
|
||||
|
|
@ -79,6 +127,18 @@ func decodeCredentialRequest(ctx context.Context, request interface{}) (interfac
|
|||
}, nil
|
||||
}
|
||||
|
||||
func EncodeCredentialRequest(r types.CredentialInput) protobuf.CredentialRequest {
|
||||
return protobuf.CredentialRequest{
|
||||
Primary: r.Primary,
|
||||
Username: r.Username,
|
||||
Email: r.Email,
|
||||
Password: r.Password,
|
||||
SourceHost: r.SourceHost,
|
||||
LoginUrl: r.LoginURL,
|
||||
Tag: r.Tag,
|
||||
}
|
||||
}
|
||||
|
||||
func encodeCredentialResponse(ctx context.Context, response interface{}) (interface{}, error) {
|
||||
r := response.(types.Credential)
|
||||
|
||||
|
|
@ -99,14 +159,44 @@ func encodeCredentialResponse(ctx context.Context, response interface{}) (interf
|
|||
Primary: r.Primary,
|
||||
SourceHost: r.SourceHost,
|
||||
LoginUrl: r.LoginURL,
|
||||
Tag: r.Tag,
|
||||
Username: r.Username,
|
||||
Email: r.Email,
|
||||
Password: r.Password,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func DecodeCredential(r protobuf.Credential) (c types.Credential, err error) {
|
||||
|
||||
createdAt, err := ptypes.Timestamp(r.CreatedAt)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
|
||||
updatedAt, err := ptypes.Timestamp(r.UpdatedAt)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
|
||||
return types.Credential{
|
||||
Metadata: types.Metadata{
|
||||
ID: r.Id,
|
||||
SourceHost: r.SourceHost,
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: updatedAt,
|
||||
Primary: r.Primary,
|
||||
LoginURL: r.LoginUrl,
|
||||
Tag: r.Tag,
|
||||
},
|
||||
Username: r.Username,
|
||||
Email: r.Email,
|
||||
Password: r.Password,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodeUpdateRequest(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
r := request.(protobuf.UpdateRequest)
|
||||
|
||||
return endpoints.UpdateRequest{
|
||||
ID: r.Id,
|
||||
Credential: types.CredentialInput{
|
||||
|
|
@ -114,6 +204,7 @@ func decodeUpdateRequest(ctx context.Context, request interface{}) (interface{},
|
|||
Primary: r.Credential.Primary,
|
||||
SourceHost: r.Credential.SourceHost,
|
||||
LoginURL: r.Credential.LoginUrl,
|
||||
Tag: r.Credential.Tag,
|
||||
},
|
||||
Username: r.Credential.Username,
|
||||
Email: r.Credential.Email,
|
||||
|
|
@ -122,6 +213,24 @@ func decodeUpdateRequest(ctx context.Context, request interface{}) (interface{},
|
|||
}, nil
|
||||
}
|
||||
|
||||
func EncodeUpdateRequest(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
r := request.(endpoints.UpdateRequest)
|
||||
|
||||
c := r.Credential
|
||||
return protobuf.UpdateRequest{
|
||||
Id: r.ID,
|
||||
Credential: &protobuf.CredentialRequest{
|
||||
Primary: c.Primary,
|
||||
Username: c.Username,
|
||||
Email: c.Email,
|
||||
Password: c.Password,
|
||||
SourceHost: c.SourceHost,
|
||||
LoginUrl: c.LoginURL,
|
||||
Tag: c.Tag,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodeIdRequest(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
r := request.(protobuf.IdRequest)
|
||||
return endpoints.IDRequest{
|
||||
|
|
@ -129,6 +238,12 @@ func decodeIdRequest(ctx context.Context, request interface{}) (interface{}, err
|
|||
}, nil
|
||||
}
|
||||
|
||||
func noOp(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
func EncodeIdRequest(r endpoints.IDRequest) protobuf.IdRequest {
|
||||
return protobuf.IdRequest{
|
||||
Id: r.ID,
|
||||
}
|
||||
}
|
||||
|
||||
func noOp(context.Context, interface{}) (interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ func (s GRPCServer) GetAllMetadata(r *protobuf.GetAllMetadataRequest, srv protob
|
|||
return err
|
||||
}
|
||||
|
||||
mds := i.(protobufMetadataStream)
|
||||
mds := i.(ProtobufMetadataStream)
|
||||
|
||||
receiveLoop:
|
||||
for {
|
||||
|
|
|
|||
|
|
@ -4,11 +4,13 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
const TypePrefixCred = "cred"
|
||||
|
||||
type Credential struct {
|
||||
Metadata
|
||||
Username string
|
||||
Email string
|
||||
Password string
|
||||
Password string `json:"-"`
|
||||
}
|
||||
|
||||
type CredentialInput struct {
|
||||
|
|
@ -25,10 +27,12 @@ type Metadata struct {
|
|||
UpdatedAt time.Time
|
||||
Primary string
|
||||
LoginURL string
|
||||
Tag string
|
||||
}
|
||||
|
||||
type MetadataInput struct {
|
||||
Primary string
|
||||
SourceHost string
|
||||
LoginURL string
|
||||
Tag string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,3 +18,13 @@ type CredentialRepo interface {
|
|||
Delete(ctx context.Context, id string) (err error)
|
||||
DumpDB(ctx context.Context) (bs []byte, err error)
|
||||
}
|
||||
|
||||
type CredentialClientInit func(ctx context.Context, target, ca, cert, key string) (c CredentialClient, err error)
|
||||
|
||||
type CredentialClient interface {
|
||||
GetAllMetadata(ctx context.Context, sourceHost string) (output <-chan Metadata, errch chan error)
|
||||
Get(ctx context.Context, id string) (output Credential, err error)
|
||||
Create(ctx context.Context, ci CredentialInput) (output Credential, err error)
|
||||
Update(ctx context.Context, id string, ci CredentialInput) (output Credential, err error)
|
||||
Delete(ctx context.Context, id string) (err error)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue