Module: SecureRandom

Defined in:
lib/opal_patches.rb

Defined Under Namespace

Classes: EntropyError

Class Method Summary collapse

Class Method Details

.base64(n = 16) ⇒ Object



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

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

.hex(n = 16) ⇒ Object

Raises:



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

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:



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

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



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

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



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
496
# File 'lib/opal_patches.rb', line 469

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



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

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

.uuidObject



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

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