Implemented all but update from cli client to server;

solidified encryption;
setup deployment mechanism for GCP
This commit is contained in:
mitchell 2019-05-27 18:16:50 -07:00
parent cd24f6e848
commit c5ae0b4ddc
28 changed files with 598 additions and 295 deletions

View file

@ -1,63 +0,0 @@
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
}

View file

@ -1,4 +1,4 @@
package cmds
package commands
import (
"context"
@ -17,5 +17,4 @@ func check(err error) {
}
}
const KeyConnConfig = "connection"
const KeyPrivateKey = "private_key"

View file

@ -1,16 +1,15 @@
package cmds
package commands
import (
"context"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"math/rand"
"os"
"time"
"github.com/atotto/clipboard"
"github.com/pquerna/otp/totp"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"gopkg.in/AlecAivazis/survey.v1"
@ -19,7 +18,11 @@ import (
"github.com/mitchell/selfpass/crypto"
)
func MakeCreateCmd(masterpass string, cfg *viper.Viper, initClient CredentialClientInit) *cobra.Command {
func MakeCreate(masterpass string, cfg *viper.Viper, initClient CredentialClientInit) *cobra.Command {
var length uint
var numbers bool
var specials bool
createCmd := &cobra.Command{
Use: "create",
Short: "Create a credential in Selfpass",
@ -56,16 +59,21 @@ password.`,
},
}
var ci types.CredentialInput
check(survey.Ask(mdqs, &ci.MetadataInput))
check(survey.Ask(cqs, &ci))
key, err := hex.DecodeString(cfg.GetString(KeyPrivateKey))
check(err)
keypass, err := crypto.CombinePasswordAndKey([]byte(masterpass), []byte(key))
check(err)
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)
ci.Password = crypto.GeneratePassword(int(length), numbers, specials)
var copypass bool
prompt = &survey.Confirm{Message: "Copy new pass to clipboard?", Default: true}
@ -79,7 +87,7 @@ password.`,
check(survey.AskOne(prompt, &ci.Password, nil))
var cpass string
prompt = &survey.Password{Message: "Confirm assword: "}
prompt = &survey.Password{Message: "Confirm password: "}
check(survey.AskOne(prompt, &cpass, nil))
if ci.Password != cpass {
@ -88,59 +96,58 @@ password.`,
}
}
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)
var otp bool
prompt = &survey.Confirm{Message: "Do you have an OTP/MFA secret?", Default: true}
check(survey.AskOne(prompt, &otp, nil))
if otp {
var secret string
prompt := &survey.Password{Message: "OTP secret:"}
check(survey.AskOne(prompt, &secret, nil))
ciphersecret, err := crypto.CBCEncrypt(keypass, []byte(secret))
check(err)
ci.OTPSecret = base64.StdEncoding.EncodeToString(ciphersecret)
var copyotp bool
prompt2 := &survey.Confirm{Message: "Copy new OTP to clipboard?", Default: true}
check(survey.AskOne(prompt2, &copyotp, nil))
if copyotp {
otp, err := totp.GenerateCode(secret, time.Now())
check(err)
check(clipboard.WriteAll(otp))
}
}
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))
fmt.Println(c)
var cleancb bool
prompt = &survey.Confirm{Message: "Do you want to clear the clipboard?", Default: true}
check(survey.AskOne(prompt, &cleancb, nil))
if cleancb {
check(clipboard.WriteAll(" "))
}
},
}
createCmd.Flags().BoolVarP(&numbers, "numbers", "n", true, "use numbers in the generated password")
createCmd.Flags().BoolVarP(&specials, "specials", "s", false, "use special characters in the generated password")
createCmd.Flags().UintVarP(&length, "length", "l", 32, "length of the generated password")
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)
}

View file

@ -0,0 +1,33 @@
package commands
import (
"context"
"time"
"github.com/spf13/cobra"
"gopkg.in/AlecAivazis/survey.v1"
)
func MakeDelete(initConfig CredentialClientInit) *cobra.Command {
deleteCmd := &cobra.Command{
Use: "delete [id]",
Short: "Delete a credential using the given ID",
Long: `Delete a credential using the given ID, permanently. THERE IS NO UNDOING THIS ACTION.`,
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
var confirmed bool
prompt := &survey.Confirm{Message: "Are you sure you want to permanently delete this credential?"}
check(survey.AskOne(prompt, &confirmed, nil))
if confirmed {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()
check(initConfig(ctx).Delete(ctx, args[0]))
}
},
}
return deleteCmd
}

View file

@ -0,0 +1,92 @@
package commands
import (
"context"
"encoding/base64"
"encoding/hex"
"fmt"
"time"
"github.com/atotto/clipboard"
"github.com/pquerna/otp/totp"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"gopkg.in/AlecAivazis/survey.v1"
"github.com/mitchell/selfpass/crypto"
)
func MakeGet(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()
cred, err := initClient(ctx).Get(ctx, args[0])
check(err)
fmt.Println(cred)
check(clipboard.WriteAll(string(cred.Primary)))
fmt.Println("Wrote primary user key to clipboard.")
key, err := hex.DecodeString(cfg.GetString(KeyPrivateKey))
check(err)
passkey, err := crypto.CombinePasswordAndKey([]byte(masterpass), key)
check(err)
var copyPass bool
prompt := &survey.Confirm{Message: "Copy password to clipboard?", Default: true}
check(survey.AskOne(prompt, &copyPass, nil))
if copyPass {
passbytes, err := base64.StdEncoding.DecodeString(cred.Password)
check(err)
plainpass, err := crypto.CBCDecrypt(passkey, passbytes)
check(clipboard.WriteAll(string(plainpass)))
fmt.Println("Wrote password to clipboard.")
}
if cred.OTPSecret != "" {
var newOTP bool
prompt = &survey.Confirm{Message: "Generate one time password and copy to clipboard?", Default: true}
check(survey.AskOne(prompt, &newOTP, nil))
if newOTP {
secretbytes, err := base64.StdEncoding.DecodeString(cred.OTPSecret)
check(err)
plainsecret, err := crypto.CBCDecrypt(passkey, secretbytes)
otp, err := totp.GenerateCode(string(plainsecret), time.Now())
check(err)
check(clipboard.WriteAll(otp))
fmt.Println("Wrote one time password to clipboard.")
}
}
var cleancb bool
prompt = &survey.Confirm{Message: "Do you want to clear the clipboard?", Default: true}
check(survey.AskOne(prompt, &cleancb, nil))
if cleancb {
check(clipboard.WriteAll(" "))
}
},
}
return getCmd
}

View file

@ -1,15 +1,14 @@
package cmds
package commands
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/spf13/cobra"
)
func MakeListCmd(initClient CredentialClientInit) *cobra.Command {
func MakeList(initClient CredentialClientInit) *cobra.Command {
var sourceHost string
listCmd := &cobra.Command{
@ -38,11 +37,11 @@ includes almost all the information but the most sensitive.`,
break receive
}
mdjson, err := json.MarshalIndent(md, "", " ")
check(err)
fmt.Println(string(mdjson))
fmt.Println(md)
}
}
fmt.Println("Done listing.")
},
}

