Module: SecureRandom

Defined in:
lib/opal_patches.rb

Defined Under Namespace

Classes: EntropyError

Class Method Summary collapse

Class Method Details

.base64(n = 16) ⇒ Object



504
505
506
507
508
# File 'lib/opal_patches.rb', line 504

def self.base64(n = 16)
  require "base64"

  Base64.strict_encode64(random_bytes(n))
end

.hex(n = 16) ⇒ Object



485
486
487
488
489
490
491
492
493
494
495
496
497
# File 'lib/opal_patches.rb', line 485

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

  out
end

.random_bytes(n = 16) ⇒ Object



471
472
473
474
475
476
477
478
479
480
481
482
483
# File 'lib/opal_patches.rb', line 471

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

  [hex_string].pack("H*")
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).



527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
# File 'lib/opal_patches.rb', line 527

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



510
511
512
513
# File 'lib/opal_patches.rb', line 510

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

.uuidObject



499
500
501
502
# File 'lib/opal_patches.rb', line 499

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