github.com/goplusjs/gopherjs@v1.2.6-0.20211206034512-f187917453b8/compiler/natives/src/crypto/rand/rand.go (about) 1 // +build js 2 3 package rand 4 5 import ( 6 "errors" 7 8 "github.com/gopherjs/gopherjs/js" 9 ) 10 11 func init() { 12 Reader = &rngReader{} 13 } 14 15 type rngReader struct{} 16 17 func (r *rngReader) Read(b []byte) (n int, err error) { 18 array := js.InternalObject(b).Get("$array") 19 offset := js.InternalObject(b).Get("$offset").Int() 20 21 // browser 22 crypto := js.Global.Get("crypto") 23 if crypto == js.Undefined { 24 crypto = js.Global.Get("msCrypto") 25 } 26 if crypto != js.Undefined { 27 if crypto.Get("getRandomValues") != js.Undefined { 28 n = len(b) 29 if n > 65536 { 30 // Avoid QuotaExceededError thrown by getRandomValues 31 // when length is more than 65536, as specified in 32 // http://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues 33 n = 65536 34 } 35 crypto.Call("getRandomValues", array.Call("subarray", offset, offset+n)) 36 return n, nil 37 } 38 } 39 40 // Node.js 41 if require := js.Global.Get("require"); require != js.Undefined { 42 if randomBytes := require.Invoke("crypto").Get("randomBytes"); randomBytes != js.Undefined { 43 array.Call("set", randomBytes.Invoke(len(b)), offset) 44 return len(b), nil 45 } 46 } 47 48 return 0, errors.New("crypto/rand not available in this environment") 49 } 50 51 func batched(f func([]byte) bool, readMax int) func([]byte) bool { 52 return func(buf []byte) bool { 53 for len(buf) > readMax { 54 if !f(buf[:readMax]) { 55 return false 56 } 57 buf = buf[readMax:] 58 } 59 return len(buf) == 0 || f(buf) 60 } 61 }