@@ -10,6 +10,8 @@ import (
1010 "time"
1111
1212 "github.com/btcsuite/btcd/btcec/v2"
13+ "github.com/btcsuite/btcd/btcec/v2/ecdsa"
14+ "github.com/btcsuite/btcd/chaincfg/chainhash"
1315 "github.com/lightninglabs/lightning-node-connect/mailbox"
1416 "github.com/lightninglabs/lightning-terminal/accounts"
1517 "github.com/lightninglabs/lightning-terminal/autopilotserver"
@@ -1010,6 +1012,52 @@ func (s *sessionRpcServer) AddAutopilotSession(ctx context.Context,
10101012 caveats = append (caveats , firewall .MetaPrivacyCaveat )
10111013 }
10121014
1015+ // If a previous session ID has been set to link this new one to, we
1016+ // first check if we have the referenced session, and we make sure it
1017+ // has been revoked.
1018+ var (
1019+ linkedGroupID * session.ID
1020+ linkedGroupSession * session.Session
1021+ )
1022+ if len (req .LinkedGroupId ) != 0 {
1023+ var groupID session.ID
1024+ copy (groupID [:], req .LinkedGroupId )
1025+
1026+ // Check that the group actually does exist.
1027+ groupSess , err := s .cfg .db .GetSessionByID (groupID )
1028+ if err != nil {
1029+ return nil , err
1030+ }
1031+
1032+ // Ensure that the linked session is in fact the first session
1033+ // in its group.
1034+ if groupSess .ID != groupSess .GroupID {
1035+ return nil , fmt .Errorf ("can not link to session " +
1036+ "%x since it is not the first in the session " +
1037+ "group %x" , groupSess .ID , groupSess .GroupID )
1038+ }
1039+
1040+ // Now we need to check that all the sessions in the group are
1041+ // no longer active.
1042+ ok , err := s .cfg .db .CheckSessionGroupPredicate (
1043+ groupID , func (s * session.Session ) bool {
1044+ return s .State == session .StateRevoked ||
1045+ s .State == session .StateExpired
1046+ },
1047+ )
1048+ if err != nil {
1049+ return nil , err
1050+ }
1051+
1052+ if ! ok {
1053+ return nil , fmt .Errorf ("a linked session in group " +
1054+ "%x is still active" , groupID )
1055+ }
1056+
1057+ linkedGroupID = & groupID
1058+ linkedGroupSession = groupSess
1059+ }
1060+
10131061 s .sessRegMu .Lock ()
10141062 defer s .sessRegMu .Unlock ()
10151063
@@ -1021,14 +1069,32 @@ func (s *sessionRpcServer) AddAutopilotSession(ctx context.Context,
10211069 sess , err := session .NewSession (
10221070 id , localPrivKey , req .Label , session .TypeAutopilot , expiry ,
10231071 req .MailboxServerAddr , req .DevServer , perms , caveats ,
1024- featureConfig , privacy , nil ,
1072+ featureConfig , privacy , linkedGroupID ,
10251073 )
10261074 if err != nil {
10271075 return nil , fmt .Errorf ("error creating new session: %v" , err )
10281076 }
10291077
1078+ // If this session is being linked to a previous one, then we need to
1079+ // use the previous session's local private key to sign the new
1080+ // session's public key in order to prove to the Autopilot server that
1081+ // the two session's belong to the same owner.
1082+ var (
1083+ linkSig []byte
1084+ prevSessionPub * btcec.PublicKey
1085+ )
1086+ if linkedGroupID != nil {
1087+ privKey := linkedGroupSession .LocalPrivateKey
1088+ pubKey := sess .LocalPublicKey .SerializeCompressed ()
1089+
1090+ msg := chainhash .HashB (pubKey )
1091+ linkSig = ecdsa .Sign (privKey , msg ).Serialize ()
1092+
1093+ prevSessionPub = linkedGroupSession .LocalPublicKey
1094+ }
1095+
10301096 // Register all the privacy map pairs for this session ID.
1031- privDB := s .cfg .privMap (sess .ID )
1097+ privDB := s .cfg .privMap (sess .GroupID )
10321098 err = privDB .Update (func (tx firewalldb.PrivacyMapTx ) error {
10331099 for r , p := range privacyMapPairs {
10341100 err := tx .NewPair (r , p )
@@ -1045,7 +1111,7 @@ func (s *sessionRpcServer) AddAutopilotSession(ctx context.Context,
10451111 // Attempt to register the session with the Autopilot server.
10461112 remoteKey , err := s .cfg .autopilot .RegisterSession (
10471113 ctx , sess .LocalPublicKey , sess .ServerAddr , sess .DevServer ,
1048- featureConfig , nil , nil ,
1114+ featureConfig , prevSessionPub , linkSig ,
10491115 )
10501116 if err != nil {
10511117 return nil , fmt .Errorf ("error registering session with " +
0 commit comments