Merge branch 'master' into discovery
diff --git a/cmd/sb/shell.go b/cmd/sb/shell.go
index e3bfe93..9d5e2e2 100644
--- a/cmd/sb/shell.go
+++ b/cmd/sb/shell.go
@@ -169,7 +169,18 @@
return d, nil
}
-func dumpDB(ctx *context.T, w io.Writer, d nosql.Database) error {
+func mergeErrors(errs []error) error {
+ if len(errs) == 0 {
+ return nil
+ }
+ err := errs[0]
+ for _, e := range errs[1:] {
+ err = fmt.Errorf("%v\n%v", err, e)
+ }
+ return err
+}
+
+func dumpTables(ctx *context.T, w io.Writer, d nosql.Database) error {
tables, err := d.ListTables(ctx)
if err != nil {
return fmt.Errorf("failed listing tables: %v", err)
@@ -182,15 +193,43 @@
}
}
if len(errs) > 0 {
- err := fmt.Errorf("failed dumping %d of %d tables:", len(errs), len(tables))
- for _, e := range errs {
- err = fmt.Errorf("%v\n%v", err, e)
- }
- return err
+ return fmt.Errorf("failed dumping %d of %d tables:\n%v", len(errs), len(tables), mergeErrors(errs))
}
return nil
}
+func dumpSyncgroups(ctx *context.T, w io.Writer, d nosql.Database) error {
+ sgNames, err := d.GetSyncgroupNames(ctx)
+ if err != nil {
+ return fmt.Errorf("failed listing syncgroups: %v", err)
+ }
+ var errs []error
+ for _, sgName := range sgNames {
+ fmt.Fprintf(w, "syncgroup: %s\n", sgName)
+ sg := d.Syncgroup(sgName)
+ if spec, version, err := sg.GetSpec(ctx); err != nil {
+ errs = append(errs, err)
+ } else {
+ fmt.Fprintf(w, "%+v (version: \"%s\")\n", spec, version)
+ }
+ }
+ if len(errs) > 0 {
+ return fmt.Errorf("failed dumping %d of %d syncgroups:\n%v", len(errs), len(sgNames), mergeErrors(errs))
+ }
+ return nil
+}
+
+func dumpDB(ctx *context.T, w io.Writer, d nosql.Database) error {
+ var errors []error
+ if err := dumpTables(ctx, w, d); err != nil {
+ errors = append(errors, fmt.Errorf("failed dumping tables: %v", err))
+ }
+ if err := dumpSyncgroups(ctx, w, d); err != nil {
+ errors = append(errors, fmt.Errorf("failed dumping syncgroups: %v", err))
+ }
+ return mergeErrors(errors)
+}
+
func makeDemoDB(ctx *context.T, w io.Writer, d nosql.Database) error {
if err := demodb.PopulateDemoDB(ctx, d); err == nil {
fmt.Fprintln(w, "Demo tables created and populated.")
diff --git a/lib/security/bcrypter/crypter.go b/lib/security/bcrypter/crypter.go
index 5e93126..5b59829 100644
--- a/lib/security/bcrypter/crypter.go
+++ b/lib/security/bcrypter/crypter.go
@@ -88,15 +88,15 @@
keys []ibe.PrivateKey
}
-// Encrypt encrypts the provided fixed-length 'plaintext' so that it can
-// only be decrypted by a crypter possessing a private key for a blessing
-// matching the provided blessing pattern.
+// Encrypt encrypts the provided 'plaintext' so that it can only be decrypted
+// by a crypter possessing a private key for a blessing matching the provided
+// blessing pattern.
//
// Encryption makes use of the public parameters of the identity provider
// that is authoritative on the set of blessings that match the provided
// blessing pattern. These paramaters must have been previously added to
// this crypter via AddParams.
-func (c *Crypter) Encrypt(ctx *context.T, forPattern security.BlessingPattern, plaintext *[32]byte) (*Ciphertext, error) {
+func (c *Crypter) Encrypt(ctx *context.T, forPattern security.BlessingPattern, plaintext []byte) (*Ciphertext, error) {
if !forPattern.IsValid() {
return nil, fmt.Errorf("provided blessing pattern %v is invalid", forPattern)
}
@@ -109,8 +109,8 @@
continue
}
for _, ibeParams := range ibeParamsList {
- ctxt := make([]byte, ibe.CiphertextSize)
- if err := ibeParams.Encrypt(string(forPattern), (*plaintext)[:], ctxt); err != nil {
+ ctxt := make([]byte, len(plaintext)+ibeParams.CiphertextOverhead())
+ if err := ibeParams.Encrypt(string(forPattern), plaintext, ctxt); err != nil {
return nil, NewErrInternal(ctx, err)
}
paramsId, err := idParams(ibeParams)
@@ -127,16 +127,24 @@
return ciphertext, nil
}
+func decrypt(key ibe.PrivateKey, ciphertext []byte) ([]byte, error) {
+ overhead := key.Params().CiphertextOverhead()
+ if got := len(ciphertext); got < overhead {
+ return nil, fmt.Errorf("ciphertext is of size %v bytes, want at least %v bytes", got, overhead)
+ }
+ plaintext := make([]byte, len(ciphertext)-overhead)
+ if err := key.Decrypt(ciphertext, plaintext); err != nil {
+ return nil, err
+ }
+ return plaintext, nil
+}
+
// Decrypt decrypts the provided 'ciphertext' and returns the corresponding
// plaintext.
//
// Decryption succeeds only if this crypter possesses a private key for a
// blessing that matches the blessing pattern corresponding to the ciphertext.
-func (c *Crypter) Decrypt(ctx *context.T, ciphertext *Ciphertext) (*[32]byte, error) {
- var (
- plaintext [32]byte
- keyFound bool
- )
+func (c *Crypter) Decrypt(ctx *context.T, ciphertext *Ciphertext) ([]byte, error) {
c.mu.RLock()
defer c.mu.RUnlock()
for paramsId, cbytes := range ciphertext.wire.Bytes {
@@ -144,16 +152,13 @@
continue
} else if key, found := keys[ciphertext.wire.PatternId]; !found {
continue
- } else if err := key.Decrypt(cbytes, plaintext[:]); err != nil {
- return nil, NewErrInternal(ctx, err)
+ } else if ptxt, err := decrypt(key, cbytes); err != nil {
+ return nil, err
+ } else {
+ return ptxt, nil
}
- keyFound = true
- break
}
- if !keyFound {
- return nil, NewErrPrivateKeyNotFound(ctx)
- }
- return &plaintext, nil
+ return nil, NewErrPrivateKeyNotFound(ctx)
}
// AddKey adds the provided private key 'key' and the associated public
diff --git a/lib/security/bcrypter/crypter_test.go b/lib/security/bcrypter/crypter_test.go
index cea179c..7efaf28 100644
--- a/lib/security/bcrypter/crypter_test.go
+++ b/lib/security/bcrypter/crypter_test.go
@@ -25,12 +25,8 @@
return NewRoot(name, master)
}
-func newPlaintext() [32]byte {
- var m [32]byte
- if n := copy(m[:], []byte("AThirtyTwoBytePieceOfTextThisIs!")); n != len(m) {
- panic(fmt.Errorf("plaintext string must be %d bytes, not %d", len(m), n))
- }
- return m
+func newPlaintext() []byte {
+ return []byte("AThirtyTwoBytePieceOfTextThisIs!")
}
func TextExtract(t *testing.T) {
@@ -79,7 +75,7 @@
)
// empty encrypter should not be able to encrypt for any pattern.
- if _, err := encrypter.Encrypt(ctx, "google/youtube/alice", &ptxt); verror.ErrorID(err) != ErrNoParams.ID {
+ if _, err := encrypter.Encrypt(ctx, "google/youtube/alice", ptxt); verror.ErrorID(err) != ErrNoParams.ID {
t.Fatalf("Got error %v, wanted error with ID %v", err, ErrNoParams.ID)
}
@@ -88,7 +84,7 @@
t.Fatal(err)
}
// encrypting for "google/youtube/alice" should now succeed.
- if _, err := encrypter.Encrypt(ctx, "google/youtube/alice", &ptxt); err != nil {
+ if _, err := encrypter.Encrypt(ctx, "google/youtube/alice", ptxt); err != nil {
t.Fatal(err)
}
@@ -96,7 +92,7 @@
// does not have params that are authoritative on all blessings matching
// the pattern "google" (the googleYoutube params are authoritative on
// blessings matching "google/youtube").
- if _, err := encrypter.Encrypt(ctx, "google", &ptxt); verror.ErrorID(err) != ErrNoParams.ID {
+ if _, err := encrypter.Encrypt(ctx, "google", ptxt); verror.ErrorID(err) != ErrNoParams.ID {
t.Fatalf("Got error %v, wanted error with ID %v", err, ErrNoParams.ID)
}
// add google's params to the encrypter.
@@ -104,21 +100,21 @@
t.Fatal(err)
}
// encrypting for "google" should now succeed.
- if _, err := encrypter.Encrypt(ctx, "google", &ptxt); err != nil {
+ if _, err := encrypter.Encrypt(ctx, "google", ptxt); err != nil {
t.Fatal(err)
}
// Encryption should succeed for all of the following patterns
patterns := []security.BlessingPattern{"google", "google/$", "google/alice", "google/bob", "google/bob/phone"}
for _, p := range patterns {
- if _, err := encrypter.Encrypt(ctx, p, &ptxt); err != nil {
+ if _, err := encrypter.Encrypt(ctx, p, ptxt); err != nil {
t.Fatal(err)
}
}
// Every ciphertext should be unique.
- ctxt1, _ := encrypter.Encrypt(ctx, "google", &ptxt)
- ctxt2, _ := encrypter.Encrypt(ctx, "google", &ptxt)
+ ctxt1, _ := encrypter.Encrypt(ctx, "google", ptxt)
+ ctxt2, _ := encrypter.Encrypt(ctx, "google", ptxt)
if reflect.DeepEqual(ctxt1, ctxt2) {
t.Fatal("Two Encrypt operations yielded the same Ciphertext")
}
@@ -156,7 +152,7 @@
addParams(encrypter, google1.Params())
addParams(encrypter, google2.Params())
// encrypt for the pattern "google/alice"
- ctxt, err := encrypter.Encrypt(ctx, "google/alice", &ptxt)
+ ctxt, err := encrypter.Encrypt(ctx, "google/alice", ptxt)
if err != nil {
t.Fatal(err)
}
@@ -175,8 +171,8 @@
// Decryption should now succeed.
if got, err := decrypter.Decrypt(ctx, ctxt); err != nil {
t.Fatal(err)
- } else if !bytes.Equal((*got)[:], ptxt[:]) {
- t.Fatalf("Got plaintext %v, want %v", *got, ptxt)
+ } else if !bytes.Equal(got, ptxt) {
+ t.Fatalf("Got plaintext %v, want %v", got, ptxt)
}
// Decryption should have succeeded had the decrypter only contained
@@ -187,8 +183,8 @@
}
if got, err := decrypter.Decrypt(ctx, ctxt); err != nil {
t.Fatal(err)
- } else if !bytes.Equal((*got)[:], ptxt[:]) {
- t.Fatalf("Got plaintext %v, want %v", *got, ptxt)
+ } else if !bytes.Equal(got, ptxt) {
+ t.Fatalf("Got plaintext %v, want %v", got, ptxt)
}
// Decryption should fail for ciphertexts encrypted for the following
@@ -196,7 +192,7 @@
// "google/alice/tablet/app" from the root google2).
patterns := []security.BlessingPattern{"google/alice/$", "google/bob", "google/alice/tablet/$", "google/bob/tablet"}
for _, p := range patterns {
- ctxt, err := encrypter.Encrypt(ctx, p, &ptxt)
+ ctxt, err := encrypter.Encrypt(ctx, p, ptxt)
if err != nil {
t.Fatal(err)
}
@@ -210,14 +206,14 @@
// patterns should succeed.
patterns = []security.BlessingPattern{"google", "google/$", "google/alice", "google/bob", "google/bob/phone"}
for _, p := range patterns {
- if _, err := decrypter.Encrypt(ctx, p, &ptxt); err != nil {
+ if _, err := decrypter.Encrypt(ctx, p, ptxt); err != nil {
t.Fatal(err)
}
}
// But encrypting for the following patterns should fail.
patterns = []security.BlessingPattern{"youtube", "youtube/$", "youtube/alice"}
for _, p := range patterns {
- if _, err := decrypter.Encrypt(ctx, p, &ptxt); verror.ErrorID(err) != ErrNoParams.ID {
+ if _, err := decrypter.Encrypt(ctx, p, ptxt); verror.ErrorID(err) != ErrNoParams.ID {
t.Fatalf("Got error %v, wanted error with ID %v", err, ErrNoParams.ID)
}
}
@@ -233,7 +229,7 @@
if err := enc.AddParams(ctx, params); err != nil {
t.Fatal(err)
}
- ctxt, err := enc.Encrypt(ctx, pattern, &ptxt)
+ ctxt, err := enc.Encrypt(ctx, pattern, ptxt)
if err != nil {
t.Fatal(err)
}
@@ -246,8 +242,8 @@
}
if got, err := dec.Decrypt(ctx, ctxt); err != nil {
return err
- } else if !bytes.Equal((*got)[:], ptxt[:]) {
- return fmt.Errorf("got plaintext %v, want %v", *got, ptxt)
+ } else if !bytes.Equal(got, ptxt) {
+ return fmt.Errorf("got plaintext %v, want %v", got, ptxt)
}
return nil
}
diff --git a/services/syncbase/server/nosql/row.go b/services/syncbase/server/nosql/row.go
index 97cfc98..e95746e 100644
--- a/services/syncbase/server/nosql/row.go
+++ b/services/syncbase/server/nosql/row.go
@@ -126,6 +126,8 @@
if err != nil {
return err
}
+ // TODO(rogulenko): Avoid the redundant lookups since in theory we have all
+ // we need from the checkAccess.
permsKey := r.t.prefixPermsKey(permsPrefix)
if err := watchable.PutWithPerms(tx, []byte(r.stKey()), value, permsKey); err != nil {
return verror.New(verror.ErrInternal, ctx, err)
@@ -140,6 +142,8 @@
if err != nil {
return err
}
+ // TODO(rogulenko): Avoid the redundant lookups since in theory we have all
+ // we need from the checkAccess.
permsKey := r.t.prefixPermsKey(permsPrefix)
if err := watchable.DeleteWithPerms(tx, []byte(r.stKey()), permsKey); err != nil {
return verror.New(verror.ErrInternal, ctx, err)
diff --git a/services/syncbase/server/nosql/table.go b/services/syncbase/server/nosql/table.go
index 5850e62..34a9407 100644
--- a/services/syncbase/server/nosql/table.go
+++ b/services/syncbase/server/nosql/table.go
@@ -415,7 +415,7 @@
if err := t.UpdatePrefixPermsIndexForSet(ctx, tx, key); err != nil {
return err
}
- return watchable.PutVOMWithPerms(ctx, tx, t.prefixPermsKey(key), perms, t.prefixPermsKey(parent))
+ return watchable.PutVomWithPerms(ctx, tx, t.prefixPermsKey(key), perms, t.prefixPermsKey(parent))
}
func (t *tableReq) deletePrefixPerms(ctx *context.T, tx store.Transaction, key string) error {
diff --git a/services/syncbase/server/watchable/transaction.go b/services/syncbase/server/watchable/transaction.go
index 49092dd..fdabb29 100644
--- a/services/syncbase/server/watchable/transaction.go
+++ b/services/syncbase/server/watchable/transaction.go
@@ -349,10 +349,10 @@
return nil
}
-// PutWithPerms puts a VOM-encoded value for the managed key, recording the key
-// and version of the prefix permissions object that granted access to this put
-// operation.
-func PutVOMWithPerms(ctx *context.T, tx store.Transaction, k string, v interface{}, permsKey string) error {
+// PutVomWithPerms puts a VOM-encoded value for the managed key, recording
+// the key and the version of the prefix permissions object that granted access
+// to this put operation.
+func PutVomWithPerms(ctx *context.T, tx store.Transaction, k string, v interface{}, permsKey string) error {
bytes, err := vom.Encode(v)
if err != nil {
return verror.New(verror.ErrInternal, ctx, err)
diff --git a/services/syncbase/testutil/util.go b/services/syncbase/testutil/util.go
index 7af6f70..a3a8c72 100644
--- a/services/syncbase/testutil/util.go
+++ b/services/syncbase/testutil/util.go
@@ -249,7 +249,8 @@
name := s.Status().Endpoints[0].Name()
return name, func() {
cancel()
- <-s.Closed()
+ s.Stop()
+ service.Close()
os.RemoveAll(rootDir)
}
}