Class: BSV::Auth::Peer
- Inherits:
-
Object
- Object
- BSV::Auth::Peer
- Defined in:
- lib/bsv/auth/peer.rb
Overview
BRC-31/BRC-103 mutual authentication peer.
Manages the cryptographic handshake between two parties using a transport for bidirectional message delivery.
High-level API (preferred):
peer_a.to_peer(payload, peer_b_identity_key) — send authenticated message
peer_a.get_authenticated_session(identity_key) — obtain/create authenticated session
peer_a.request_certificates(certs, identity_key) — request certs post-handshake
peer_a.send_certificate_response(key, certs) — send certs to a peer
The high-level API auto-initiates the handshake when no authenticated session exists. The low-level handle_incoming_message is called internally by the transport callback and is not part of the public contract.
Sessions are indexed by session_nonce (our nonce), which is the primary key in the SessionManager.
Constant Summary collapse
- AUTH_PROTOCOL =
[2, 'auth message signature'].freeze
Instance Attribute Summary collapse
-
#last_interacted_peer ⇒ Object
readonly
Returns the value of attribute last_interacted_peer.
-
#session_manager ⇒ Object
readonly
Returns the value of attribute session_manager.
-
#wallet ⇒ Object
readonly
Returns the value of attribute wallet.
Instance Method Summary collapse
-
#authenticated?(identifier) ⇒ Boolean
Checks whether we have an authenticated session with a peer.
-
#get_authenticated_session(identity_key = nil) ⇒ PeerSession
Returns an authenticated session for a peer, initiating a handshake if needed.
-
#identity_key ⇒ String
Returns our identity key (cached after first call).
-
#initialize(wallet:, transport:, session_manager: nil, certificates_to_request: nil, auto_persist_last_session: true, handshake_timeout: 30) ⇒ Peer
constructor
A new instance of Peer.
-
#off_certificate_request(callback_id) ⇒ Object
Removes a certificate request callback.
-
#off_certificates_received(callback_id) ⇒ Object
Removes a certificates received callback.
-
#off_general_message(callback_id) ⇒ Object
Removes a general message callback.
-
#on_certificate_request {|sender_key, requested_certs| ... } ⇒ Integer
Registers a callback to be called when a certificate request is received from a peer.
-
#on_certificates_received {|sender_key, certs| ... } ⇒ Integer
Registers a callback to be called when certificates are received from a peer.
-
#on_general_message {|sender_key, payload| ... } ⇒ Integer
Registers a callback to be called when a general message is received.
-
#request_certificates(certificates_to_request, identity_key = nil) ⇒ Object
Sends a certificate request to a peer post-handshake.
-
#send_certificate_response(peer_identity_key, certificates) ⇒ Object
Sends a certificate response to a peer.
-
#to_peer(payload, identity_key = nil) ⇒ Object
Sends an authenticated general message to a peer, initiating a handshake automatically if no authenticated session exists.
Constructor Details
#initialize(wallet:, transport:, session_manager: nil, certificates_to_request: nil, auto_persist_last_session: true, handshake_timeout: 30) ⇒ Peer
Returns a new instance of Peer.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/bsv/auth/peer.rb', line 46 def initialize(wallet:, transport:, session_manager: nil, certificates_to_request: nil, auto_persist_last_session: true, handshake_timeout: 30) raise ArgumentError, 'transport is required' if transport.nil? @wallet = wallet @transport = transport @session_manager = session_manager || SessionManager.new @certificates_to_request = certificates_to_request || { certifiers: [], types: {} } @identity_public_key = nil @callbacks = { general_message: {}, certificates_received: {}, certificate_request: {} } @callback_id_counter = 0 @callback_mutex = Mutex.new @last_interacted_peer = nil @auto_persist_last_session = auto_persist_last_session @handshake_queues = {} @handshake_queues_mutex = Mutex.new @handshake_timeout = handshake_timeout @transport.on_data { |msg| (msg) } end |
Instance Attribute Details
#last_interacted_peer ⇒ Object (readonly)
Returns the value of attribute last_interacted_peer.
37 38 39 |
# File 'lib/bsv/auth/peer.rb', line 37 def last_interacted_peer @last_interacted_peer end |
#session_manager ⇒ Object (readonly)
Returns the value of attribute session_manager.
37 38 39 |
# File 'lib/bsv/auth/peer.rb', line 37 def session_manager @session_manager end |
#wallet ⇒ Object (readonly)
Returns the value of attribute wallet.
37 38 39 |
# File 'lib/bsv/auth/peer.rb', line 37 def wallet @wallet end |
Instance Method Details
#authenticated?(identifier) ⇒ Boolean
Checks whether we have an authenticated session with a peer.
Accepts either a session_nonce or peer_identity_key.
192 193 194 195 |
# File 'lib/bsv/auth/peer.rb', line 192 def authenticated?(identifier) session = @session_manager.get_session(identifier) session&.authenticated? || false end |
#get_authenticated_session(identity_key = nil) ⇒ PeerSession
Returns an authenticated session for a peer, initiating a handshake if needed.
If identity_key is given and an authenticated session already exists, returns it immediately. Otherwise initiates a handshake and blocks until the response arrives or the timeout expires.
98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/bsv/auth/peer.rb', line 98 def get_authenticated_session(identity_key = nil) if identity_key session = @session_manager.get_session(identity_key) return session if session&.authenticated? end session_nonce = initiate_handshake(identity_key) session = @session_manager.get_session(session_nonce) raise AuthError, 'Unable to establish mutual authentication with peer!' unless session&.authenticated? session end |
#identity_key ⇒ String
Returns our identity key (cached after first call).
182 183 184 |
# File 'lib/bsv/auth/peer.rb', line 182 def identity_key @identity_key ||= @wallet.get_public_key({ identity_key: true })[:public_key] end |
#off_certificate_request(callback_id) ⇒ Object
Removes a certificate request callback.
175 176 177 |
# File 'lib/bsv/auth/peer.rb', line 175 def off_certificate_request(callback_id) unregister_callback(:certificate_request, callback_id) end |
#off_certificates_received(callback_id) ⇒ Object
Removes a certificates received callback.
160 161 162 |
# File 'lib/bsv/auth/peer.rb', line 160 def off_certificates_received(callback_id) unregister_callback(:certificates_received, callback_id) end |
#off_general_message(callback_id) ⇒ Object
Removes a general message callback.
145 146 147 |
# File 'lib/bsv/auth/peer.rb', line 145 def (callback_id) unregister_callback(:general_message, callback_id) end |
#on_certificate_request {|sender_key, requested_certs| ... } ⇒ Integer
Registers a callback to be called when a certificate request is received from a peer.
168 169 170 |
# File 'lib/bsv/auth/peer.rb', line 168 def on_certificate_request(&block) register_callback(:certificate_request, block) end |
#on_certificates_received {|sender_key, certs| ... } ⇒ Integer
Registers a callback to be called when certificates are received from a peer.
153 154 155 |
# File 'lib/bsv/auth/peer.rb', line 153 def on_certificates_received(&block) register_callback(:certificates_received, block) end |
#on_general_message {|sender_key, payload| ... } ⇒ Integer
Registers a callback to be called when a general message is received.
138 139 140 |
# File 'lib/bsv/auth/peer.rb', line 138 def (&block) register_callback(:general_message, block) end |
#request_certificates(certificates_to_request, identity_key = nil) ⇒ Object
Sends a certificate request to a peer post-handshake.
115 116 117 118 119 120 |
# File 'lib/bsv/auth/peer.rb', line 115 def request_certificates(certificates_to_request, identity_key = nil) identity_key = resolve_identity_key(identity_key) session = get_authenticated_session(identity_key) = create_certificate_request(session.peer_identity_key, certificates_to_request) @transport.send() end |
#send_certificate_response(peer_identity_key, certificates) ⇒ Object
Sends a certificate response to a peer.
126 127 128 129 130 |
# File 'lib/bsv/auth/peer.rb', line 126 def send_certificate_response(peer_identity_key, certificates) session = get_authenticated_session(peer_identity_key) = create_certificate_response(session.peer_identity_key, certificates) @transport.send() end |
#to_peer(payload, identity_key = nil) ⇒ Object
Sends an authenticated general message to a peer, initiating a handshake automatically if no authenticated session exists.
76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/bsv/auth/peer.rb', line 76 def to_peer(payload, identity_key = nil) identity_key = resolve_identity_key(identity_key) session = get_authenticated_session(identity_key) if session.certificates_required && !session.certificates_validated raise AuthError, 'Cannot send general message before certificate validation is complete' end = (session.peer_identity_key, payload) @transport.send() @last_interacted_peer = session.peer_identity_key if @auto_persist_last_session end |