multi: allow client to link autopilot sessions

This commit is contained in:
Elle Mouton 2023-06-19 16:16:04 +02:00
parent 71cac8672f
commit 5882a21df8
No known key found for this signature in database
GPG key ID: D7D916376026F177
3 changed files with 84 additions and 4 deletions

View file

@ -29,7 +29,7 @@ type Autopilot interface {
// remains active.
RegisterSession(ctx context.Context, pubKey *btcec.PublicKey,
mailboxAddr string, devServer bool,
featureConf map[string][]byte, prevLocal *btcec.PublicKey,
featureConf map[string][]byte, linkedGroupKey *btcec.PublicKey,
linkSig []byte) (*btcec.PublicKey, error)
// ActivateSession attempts to inform the autopilot server that the

View file

@ -65,6 +65,11 @@ var addAutopilotSessionCmd = cli.Command{
"perform actions on. In the " +
"form of: peerID1,peerID2,...",
},
cli.StringFlag{
Name: "group_id",
Usage: "The hex encoded group ID of the session " +
"group to link this one to",
},
},
}
@ -224,6 +229,14 @@ func initAutopilotSession(ctx *cli.Context) error {
}
}
var groupID []byte
if ctx.IsSet("group_id") {
groupID, err = hex.DecodeString(ctx.String("group_id"))
if err != nil {
return err
}
}
resp, err := client.AddAutopilotSession(
ctxb, &litrpc.AddAutopilotSessionRequest{
Label: ctx.String("label"),
@ -231,6 +244,7 @@ func initAutopilotSession(ctx *cli.Context) error {
MailboxServerAddr: ctx.String("mailboxserveraddr"),
DevServer: ctx.Bool("devserver"),
Features: featureMap,
LinkedGroupId: groupID,
},
)
if err != nil {

View file

@ -10,6 +10,8 @@ import (
"time"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lightninglabs/lightning-node-connect/mailbox"
"github.com/lightninglabs/lightning-terminal/accounts"
"github.com/lightninglabs/lightning-terminal/autopilotserver"
@ -1010,6 +1012,52 @@ func (s *sessionRpcServer) AddAutopilotSession(ctx context.Context,
caveats = append(caveats, firewall.MetaPrivacyCaveat)
}
// If a previous session ID has been set to link this new one to, we
// first check if we have the referenced session, and we make sure it
// has been revoked.
var (
linkedGroupID *session.ID
linkedGroupSession *session.Session
)
if len(req.LinkedGroupId) != 0 {
var groupID session.ID
copy(groupID[:], req.LinkedGroupId)
// Check that the group actually does exist.
groupSess, err := s.cfg.db.GetSessionByID(groupID)
if err != nil {
return nil, err
}
// Ensure that the linked session is in fact the first session
// in its group.
if groupSess.ID != groupSess.GroupID {
return nil, fmt.Errorf("can not link to session "+
"%x since it is not the first in the session "+
"group %x", groupSess.ID, groupSess.GroupID)
}
// Now we need to check that all the sessions in the group are
// no longer active.
ok, err := s.cfg.db.CheckSessionGroupPredicate(
groupID, func(s *session.Session) bool {
return s.State == session.StateRevoked ||
s.State == session.StateExpired
},
)
if err != nil {
return nil, err
}
if !ok {
return nil, fmt.Errorf("a linked session in group "+
"%x is still active", groupID)
}
linkedGroupID = &groupID
linkedGroupSession = groupSess
}
s.sessRegMu.Lock()
defer s.sessRegMu.Unlock()
@ -1021,14 +1069,32 @@ func (s *sessionRpcServer) AddAutopilotSession(ctx context.Context,
sess, err := session.NewSession(
id, localPrivKey, req.Label, session.TypeAutopilot, expiry,
req.MailboxServerAddr, req.DevServer, perms, caveats,
featureConfig, privacy, nil,
featureConfig, privacy, linkedGroupID,
)
if err != nil {
return nil, fmt.Errorf("error creating new session: %v", err)
}
// If this session is being linked to a previous one, then we need to
// use the previous session's local private key to sign the new
// session's public key in order to prove to the Autopilot server that
// the two session's belong to the same owner.
var (
linkSig []byte
prevSessionPub *btcec.PublicKey
)
if linkedGroupID != nil {
privKey := linkedGroupSession.LocalPrivateKey
pubKey := sess.LocalPublicKey.SerializeCompressed()
msg := chainhash.HashB(pubKey)
linkSig = ecdsa.Sign(privKey, msg).Serialize()
prevSessionPub = linkedGroupSession.LocalPublicKey
}
// Register all the privacy map pairs for this session ID.
privDB := s.cfg.privMap(sess.ID)
privDB := s.cfg.privMap(sess.GroupID)
err = privDB.Update(func(tx firewalldb.PrivacyMapTx) error {
for r, p := range privacyMapPairs {
err := tx.NewPair(r, p)
@ -1045,7 +1111,7 @@ func (s *sessionRpcServer) AddAutopilotSession(ctx context.Context,
// Attempt to register the session with the Autopilot server.
remoteKey, err := s.cfg.autopilot.RegisterSession(
ctx, sess.LocalPublicKey, sess.ServerAddr, sess.DevServer,
featureConfig, nil, nil,
featureConfig, prevSessionPub, linkSig,
)
if err != nil {
return nil, fmt.Errorf("error registering session with "+