@@ -10,6 +10,7 @@ import (
1010 "time"
1111
1212 "github.com/btcsuite/btcd/btcec/v2"
13+ "github.com/btcsuite/btcd/btcec/v2/ecdsa"
1314 "github.com/lightninglabs/lightning-node-connect/mailbox"
1415 "github.com/lightninglabs/lightning-terminal/accounts"
1516 "github.com/lightninglabs/lightning-terminal/autopilotserver"
@@ -997,16 +998,73 @@ func (s *sessionRpcServer) AddAutopilotSession(ctx context.Context,
997998 caveats = append (caveats , firewall .MetaPrivacyCaveat )
998999 }
9991000
1001+ // If a previous session ID has been set to link this new one to, we
1002+ // first check if we have the referenced session, and we make sure it
1003+ // has been revoked.
1004+ var prevSess * session.Session
1005+ if len (req .PrevLocalPub ) != 0 {
1006+ prevPub , err := btcec .ParsePubKey (req .PrevLocalPub )
1007+ if err != nil {
1008+ return nil , err
1009+ }
1010+
1011+ // Make sure that the previous session does actually exist.
1012+ prevSess , err = s .cfg .db .GetSession (prevPub )
1013+ if errors .Is (err , session .ErrSessionNotFound ) {
1014+ return nil , fmt .Errorf ("linked session(%x) not found" ,
1015+ req .PrevLocalPub )
1016+ } else if err != nil {
1017+ return nil , err
1018+ }
1019+
1020+ // Now we need to check that all the other sessions in the
1021+ // linked group are no longer active.
1022+
1023+ // First we use the session ID index to get the set of session
1024+ // IDs in this group.
1025+ prevSessionIDs , err := s .cfg .db .GetSessionIDs (
1026+ prevSess .GroupID ,
1027+ )
1028+ if err != nil {
1029+ return nil , err
1030+ }
1031+
1032+ // Now, check that they are all revoked or expired.
1033+ for _ , id := range prevSessionIDs {
1034+ prevSess , err := s .cfg .db .GetSessionByID (id )
1035+ if err != nil {
1036+ return nil , err
1037+ }
1038+
1039+ if prevSess .State != session .StateRevoked &&
1040+ prevSess .State != session .StateExpired {
1041+
1042+ return nil , fmt .Errorf ("linked session(%x) " +
1043+ "still active" , req .PrevLocalPub )
1044+ }
1045+ }
1046+ }
1047+
10001048 sess , err := session .NewSession (
10011049 req .Label , session .TypeAutopilot , expiry , req .MailboxServerAddr ,
1002- req .DevServer , perms , caveats , featureConfig , privacy , nil ,
1050+ req .DevServer , perms , caveats , featureConfig , privacy , prevSess ,
10031051 )
10041052 if err != nil {
10051053 return nil , fmt .Errorf ("error creating new session: %v" , err )
10061054 }
10071055
1056+ // If this session is being linked to a previous one, then we need to
1057+ // use the previous session's local private key to sign the new
1058+ // session's public key in order to prove to the Autopilot server that
1059+ // the two session's belong to the same owner.
1060+ var linkSig []byte
1061+ if prevSess != nil {
1062+ msg := sess .LocalPublicKey .SerializeCompressed ()
1063+ linkSig = ecdsa .Sign (prevSess .LocalPrivateKey , msg ).Serialize ()
1064+ }
1065+
10081066 // Register all the privacy map pairs for this session ID.
1009- privDB := s .cfg .privMap (sess .ID )
1067+ privDB := s .cfg .privMap (sess .GroupID )
10101068 err = privDB .Update (func (tx firewalldb.PrivacyMapTx ) error {
10111069 for r , p := range privacyMapPairs {
10121070 err := tx .NewPair (r , p )
@@ -1023,7 +1081,7 @@ func (s *sessionRpcServer) AddAutopilotSession(ctx context.Context,
10231081 // Attempt to register the session with the Autopilot server.
10241082 remoteKey , err := s .cfg .autopilot .RegisterSession (
10251083 ctx , sess .LocalPublicKey , sess .ServerAddr , sess .DevServer ,
1026- featureConfig , nil , nil ,
1084+ featureConfig , sess . PrevLocalPub , linkSig ,
10271085 )
10281086 if err != nil {
10291087 return nil , fmt .Errorf ("error registering session with " +
0 commit comments