firestore: use crypto/rand to generate new doc IDs
Change-Id: Ifc564eb5a5953bf5740ecd9e8ec0b3a431d99cc5
Reviewed-on: https://code-review.googlesource.com/c/gocloud/+/44570
Reviewed-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
diff --git a/firestore/collref.go b/firestore/collref.go
index 77deac8..6dff217 100644
--- a/firestore/collref.go
+++ b/firestore/collref.go
@@ -16,10 +16,9 @@
import (
"context"
- "math/rand"
- "os"
- "sync"
- "time"
+ "crypto/rand"
+ "encoding/base64"
+ "fmt"
)
// A CollectionRef is a reference to Firestore collection.
@@ -97,6 +96,9 @@
}
// NewDoc returns a DocumentRef with a uniquely generated ID.
+//
+// NewDoc will panic if crypto/rand cannot generate enough bytes to make a new
+// doc ID.
func (c *CollectionRef) NewDoc() *DocumentRef {
return c.Doc(uniqueID())
}
@@ -123,19 +125,10 @@
return newDocumentRefIterator(ctx, c, nil)
}
-const alphanum = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
-
-var (
- rngMu sync.Mutex
- rng = rand.New(rand.NewSource(time.Now().UnixNano() ^ int64(os.Getpid())))
-)
-
func uniqueID() string {
- var b [20]byte
- rngMu.Lock()
- for i := 0; i < len(b); i++ {
- b[i] = alphanum[rng.Intn(len(alphanum))]
+ b := make([]byte, 32)
+ if _, err := rand.Read(b); err != nil {
+ panic(fmt.Sprintf("firestore: crypto/rand.Read error: %v", err))
}
- rngMu.Unlock()
- return string(b[:])
+ return base64.RawURLEncoding.EncodeToString(b)
}
diff --git a/firestore/collref_test.go b/firestore/collref_test.go
index be45bf8..4624cbb 100644
--- a/firestore/collref_test.go
+++ b/firestore/collref_test.go
@@ -16,6 +16,7 @@
import (
"context"
+ "encoding/base64"
"testing"
"github.com/golang/protobuf/proto"
@@ -41,10 +42,14 @@
coll := c.Collection("C")
got := coll.NewDoc()
if got.Parent != coll {
- t.Errorf("got %v, want %v", got.Parent, coll)
+ t.Errorf("NewDoc got %v, want %v", got.Parent, coll)
}
- if len(got.ID) != 20 {
- t.Errorf("got %d-char ID, wanted 20", len(got.ID))
+ b, err := base64.RawURLEncoding.DecodeString(got.ID)
+ if err != nil {
+ t.Fatalf("NewDoc DecodeToString(%q) got err: %v", got.ID, err)
+ }
+ if len(b) != 32 {
+ t.Errorf("NewDoc got %d-byte ID, wanted 32", len(b))
}
got2 := coll.NewDoc()