Module: SecureRandom

Defined in:
lib/opal_patches.rb

Defined Under Namespace

Classes: EntropyError

Class Method Summary collapse

Class Method Details

.base64(n = 16) ⇒ Object



448
449
450
451
# File 'lib/opal_patches.rb', line 448

def self.base64(n = 16)
  require 'base64'
  Base64.strict_encode64(random_bytes(n))
end

.hex(n = 16) ⇒ Object

Raises:



435
436
437
438
439
440
441
# File 'lib/opal_patches.rb', line 435

def self.hex(n = 16)
  n = n.to_i
  n = 16 if n <= 0
  out = secure_hex_bytes(n)
  raise EntropyError, 'no source of cryptographic entropy available (node:crypto AND Web Crypto both unreachable)' if out.nil?
  out
end

.random_bytes(n = 16) ⇒ Object

Raises:



427
428
429
430
431
432
433
# File 'lib/opal_patches.rb', line 427

def self.random_bytes(n = 16)
  n = n.to_i
  n = 16 if n <= 0
  hex_string = secure_hex_bytes(n)
  raise EntropyError, 'no source of cryptographic entropy available (node:crypto AND Web Crypto both unreachable)' if hex_string.nil?
  [hex_string].pack('H*')
end

.random_number(n = 0) ⇒ Object



458
459
460
461
# File 'lib/opal_patches.rb', line 458

def self.random_number(n = 0)
  # Not used at class-init time; real implementations welcome.
  0
end

.secure_hex_bytes(n) ⇒ Object

Returns a hex string of ‘n` random bytes, or nil when no entropy source is available. Tries node:crypto.randomBytes first (works on both Cloudflare Workers with `nodejs_compat` and Node.js), falls back to Web Crypto getRandomValues (works at request time on Workers and everywhere on browsers).



468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
# File 'lib/opal_patches.rb', line 468

def self.secure_hex_bytes(n)
  # Opal does not always auto-return backtick IIFEs; assign first
  # so the method's last expression is a normal Ruby reference.
  result = `(function(n) {
    try {
      if (typeof globalThis.__nodeCrypto__ !== 'undefined' && globalThis.__nodeCrypto__) {
        return globalThis.__nodeCrypto__.randomBytes(n).toString('hex');
      }
    } catch (e) { /* fall through to Web Crypto */ }
    try {
      if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
        var bytes = new Uint8Array(n);
        crypto.getRandomValues(bytes);
        var out = '';
        for (var i = 0; i < bytes.length; i++) {
          var h = bytes[i].toString(16);
          if (h.length < 2) h = '0' + h;
          out += h;
        }
        return out;
      }
    } catch (e) {
      // Workers blocks getRandomValues at module-load scope; fall through.
    }
    return nil;   // Opal nil singleton, not JS null — so .nil? works
  })(#{n})`
  result
end

.urlsafe_base64(n = 16, padding = false) ⇒ Object



453
454
455
456
# File 'lib/opal_patches.rb', line 453

def self.urlsafe_base64(n = 16, padding = false)
  s = base64(n).tr('+/', '-_')
  padding ? s : s.delete('=')
end

.uuidObject



443
444
445
446
# File 'lib/opal_patches.rb', line 443

def self.uuid
  h = hex(16)
  "#{h[0, 8]}-#{h[8, 4]}-4#{h[13, 3]}-#{h[16, 4]}-#{h[20, 12]}"
end