Module: SecureRandom

Defined in:
lib/opal_patches.rb

Defined Under Namespace

Classes: EntropyError

Class Method Summary collapse

Class Method Details

.base64(n = 16) ⇒ Object



496
497
498
499
# File 'lib/opal_patches.rb', line 496

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

.hex(n = 16) ⇒ Object



480
481
482
483
484
485
486
487
488
489
# File 'lib/opal_patches.rb', line 480

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



469
470
471
472
473
474
475
476
477
478
# File 'lib/opal_patches.rb', line 469

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).



518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
# File 'lib/opal_patches.rb', line 518

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



501
502
503
504
# File 'lib/opal_patches.rb', line 501

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

.uuidObject



491
492
493
494
# File 'lib/opal_patches.rb', line 491

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