This commit is contained in:
Neeraj Gupta 2023-09-23 16:15:10 +05:30
parent c5f978d32b
commit 02ff452c09
10 changed files with 89 additions and 77 deletions

View file

@ -1,4 +1,4 @@
package pkg package internal
import ( import (
"cli-go/internal/api" "cli-go/internal/api"

View file

@ -4,6 +4,7 @@ import (
"cli-go/cmd" "cli-go/cmd"
"cli-go/internal/api" "cli-go/internal/api"
"cli-go/pkg" "cli-go/pkg"
"cli-go/pkg/secrets"
) )
func main() { func main() {
@ -17,8 +18,8 @@ func main() {
Host: "http://localhost:8080", Host: "http://localhost:8080",
}), }),
DB: db, DB: db,
CliKey: pkg.GetOrCreateClISecret(), CliKey: secrets.GetOrCreateClISecret(),
KeyHolder: pkg.NewKeyHolder(), KeyHolder: secrets.NewKeyHolder(),
} }
err = ctrl.Init() err = ctrl.Init()
if err != nil { if err != nil {

View file

@ -1,6 +1,7 @@
package pkg package pkg
import ( import (
"cli-go/internal"
"cli-go/internal/api" "cli-go/internal/api"
"cli-go/pkg/model" "cli-go/pkg/model"
"cli-go/utils/encoding" "cli-go/utils/encoding"
@ -21,9 +22,9 @@ func (c *ClICtrl) AddAccount(cxt context.Context) {
log.Fatal(flowErr) log.Fatal(flowErr)
} }
}() }()
app := GetAppType() app := internal.GetAppType()
cxt = context.WithValue(cxt, "app", string(app)) cxt = context.WithValue(cxt, "app", string(app))
email, flowErr := GetUserInput("Enter email address") email, flowErr := internal.GetUserInput("Enter email address")
if flowErr != nil { if flowErr != nil {
return return
} }
@ -69,7 +70,7 @@ func (c *ClICtrl) AddAccount(cxt context.Context) {
} }
} }
func (c *ClICtrl) storeAccount(_ context.Context, email string, userID int64, app api.App, secretInfo *accSecretInfo) error { func (c *ClICtrl) storeAccount(_ context.Context, email string, userID int64, app api.App, secretInfo *model.AccSecretInfo) error {
// get password // get password
secret := c.CliKey secret := c.CliKey
err := c.DB.Update(func(tx *bolt.Tx) error { err := c.DB.Update(func(tx *bolt.Tx) error {

57
pkg/collections.go Normal file
View file

@ -0,0 +1,57 @@
package pkg
import (
"cli-go/internal/api"
enteCrypto "cli-go/internal/crypto"
"cli-go/pkg/model"
"cli-go/utils/encoding"
"context"
"fmt"
"log"
)
func (c *ClICtrl) syncRemoteCollections(ctx context.Context, info model.Account) error {
collections, err := c.Client.GetCollections(ctx, 0)
if err != nil {
return fmt.Errorf("failed to get collections: %s", err)
}
for _, collection := range collections {
collectionKey, err := c.getCollectionKey(ctx, collection)
if err != nil {
return err
}
name, nameErr := enteCrypto.SecretBoxOpenBase64(collection.EncryptedName, collection.NameDecryptionNonce, collectionKey)
if nameErr != nil {
log.Fatalf("failed to decrypt collection name: %v", nameErr)
}
if collection.Owner.ID != info.UserID {
fmt.Printf("Shared Album %s\n", string(name))
continue
} else {
fmt.Printf("Owned Name %s\n", string(name))
}
}
return nil
}
func (c *ClICtrl) getCollectionKey(ctx context.Context, collection api.Collection) ([]byte, error) {
accSecretInfo := c.KeyHolder.GetAccountSecretInfo(ctx)
userID := ctx.Value("user_id").(int64)
if collection.Owner.ID == userID {
collKey, err := enteCrypto.SecretBoxOpen(
encoding.DecodeBase64(collection.EncryptedKey),
encoding.DecodeBase64(collection.KeyDecryptionNonce),
accSecretInfo.MasterKey)
if err != nil {
log.Fatalf("failed to decrypt collection key %s", err)
}
return collKey, nil
} else {
collKey, err := enteCrypto.SealedBoxOpen(encoding.DecodeBase64(collection.EncryptedKey),
accSecretInfo.PublicKey, accSecretInfo.SecretKey)
if err != nil {
log.Fatalf("failed to decrypt collection key %s", err)
}
return collKey, nil
}
}

View file

@ -2,6 +2,7 @@ package pkg
import ( import (
"cli-go/internal/api" "cli-go/internal/api"
"cli-go/pkg/secrets"
"fmt" "fmt"
bolt "go.etcd.io/bbolt" bolt "go.etcd.io/bbolt"
) )
@ -11,7 +12,7 @@ type ClICtrl struct {
DB *bolt.DB DB *bolt.DB
// CliKey is the key used to encrypt/decrypt sensitive data stored in the database // CliKey is the key used to encrypt/decrypt sensitive data stored in the database
CliKey []byte CliKey []byte
KeyHolder *KeyHolder KeyHolder *secrets.KeyHolder
} }
func (c *ClICtrl) Init() error { func (c *ClICtrl) Init() error {

View file

@ -23,3 +23,10 @@ func (a *Account) AccountKey() string {
func (a *Account) DataBucket() string { func (a *Account) DataBucket() string {
return fmt.Sprintf("%s-%d-data", a.App, a.UserID) return fmt.Sprintf("%s-%d-data", a.App, a.UserID)
} }
type AccSecretInfo struct {
MasterKey []byte
SecretKey []byte
Token []byte
PublicKey []byte
}

View file

@ -1,10 +1,7 @@
package pkg package pkg
import ( import (
"cli-go/internal/api"
enteCrypto "cli-go/internal/crypto"
"cli-go/pkg/model" "cli-go/pkg/model"
"cli-go/utils/encoding"
"context" "context"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
@ -51,50 +48,3 @@ func createDataBuckets(db *bolt.DB, account model.Account) error {
return nil return nil
}) })
} }
func (c *ClICtrl) syncRemoteCollections(ctx context.Context, info model.Account) error {
collections, err := c.Client.GetCollections(ctx, 0)
if err != nil {
return fmt.Errorf("failed to get collections: %s", err)
}
for _, collection := range collections {
collectionKey, err := c.getCollectionKey(ctx, collection)
if err != nil {
return err
}
name, nameErr := enteCrypto.SecretBoxOpenBase64(collection.EncryptedName, collection.NameDecryptionNonce, collectionKey)
if nameErr != nil {
log.Fatalf("failed to decrypt collection name: %v", nameErr)
}
if collection.Owner.ID != info.UserID {
fmt.Printf("Shared Album %s\n", string(name))
continue
} else {
fmt.Printf("Owned Name %s\n", string(name))
}
}
return nil
}
func (c *ClICtrl) getCollectionKey(ctx context.Context, collection api.Collection) ([]byte, error) {
accSecretInfo := c.KeyHolder.GetAccountSecretInfo(ctx)
userID := ctx.Value("user_id").(int64)
if collection.Owner.ID == userID {
collKey, err := enteCrypto.SecretBoxOpen(
encoding.DecodeBase64(collection.EncryptedKey),
encoding.DecodeBase64(collection.KeyDecryptionNonce),
accSecretInfo.MasterKey)
if err != nil {
log.Fatalf("failed to decrypt collection key %s", err)
}
return collKey, nil
} else {
collKey, err := enteCrypto.SealedBoxOpen(encoding.DecodeBase64(collection.EncryptedKey),
accSecretInfo.PublicKey, accSecretInfo.SecretKey)
if err != nil {
log.Fatalf("failed to decrypt collection key %s", err)
}
return collKey, nil
}
}

View file

@ -1,4 +1,4 @@
package pkg package secrets
import ( import (
"cli-go/pkg/model" "cli-go/pkg/model"
@ -7,22 +7,22 @@ import (
) )
type KeyHolder struct { type KeyHolder struct {
AccountSecrets map[string]*accSecretInfo AccountSecrets map[string]*model.AccSecretInfo
CollectionKeys map[string][]byte CollectionKeys map[string][]byte
} }
func NewKeyHolder() *KeyHolder { func NewKeyHolder() *KeyHolder {
return &KeyHolder{ return &KeyHolder{
AccountSecrets: make(map[string]*accSecretInfo), AccountSecrets: make(map[string]*model.AccSecretInfo),
CollectionKeys: make(map[string][]byte), CollectionKeys: make(map[string][]byte),
} }
} }
func (k *KeyHolder) LoadSecrets(account model.Account, cliKey []byte) (*accSecretInfo, error) { func (k *KeyHolder) LoadSecrets(account model.Account, cliKey []byte) (*model.AccSecretInfo, error) {
tokenKey := account.Token.MustDecrypt(cliKey) tokenKey := account.Token.MustDecrypt(cliKey)
masterKey := account.MasterKey.MustDecrypt(cliKey) masterKey := account.MasterKey.MustDecrypt(cliKey)
secretKey := account.SecretKey.MustDecrypt(cliKey) secretKey := account.SecretKey.MustDecrypt(cliKey)
k.AccountSecrets[account.AccountKey()] = &accSecretInfo{ k.AccountSecrets[account.AccountKey()] = &model.AccSecretInfo{
Token: tokenKey, Token: tokenKey,
MasterKey: masterKey, MasterKey: masterKey,
SecretKey: secretKey, SecretKey: secretKey,
@ -31,7 +31,7 @@ func (k *KeyHolder) LoadSecrets(account model.Account, cliKey []byte) (*accSecre
return k.AccountSecrets[account.AccountKey()], nil return k.AccountSecrets[account.AccountKey()], nil
} }
func (k *KeyHolder) GetAccountSecretInfo(ctx context.Context) *accSecretInfo { func (k *KeyHolder) GetAccountSecretInfo(ctx context.Context) *model.AccSecretInfo {
accountKey := ctx.Value("account_id").(string) accountKey := ctx.Value("account_id").(string)
return k.AccountSecrets[accountKey] return k.AccountSecrets[accountKey]
} }

View file

@ -1,4 +1,4 @@
package pkg package secrets
import ( import (
"crypto/rand" "crypto/rand"

View file

@ -1,8 +1,10 @@
package pkg package pkg
import ( import (
"cli-go/internal"
"cli-go/internal/api" "cli-go/internal/api"
enteCrypto "cli-go/internal/crypto" enteCrypto "cli-go/internal/crypto"
"cli-go/pkg/model"
"cli-go/utils/encoding" "cli-go/utils/encoding"
"context" "context"
"fmt" "fmt"
@ -11,17 +13,10 @@ import (
"github.com/kong/go-srp" "github.com/kong/go-srp"
) )
type accSecretInfo struct {
MasterKey []byte
SecretKey []byte
Token []byte
PublicKey []byte
}
func (c *ClICtrl) signInViaPassword(ctx context.Context, email string, srpAttr *api.SRPAttributes) (*api.AuthorizationResponse, []byte, error) { func (c *ClICtrl) signInViaPassword(ctx context.Context, email string, srpAttr *api.SRPAttributes) (*api.AuthorizationResponse, []byte, error) {
for { for {
// CLI prompt for password // CLI prompt for password
password, flowErr := GetSensitiveField("Enter password") password, flowErr := internal.GetSensitiveField("Enter password")
if flowErr != nil { if flowErr != nil {
return nil, nil, flowErr return nil, nil, flowErr
} }
@ -62,7 +57,7 @@ func (c *ClICtrl) decryptAccSecretInfo(
_ context.Context, _ context.Context,
authResp *api.AuthorizationResponse, authResp *api.AuthorizationResponse,
keyEncKey []byte, keyEncKey []byte,
) (*accSecretInfo, error) { ) (*model.AccSecretInfo, error) {
var currentKeyEncKey []byte var currentKeyEncKey []byte
var err error var err error
var masterKey, secretKey, tokenKey []byte var masterKey, secretKey, tokenKey []byte
@ -70,7 +65,7 @@ func (c *ClICtrl) decryptAccSecretInfo(
for { for {
if keyEncKey == nil { if keyEncKey == nil {
// CLI prompt for password // CLI prompt for password
password, flowErr := GetSensitiveField("Enter password") password, flowErr := internal.GetSensitiveField("Enter password")
if flowErr != nil { if flowErr != nil {
return nil, flowErr return nil, flowErr
} }
@ -117,7 +112,7 @@ func (c *ClICtrl) decryptAccSecretInfo(
} }
break break
} }
return &accSecretInfo{ return &model.AccSecretInfo{
MasterKey: masterKey, MasterKey: masterKey,
SecretKey: secretKey, SecretKey: secretKey,
Token: tokenKey, Token: tokenKey,
@ -131,7 +126,7 @@ func (c *ClICtrl) validateTOTP(ctx context.Context, authResp *api.AuthorizationR
} }
for { for {
// CLI prompt for TOTP // CLI prompt for TOTP
totp, flowErr := GetCode("Enter TOTP", 6) totp, flowErr := internal.GetCode("Enter TOTP", 6)
if flowErr != nil { if flowErr != nil {
return nil, flowErr return nil, flowErr
} }
@ -151,7 +146,7 @@ func (c *ClICtrl) validateEmail(ctx context.Context, email string) (*api.Authori
} }
for { for {
// CLI prompt for OTP // CLI prompt for OTP
ott, flowErr := GetCode("Enter OTP", 6) ott, flowErr := internal.GetCode("Enter OTP", 6)
if flowErr != nil { if flowErr != nil {
return nil, flowErr return nil, flowErr
} }