View file

@ -357,6 +357,7 @@ type Credential struct {
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"`
OtpSecret string `protobuf:"bytes,11,opt,name=otp_secret,json=otpSecret,proto3" json:"otp_secret,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -457,6 +458,13 @@ func (m *Credential) GetTag() string {
return ""
}
func (m *Credential) GetOtpSecret() string {
if m != nil {
return m.OtpSecret
}
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"`
@ -465,6 +473,7 @@ type CredentialRequest struct {
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"`
OtpSecret string `protobuf:"bytes,8,opt,name=otp_secret,json=otpSecret,proto3" json:"otp_secret,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -544,6 +553,13 @@ func (m *CredentialRequest) GetTag() string {
return ""
}
func (m *CredentialRequest) GetOtpSecret() string {
if m != nil {
return m.OtpSecret
}
return ""
}
func init() {
proto.RegisterType((*DeleteResponse)(nil), "selfpass.credentials.DeleteResponse")
proto.RegisterType((*GetAllMetadataRequest)(nil), "selfpass.credentials.GetAllMetadataRequest")
@ -559,41 +575,43 @@ func init() {
func init() { proto.RegisterFile("credentials/protobuf/service.proto", fileDescriptor_ad34efc7bbd96e69) }
var fileDescriptor_ad34efc7bbd96e69 = []byte{
// 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,
// 561 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x95, 0x4d, 0x6f, 0xd3, 0x4c,
0x10, 0xc7, 0xe5, 0xa4, 0x4d, 0xed, 0x69, 0x9f, 0xe8, 0x61, 0x55, 0x24, 0xcb, 0x15, 0x24, 0x32,
0x48, 0x54, 0x45, 0x72, 0x51, 0xb9, 0xc0, 0x31, 0xb4, 0x28, 0xe5, 0x80, 0x90, 0x1c, 0x7a, 0xe1,
0x12, 0x6d, 0xed, 0x69, 0x6a, 0xc9, 0xf6, 0x9a, 0xdd, 0x31, 0xa8, 0x1f, 0x8c, 0x0f, 0x05, 0x1f,
0x81, 0x13, 0xf2, 0xfa, 0x25, 0x2f, 0x75, 0x9a, 0x48, 0x5c, 0xb8, 0xed, 0x8c, 0xff, 0xb3, 0x9a,
0xdf, 0xec, 0xee, 0xdf, 0xe0, 0x06, 0x12, 0x43, 0x4c, 0x29, 0xe2, 0xb1, 0x3a, 0xcd, 0xa4, 0x20,
0x71, 0x9d, 0xdf, 0x9c, 0x2a, 0x94, 0xdf, 0xa2, 0x00, 0x3d, 0x9d, 0x60, 0x87, 0x0a, 0xe3, 0x9b,
0x8c, 0x2b, 0xe5, 0x2d, 0x88, 0x9d, 0xc1, 0x4c, 0x88, 0x59, 0x8c, 0xf3, 0x22, 0x8a, 0x12, 0x54,
0xc4, 0x93, 0xac, 0x2c, 0x73, 0x4f, 0xa0, 0x7f, 0x81, 0x31, 0x12, 0xfa, 0xa8, 0x32, 0x91, 0x2a,
0x64, 0x36, 0xec, 0xa9, 0x3c, 0x08, 0x50, 0x29, 0xdb, 0x18, 0x1a, 0xc7, 0xa6, 0x5f, 0x87, 0xee,
0x1b, 0x78, 0x3c, 0x46, 0x1a, 0xc5, 0xf1, 0x47, 0x24, 0x1e, 0x72, 0xe2, 0x3e, 0x7e, 0xcd, 0x51,
0x11, 0x1b, 0xc0, 0xbe, 0x12, 0xb9, 0x0c, 0x70, 0x7a, 0x2b, 0x14, 0xe9, 0x32, 0xcb, 0x87, 0x32,
0x75, 0x29, 0x14, 0xb9, 0x47, 0x60, 0x7d, 0x08, 0x6b, 0x75, 0x1f, 0x3a, 0x51, 0x58, 0x89, 0x3a,
0x51, 0xe8, 0xde, 0xc2, 0x7f, 0x57, 0x59, 0xc8, 0x8b, 0x16, 0x5a, 0x05, 0x6c, 0x0c, 0x30, 0x67,
0xb2, 0x3b, 0x43, 0xe3, 0x78, 0xff, 0xec, 0x85, 0xd7, 0xc6, 0xeb, 0x9d, 0x37, 0xeb, 0x6a, 0x33,
0x7f, 0xa1, 0xd4, 0x3d, 0x81, 0x83, 0x8b, 0x3c, 0xc9, 0x1a, 0x54, 0x07, 0xcc, 0x40, 0xa4, 0x84,
0x29, 0x95, 0xac, 0x07, 0x7e, 0x13, 0xbb, 0x7d, 0x38, 0x78, 0x9f, 0x64, 0x74, 0x57, 0xed, 0xe3,
0xfe, 0x36, 0xc0, 0xac, 0xb9, 0xef, 0x75, 0xf8, 0x56, 0x77, 0xc8, 0x09, 0xc3, 0x29, 0xa7, 0xaa,
0x43, 0xc7, 0x2b, 0x67, 0xef, 0xd5, 0xb3, 0xf7, 0x3e, 0xd7, 0xb3, 0xf7, 0xad, 0x4a, 0x3d, 0xa2,
0xa2, 0x34, 0xd7, 0xf4, 0xba, 0xb4, 0xbb, 0xb9, 0xb4, 0x52, 0x8f, 0xa8, 0x38, 0xa9, 0x4c, 0x46,
0x09, 0x97, 0x77, 0xf6, 0x8e, 0x6e, 0xa5, 0x0e, 0x57, 0x0f, 0x64, 0x77, 0xf5, 0x40, 0xd8, 0x11,
0x58, 0xb1, 0x98, 0x45, 0xe9, 0x34, 0x97, 0xb1, 0xdd, 0xd3, 0x9f, 0x4d, 0x9d, 0xb8, 0x92, 0x31,
0xfb, 0x1f, 0xba, 0xc4, 0x67, 0xf6, 0x9e, 0x4e, 0x17, 0x4b, 0xf7, 0x67, 0x07, 0x60, 0x3e, 0xda,
0x7f, 0x1e, 0xdf, 0x01, 0x33, 0x57, 0x28, 0x53, 0x9e, 0x60, 0xc5, 0xde, 0xc4, 0xec, 0x10, 0x76,
0x31, 0xe1, 0x51, 0x4d, 0x5d, 0x06, 0x45, 0x45, 0x71, 0x97, 0xbe, 0x0b, 0x19, 0x56, 0xdc, 0x4d,
0xbc, 0x3a, 0x4c, 0xf3, 0xe1, 0x61, 0x5a, 0xed, 0xc3, 0x84, 0x66, 0x98, 0xec, 0x09, 0x80, 0xa0,
0x6c, 0xaa, 0x30, 0x90, 0x48, 0xf6, 0xbe, 0xfe, 0x60, 0x09, 0xca, 0x26, 0x3a, 0xe1, 0xfe, 0x32,
0xe0, 0xd1, 0xbd, 0x6b, 0xbc, 0x08, 0x6b, 0xac, 0x87, 0xed, 0xac, 0x83, 0xed, 0xae, 0x83, 0xdd,
0x79, 0x18, 0xf6, 0x6f, 0x6f, 0xce, 0x0a, 0xac, 0xb9, 0x02, 0x7b, 0xf6, 0xa3, 0xbb, 0x08, 0x3b,
0x29, 0x1d, 0x8d, 0x4d, 0xa1, 0xbf, 0x6c, 0x34, 0xec, 0x65, 0xfb, 0x73, 0x6f, 0xb5, 0x23, 0xe7,
0x69, 0xbb, 0xb8, 0x96, 0xbd, 0x32, 0xd8, 0x25, 0x74, 0xc7, 0x48, 0x6c, 0xd0, 0x2e, 0x6c, 0xac,
0xca, 0x19, 0x6e, 0x72, 0x19, 0x36, 0x81, 0xde, 0xb9, 0xbe, 0xcc, 0x6c, 0x5b, 0x47, 0xda, 0x62,
0xd3, 0x4f, 0xd0, 0x2b, 0x1d, 0x91, 0x3d, 0x6b, 0xd7, 0x2e, 0xf9, 0xe5, 0x76, 0x1b, 0x96, 0x2e,
0xbf, 0x19, 0xf9, 0x79, 0xbb, 0x60, 0xf9, 0x27, 0xf1, 0x0e, 0xbe, 0x98, 0xf5, 0xe3, 0xbc, 0xee,
0xe9, 0xd5, 0xeb, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xde, 0x03, 0x4f, 0xb2, 0xa6, 0x06, 0x00,
0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

View file

@ -60,6 +60,7 @@ message Credential {
string source_host = 8;
string login_url = 9;
string tag = 10;
string otp_secret = 11;
}
message CredentialRequest {
@ -70,4 +71,5 @@ message CredentialRequest {
string source_host = 5;
string login_url = 6;
string tag = 7;
string otp_secret = 8;
}

View file

@ -7,12 +7,13 @@ import (
"fmt"
"io"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"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) {
@ -34,16 +35,16 @@ func NewCredentialServiceClient(ctx context.Context, target, ca, cert, key strin
return nil, err
}
return CredentialServiceClient{
return credentialServiceClient{
client: protobuf.NewCredentialServiceClient(conn),
}, nil
}
type CredentialServiceClient struct {
type credentialServiceClient struct {
client protobuf.CredentialServiceClient
}
func (c CredentialServiceClient) GetAllMetadata(ctx context.Context, sourceHost string) (output <-chan types.Metadata, errch chan error) {
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)
@ -84,7 +85,7 @@ func (c CredentialServiceClient) GetAllMetadata(ctx context.Context, sourceHost
return stream.Metadata, stream.Errors
}
func (c CredentialServiceClient) Get(ctx context.Context, id string) (output types.Credential, err error) {
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)
@ -95,7 +96,7 @@ func (c CredentialServiceClient) Get(ctx context.Context, id string) (output typ
return transport.DecodeCredential(*res)
}
func (c CredentialServiceClient) Create(ctx context.Context, ci types.CredentialInput) (output types.Credential, err error) {
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)
@ -106,10 +107,26 @@ func (c CredentialServiceClient) Create(ctx context.Context, ci types.Credential
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) Update(ctx context.Context, id string, ci types.CredentialInput) (output types.Credential, err error) {
req := transport.EncodeUpdateRequest(endpoints.UpdateRequest{ID: id, Credential: ci})
res, err := c.client.Update(ctx, &req)
if err != nil {
return output, err
}
return transport.DecodeCredential(*res)
}
func (c CredentialServiceClient) Delete(ctx context.Context, id string) (err error) {
panic("implement me")
func (c credentialServiceClient) Delete(ctx context.Context, id string) (err error) {
req := transport.EncodeIdRequest(endpoints.IDRequest{ID: id})
res, err := c.client.Delete(ctx, &req)
if err != nil {
return err
}
if !res.Success {
return fmt.Errorf("delete unsuccessful")
}
return nil
}

View file

@ -46,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.OTPSecret = ci.OTPSecret
c.Tag = ci.Tag
err = svc.repo.Put(ctx, c)
@ -97,6 +98,7 @@ func (svc Credentials) Update(ctx context.Context, id string, ci types.Credentia
c.LoginURL = ci.LoginURL
c.SourceHost = ci.SourceHost
c.Password = ci.Password
c.OTPSecret = ci.OTPSecret
c.Email = ci.Email
c.Username = ci.Username
c.Tag = ci.Tag

View file

@ -4,6 +4,7 @@ import (
"context"
"github.com/golang/protobuf/ptypes"
"github.com/mitchell/selfpass/credentials/endpoints"
"github.com/mitchell/selfpass/credentials/protobuf"
"github.com/mitchell/selfpass/credentials/types"
@ -121,9 +122,10 @@ func decodeCredentialRequest(ctx context.Context, request interface{}) (interfac
SourceHost: r.SourceHost,
Tag: r.Tag,
},
Username: r.Username,
Email: r.Email,
Password: r.Password,
Username: r.Username,
Email: r.Email,
Password: r.Password,
OTPSecret: r.OtpSecret,
}, nil
}
@ -133,6 +135,7 @@ func EncodeCredentialRequest(r types.CredentialInput) protobuf.CredentialRequest
Username: r.Username,
Email: r.Email,
Password: r.Password,
OtpSecret: r.OTPSecret,
SourceHost: r.SourceHost,
LoginUrl: r.LoginURL,
Tag: r.Tag,
@ -163,6 +166,7 @@ func encodeCredentialResponse(ctx context.Context, response interface{}) (interf
Username: r.Username,
Email: r.Email,
Password: r.Password,
OtpSecret: r.OTPSecret,
}, nil
}
@ -188,9 +192,10 @@ func DecodeCredential(r protobuf.Credential) (c types.Credential, err error) {
LoginURL: r.LoginUrl,
Tag: r.Tag,
},
Username: r.Username,
Email: r.Email,
Password: r.Password,
Username: r.Username,
Email: r.Email,
Password: r.Password,
OTPSecret: r.OtpSecret,
}, nil
}
@ -206,16 +211,15 @@ func decodeUpdateRequest(ctx context.Context, request interface{}) (interface{},
LoginURL: r.Credential.LoginUrl,
Tag: r.Credential.Tag,
},
Username: r.Credential.Username,
Email: r.Credential.Email,
Password: r.Credential.Password,
Username: r.Credential.Username,
Email: r.Credential.Email,
Password: r.Credential.Password,
OTPSecret: r.Credential.OtpSecret,
},
}, nil
}
func EncodeUpdateRequest(ctx context.Context, request interface{}) (interface{}, error) {
r := request.(endpoints.UpdateRequest)
func EncodeUpdateRequest(r endpoints.UpdateRequest) protobuf.UpdateRequest {
c := r.Credential
return protobuf.UpdateRequest{
Id: r.ID,
@ -224,11 +228,12 @@ func EncodeUpdateRequest(ctx context.Context, request interface{}) (interface{},
Username: c.Username,
Email: c.Email,
Password: c.Password,
OtpSecret: c.OTPSecret,
SourceHost: c.SourceHost,
LoginUrl: c.LoginURL,
Tag: c.Tag,
},
}, nil
}
}
func decodeIdRequest(ctx context.Context, request interface{}) (interface{}, error) {

View file

@ -1,6 +1,7 @@
package types
import (
"fmt"
"time"
)
@ -8,16 +9,25 @@ const TypePrefixCred = "cred"
type Credential struct {
Metadata
Username string
Email string
Password string `json:"-"`
Username string
Email string
Password string `json:"-"`
OTPSecret string `json:"-"`
}
func (c Credential) String() string {
return fmt.Sprintf(
"username = %s\nemail = %s\n%s",
c.Username, c.Email, c.Metadata,
)
}
type CredentialInput struct {
MetadataInput
Username string
Email string
Password string
Username string
Email string
Password string
OTPSecret string
}
type Metadata struct {
@ -30,6 +40,13 @@ type Metadata struct {
Tag string
}
func (m Metadata) String() string {
return fmt.Sprintf(
"id = %s\nsourceHost = %s\ncreatedAt = %s\nupdatedAt = %s\nprimary = %s\nloginUrl = %s\ntag = %s\n",
m.ID, m.SourceHost, m.CreatedAt, m.UpdatedAt, m.Primary, m.LoginURL, m.Tag,
)
}
type MetadataInput struct {
Primary string
SourceHost string