Skip to content

Commit 5882a21

Browse files
committed
multi: allow client to link autopilot sessions
1 parent 71cac86 commit 5882a21

File tree

3 files changed

+84
-4
lines changed

3 files changed

+84
-4
lines changed

autopilotserver/interface.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ type Autopilot interface {
2929
// remains active.
3030
RegisterSession(ctx context.Context, pubKey *btcec.PublicKey,
3131
mailboxAddr string, devServer bool,
32-
featureConf map[string][]byte, prevLocal *btcec.PublicKey,
32+
featureConf map[string][]byte, linkedGroupKey *btcec.PublicKey,
3333
linkSig []byte) (*btcec.PublicKey, error)
3434

3535
// ActivateSession attempts to inform the autopilot server that the

cmd/litcli/autopilot.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ var addAutopilotSessionCmd = cli.Command{
6565
"perform actions on. In the " +
6666
"form of: peerID1,peerID2,...",
6767
},
68+
cli.StringFlag{
69+
Name: "group_id",
70+
Usage: "The hex encoded group ID of the session " +
71+
"group to link this one to",
72+
},
6873
},
6974
}
7075

@@ -224,13 +229,22 @@ func initAutopilotSession(ctx *cli.Context) error {
224229
}
225230
}
226231

232+
var groupID []byte
233+
if ctx.IsSet("group_id") {
234+
groupID, err = hex.DecodeString(ctx.String("group_id"))
235+
if err != nil {
236+
return err
237+
}
238+
}
239+
227240
resp, err := client.AddAutopilotSession(
228241
ctxb, &litrpc.AddAutopilotSessionRequest{
229242
Label: ctx.String("label"),
230243
ExpiryTimestampSeconds: uint64(sessionExpiry),
231244
MailboxServerAddr: ctx.String("mailboxserveraddr"),
232245
DevServer: ctx.Bool("devserver"),
233246
Features: featureMap,
247+
LinkedGroupId: groupID,
234248
},
235249
)
236250
if err != nil {

session_rpcserver.go

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)