@@ -654,13 +654,10 @@ class NodeConnectionManager {
654654 const cancelAuthenticationPs : Array < PromiseCancellable < void > > = [ ] ;
655655 const cancelReason = new nodesErrors . ErrorNodeConnectionManagerStopping ( ) ;
656656 for ( const [ nodeIdString ] of this . connections ) {
657- const destroyP = this . authenticateCancel ( nodeIdString , cancelReason ) . then (
658- async ( ) => {
659- return await this . destroyConnection (
660- IdInternal . fromString < NodeId > ( nodeIdString ) ,
661- force ,
662- ) ;
663- } ,
657+ this . authenticateCancel ( nodeIdString , cancelReason ) ;
658+ const destroyP = this . destroyConnection (
659+ IdInternal . fromString < NodeId > ( nodeIdString ) ,
660+ force ,
664661 ) ;
665662 destroyConnectionPs . push ( destroyP ) ;
666663 }
@@ -738,12 +735,13 @@ class NodeConnectionManager {
738735 connectionAndTimer . connection . connectionId ,
739736 ) ;
740737 connectionAndTimer . timer = new Timer ( {
741- handler : async ( ) =>
738+ handler : async ( ) => {
742739 await this . destroyConnection (
743740 targetNodeId ,
744741 false ,
745742 connectionAndTimer . connection . connectionId ,
746- ) ,
743+ ) ;
744+ } ,
747745 delay,
748746 } ) ;
749747 // Prevent unhandled exceptions when cancelling
@@ -878,6 +876,7 @@ class NodeConnectionManager {
878876 ctx ,
879877 ) ;
880878 this . addConnection ( nodeConnection . validatedNodeId , nodeConnection ) ;
879+ this . initiateForwardAuthenticate ( nodeConnection . nodeId ) ;
881880 // Dispatch the connection event
882881 const connectionData : ConnectionData = {
883882 remoteNodeId : nodeConnection . nodeId ,
@@ -1050,6 +1049,7 @@ class NodeConnectionManager {
10501049
10511050 // Creating TTL timeout.
10521051 // Add to map
1052+ // TODO: update type to something like ConnectionDetails
10531053 const newConnAndTimer : ConnectionAndTimer = {
10541054 connection : nodeConnection ,
10551055 timer : null ,
@@ -1091,7 +1091,6 @@ class NodeConnectionManager {
10911091 authenticatedRejectP,
10921092 } ;
10931093 this . connections . set ( nodeIdString , entry ) ;
1094- this . initiateForwardAuthenticate ( nodeId ) ;
10951094 } else {
10961095 // Adding connection to existing entry
10971096 newConnAndTimer . timer = new Timer ( {
@@ -1177,7 +1176,7 @@ class NodeConnectionManager {
11771176 const remainingKeys = Object . keys ( connectionsEntry . connections ) ;
11781177 if ( remainingKeys . length === 0 ) {
11791178 // Clean up authentication
1180- await this . authenticateCancel (
1179+ this . authenticateCancel (
11811180 targetNodeIdString ,
11821181 new nodesErrors . ErrorNodeManagerAuthenticationFailed (
11831182 'Connection destroyed before authentication could complete' ,
@@ -1663,10 +1662,52 @@ class NodeConnectionManager {
16631662 const authenticateMessage =
16641663 await this . authenticateNetworkForwardCallback ( ctx ) ;
16651664 await withF ( [ this . acquireConnectionInternal ( nodeId ) ] , async ( [ conn ] ) => {
1666- await conn . rpcClient . methods . nodesAuthenticateConnection (
1667- authenticateMessage ,
1668- ctx ,
1669- ) ;
1665+ const authStream =
1666+ await conn . rpcClient . methods . nodesAuthenticateConnection ( ctx ) ;
1667+ const writer = authStream . writable . getWriter ( ) ;
1668+ const reader = authStream . readable . getReader ( ) ;
1669+ await writer . write ( authenticateMessage ) ;
1670+ const reverseMessageIn = ( await reader . read ( ) ) . value ;
1671+ // If the reverse auth was unsuccessful, error out gracefully.
1672+ if (
1673+ reverseMessageIn == null ||
1674+ reverseMessageIn . type !== 'success' ||
1675+ ! reverseMessageIn . success
1676+ ) {
1677+ throw new nodesErrors . ErrorNodeManagerAuthenticationFailedForward (
1678+ 'Unsuccessful forward response' ,
1679+ ) ;
1680+ }
1681+ const forwardMessageIn = ( await reader . read ( ) ) . value ;
1682+ // If the forward message retrieval was unsuccessful, error out.
1683+ if ( forwardMessageIn == null || forwardMessageIn . type === 'success' ) {
1684+ throw new nodesErrors . ErrorNodeManagerAuthenticationFailedForward (
1685+ 'Invalid forward message' ,
1686+ ) ;
1687+ }
1688+ try {
1689+ await this . handleReverseAuthenticate (
1690+ conn . nodeId ,
1691+ forwardMessageIn ,
1692+ ctx ,
1693+ ) ;
1694+ } catch ( e ) {
1695+ await writer . close ( ) ;
1696+ await reader . cancel ( ) ;
1697+ throw e ;
1698+ }
1699+ // If reverse authentication finished without errors, then we continue
1700+ await writer . write ( { type : 'success' , success : true } ) ;
1701+ const ack = ( await reader . read ( ) ) . value ;
1702+
1703+ if ( ack == null || ack . type !== 'success' || ! ack . success ) {
1704+ throw new nodesErrors . ErrorNodeManagerAuthenticationFailedForward (
1705+ 'Invalid ack response' ,
1706+ ) ;
1707+ }
1708+
1709+ await writer . close ( ) ;
1710+ await reader . cancel ( ) ;
16701711 } ) ;
16711712 connectionsEntry . authenticatedForward = AuthenticatingState . SUCCESS ;
16721713 } catch ( e ) {
@@ -1743,7 +1784,7 @@ class NodeConnectionManager {
17431784 /**
17441785 * Will initiate a forward authentication call and coalesce
17451786 */
1746- public initiateForwardAuthenticate ( nodeId : NodeId ) {
1787+ public initiateForwardAuthenticate ( nodeId : NodeId ) : void {
17471788 // Needs check the map if one is already running, otherwise it needs to start one and manage it.
17481789 const nodeIdString = nodeId . toString ( ) as NodeIdString ;
17491790 const authenticationEntry = this . connections . get ( nodeIdString ) ;
@@ -1752,8 +1793,12 @@ class NodeConnectionManager {
17521793 }
17531794 const existingAuthenticate =
17541795 this . activeForwardAuthenticateCalls . get ( nodeIdString ) ;
1796+
17551797 // If it exists in the map then we don't need to start one and can just return
17561798 if ( existingAuthenticate != null ) return ;
1799+ // TODO: retry if fail
1800+ // create retry authenticatoin on new connections if the existing connection
1801+ // had a failed authentication. put a limit - soemwhere around 3.
17571802 if (
17581803 authenticationEntry . authenticatedForward !==
17591804 AuthenticatingState . PENDING ||
@@ -1762,10 +1807,8 @@ class NodeConnectionManager {
17621807 return ;
17631808 }
17641809 // Otherwise we need to start one and add it to the map
1765- const forwardAuthenticateP = this . forwardAuthenticate ( nodeId ) . finally (
1766- ( ) => {
1767- this . activeForwardAuthenticateCalls . delete ( nodeIdString ) ;
1768- } ,
1810+ const forwardAuthenticateP = this . forwardAuthenticate ( nodeId ) . finally ( ( ) =>
1811+ this . activeForwardAuthenticateCalls . delete ( nodeIdString ) ,
17691812 ) ;
17701813 // Prevent unhandled errors
17711814 forwardAuthenticateP . then (
@@ -1775,6 +1818,40 @@ class NodeConnectionManager {
17751818 this . activeForwardAuthenticateCalls . set ( nodeIdString , forwardAuthenticateP ) ;
17761819 }
17771820
1821+ public handleAuthentication (
1822+ requestingNodeId : NodeId ,
1823+ forwardMessage : NodesAuthenticateConnectionMessage ,
1824+ ctx : ContextTimed ,
1825+ ) : PromiseCancellable < NodesAuthenticateConnectionMessage > ;
1826+ @decorators . timedCancellable ( true )
1827+ public async handleAuthentication (
1828+ requestingNodeId : NodeId ,
1829+ forwardMessage : NodesAuthenticateConnectionMessage ,
1830+ @decorators . context ctx : ContextTimed ,
1831+ ) : Promise < NodesAuthenticateConnectionMessage > {
1832+ const requestingNodeIdString = requestingNodeId . toString ( ) as NodeIdString ;
1833+ const connectionEntry = this . connections . get ( requestingNodeIdString ) ;
1834+ if ( connectionEntry == null ) utils . never ( 'Connection should be defined' ) ;
1835+
1836+ await this . handleReverseAuthenticate ( requestingNodeId , forwardMessage , ctx ) ;
1837+ connectionEntry . authenticatedReverse = AuthenticatingState . SUCCESS ;
1838+
1839+ return await this . authenticateNetworkForwardCallback ( ctx ) ;
1840+ }
1841+
1842+ public finalizeAuthentication ( requestingNodeId : NodeId , success : boolean ) {
1843+ const requestingNodeIdString = requestingNodeId . toString ( ) as NodeIdString ;
1844+ const connectionEntry = this . connections . get ( requestingNodeIdString ) ;
1845+ if ( connectionEntry == null ) utils . never ( 'Connection should be defined' ) ;
1846+ if ( success ) {
1847+ connectionEntry . authenticatedReverse = AuthenticatingState . SUCCESS ;
1848+ this . authenticateSuccess ( requestingNodeIdString ) ;
1849+ } else {
1850+ connectionEntry . authenticatedReverse = AuthenticatingState . FAIL ;
1851+ this . authenticateFail ( requestingNodeIdString , new Error ( 'temp' ) ) ;
1852+ }
1853+ }
1854+
17781855 /**
17791856 * Returns true if the connection has been authenticated
17801857 */
@@ -1808,7 +1885,6 @@ class NodeConnectionManager {
18081885 nodeId : NodeId ,
18091886 @decorators . context ctx : ContextTimed ,
18101887 ) : Promise < void > {
1811- ctx . signal . throwIfAborted ( ) ;
18121888 const targetNodeIdString = nodeId . toString ( ) as NodeIdString ;
18131889 const connectionsEntry = this . connections . get ( targetNodeIdString ) ;
18141890 if ( connectionsEntry == null ) {
@@ -1818,11 +1894,20 @@ class NodeConnectionManager {
18181894 const abortHandler = ( ) => {
18191895 rejectAbortP ( ctx . signal . reason ) ;
18201896 } ;
1821- ctx . signal . addEventListener ( 'abort' , abortHandler , { once : true } ) ;
1897+ if ( ctx . signal . aborted ) {
1898+ abortHandler ( ) ;
1899+ } else {
1900+ ctx . signal . addEventListener ( 'abort' , abortHandler , { once : true } ) ;
1901+ }
1902+ // If the connection isn't already authenticated, then try authenticating
1903+ if ( ! connectionsEntry . authenticateComplete ) {
1904+ this . initiateForwardAuthenticate ( nodeId ) ;
1905+ }
18221906 try {
18231907 return await Promise . race ( [ connectionsEntry . authenticatedP , abortP ] ) ;
18241908 } catch ( e ) {
1825- // Capture the stacktrace here since knowing where we're waiting for authentication is more useful
1909+ // Capture the stacktrace here since knowing where we're waiting for
1910+ // authentication is more useful.
18261911 Error . captureStackTrace ( e ) ;
18271912 throw e ;
18281913 } finally {
@@ -1881,7 +1966,7 @@ class NodeConnectionManager {
18811966 }
18821967 }
18831968
1884- protected async authenticateCancel (
1969+ protected authenticateCancel (
18851970 targetNodeIdString : NodeIdString ,
18861971 reason : Error ,
18871972 ) {
0 commit comments