Class: NebulaToken::MemoryRefreshTokenStore

Inherits:
Object
  • Object
show all
Includes:
RefreshTokenStore
Defined in:
lib/nebula_token.rb

Overview

Reference store ([N-21]).

Guarded by a mutex, so the compare-and-set methods are atomic under the threaded request concurrency of Puma, Falcon or Sidekiq.

NOT FOR PRODUCTION: state is per-process and lost on restart, so reuse detection does not survive a deploy and does not work behind more than one instance. Implement the six methods over your database instead — start from examples/pg_store.rb, schema in docs/STORE.md.

Instance Method Summary collapse

Constructor Details

#initializeMemoryRefreshTokenStore

Returns a new instance of MemoryRefreshTokenStore.



409
410
411
412
# File 'lib/nebula_token.rb', line 409

def initialize
  @rows = {}
  @mutex = Mutex.new
end

Instance Method Details

#allObject

Test helper: every record currently stored. Not part of the store contract.



463
464
465
# File 'lib/nebula_token.rb', line 463

def all
  @mutex.synchronize { @rows.values.map(&:dup_record) }
end

#delete_expired(now) ⇒ Object

Operational helper: drop records whose family deadline has passed. Nothing may be deleted before it ([N-15]) — rotated rows ARE the reuse detector.



469
470
471
472
473
474
475
# File 'lib/nebula_token.rb', line 469

def delete_expired(now)
  @mutex.synchronize do
    expired = @rows.select { |_, row| now >= row.family_expires_at }
    expired.each_key { |selector| @rows.delete(selector) }
    expired.size
  end
end

#find_by_selector(selector) ⇒ Object



414
415
416
# File 'lib/nebula_token.rb', line 414

def find_by_selector(selector)
  @mutex.synchronize { @rows[selector]&.dup_record }
end

#insert(record) ⇒ Object



418
419
420
421
422
423
424
425
426
427
428
429
# File 'lib/nebula_token.rb', line 418

def insert(record)
  @mutex.synchronize do
    if @rows.key?(record.selector)
      # An infrastructure failure, not a protocol outcome ([N-20]): mirrors
      # the primary-key violation a real store would raise.
      raise "[NEBULA] duplicate selector #{record.selector}"
    end

    @rows[record.selector] = record.dup_record
  end
  nil
end

#mark_rotated(selector, from_status, rotated_at, replaced_by_selector) ⇒ Object



431
432
433
434
435
436
437
438
439
440
441
442
# File 'lib/nebula_token.rb', line 431

def mark_rotated(selector, from_status, rotated_at, replaced_by_selector)
  want = NebulaToken.normalize_status(from_status)
  @mutex.synchronize do
    row = @rows[selector]
    next false if row.nil? || row.status != want

    row.status = STATUS_ROTATED
    row.rotated_at = rotated_at
    row.replaced_by_selector = replaced_by_selector
    true
  end
end

#revoke_family(family_id) ⇒ Object



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

def revoke_family(family_id)
  revoke_where { |row| row.family_id == family_id }
end

#revoke_if_active(selector) ⇒ Object



444
445
446
447
448
449
450
451
452
# File 'lib/nebula_token.rb', line 444

def revoke_if_active(selector)
  @mutex.synchronize do
    row = @rows[selector]
    next false unless row&.active?

    row.status = STATUS_REVOKED
    true
  end
end

#revoke_user(user_id) ⇒ Object



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

def revoke_user(user_id)
  revoke_where { |row| row.user_id == user_id }
end