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  }