# Ruby 3+. BOTH sides, transport-independent scaffold, not a verifier. # Ports implement the contract in examples/README.md; no permissive default. module BringPassDraft OPS = %w[REGISTER USE REVOKE RETRACT].freeze Envelope = Struct.new(:fields, :signature, keyword_init: true) Result = Struct.new(:receipt, :fresh, keyword_init: true) class Ports def challenge(op, rid, target, context) = raise(NotImplementedError) def verify_provider_and_approve(challenge) = raise(NotImplementedError) def sign_proof(challenge) = raise(NotImplementedError) def verify_result_and_apply(result) = raise(NotImplementedError) def begin_verified(proof, trusted_context) = raise(NotImplementedError) def recover_revoke(rid, target, trusted_context) = raise(NotImplementedError) end class Transaction # Created only after cryptographic verification inside a locked transaction. def operation = raise(NotImplementedError) def cached = raise(NotImplementedError) def register_new_key = raise(NotImplementedError) def require_current_entitlement = raise(NotImplementedError) def revoke_target = raise(NotImplementedError) def retract_relationship = raise(NotImplementedError) def sign_result = raise(NotImplementedError) def commit_once(result) = raise(NotImplementedError) def close = raise(NotImplementedError) # Roll back unless committed. end class TokenSide def initialize(ports) = @ports = ports def respond(challenge) @ports.verify_provider_and_approve(challenge) @ports.sign_proof(challenge) end def accept(result) = @ports.verify_result_and_apply(result) end class ProviderSide def initialize(ports) = @ports = ports def start(op, rid, target, context) = @ports.challenge(op, rid, target, context) def finish(proof, trusted_context) tx = @ports.begin_verified(proof, trusted_context) begin old = tx.cached return Result.new(receipt: old, fresh: false) if old case tx.operation when 'REGISTER' then tx.register_new_key when 'USE' then tx.require_current_entitlement when 'REVOKE' then tx.revoke_target when 'RETRACT' then tx.retract_relationship else raise ArgumentError, 'Unsupported operation' end result = tx.sign_result tx.commit_once(result) Result.new(receipt: result, fresh: true) ensure tx.close end end def lost(rid, target, context) = @ports.recover_revoke(rid, target, context) end def self.legacy_value(value, approved:, selected:) raise ArgumentError, 'Local approval/selection required' unless approved && selected && !value.empty? value # The only payload sent to the approved renderer/driver. end end