151 lines
5.9 KiB
Go
151 lines
5.9 KiB
Go
package helpers
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"forge.redroom.link/yves/meowlib"
|
|
"forge.redroom.link/yves/meowlib/client"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
// InvitationStep3ProcessAnswer is called by the initiator's background service when a
|
|
// step-2 answer (invitee's ContactCard) arrives via the invitation server poll.
|
|
// It decrypts the answer, calls InvitationStep3 to generate the initiator's full keypairs,
|
|
// and returns the peer and the initiator's ContactCard ready for STEP_3_SEND.
|
|
func InvitationStep3ProcessAnswer(invitation *meowlib.Invitation) (*client.Peer, *meowlib.ContactCard, string, error) {
|
|
var invitationAnswer meowlib.PackedUserMessage
|
|
if err := proto.Unmarshal(invitation.Payload, &invitationAnswer); err != nil {
|
|
return nil, nil, "InvitationStep3ProcessAnswer: Unmarshal PackedUserMessage", err
|
|
}
|
|
|
|
peer := client.GetConfig().GetIdentity().Peers.GetFromInvitationId(invitation.Uuid)
|
|
if peer == nil {
|
|
return nil, nil, "InvitationStep3ProcessAnswer: peer not found", errors.New("no peer for invitation uuid " + invitation.Uuid)
|
|
}
|
|
// Guard against duplicate delivery (e.g., same answer from multiple servers).
|
|
if peer.InvitationKp == nil {
|
|
return nil, nil, "", nil
|
|
}
|
|
|
|
// Decrypt invitee's ContactCard using the initiator's temporary InvitationKp.
|
|
usermsg, err := peer.ProcessInboundStep2UserMessage(&invitationAnswer, invitation.From)
|
|
if err != nil {
|
|
return nil, nil, "InvitationStep3ProcessAnswer: ProcessInboundStep2UserMessage", err
|
|
}
|
|
|
|
var inviteeCC meowlib.ContactCard
|
|
if err := proto.Unmarshal(usermsg.Invitation.Payload, &inviteeCC); err != nil {
|
|
return nil, nil, "InvitationStep3ProcessAnswer: Unmarshal ContactCard", err
|
|
}
|
|
|
|
myCC, peer, err := client.GetConfig().GetIdentity().InvitationStep3(&inviteeCC)
|
|
if err != nil {
|
|
return nil, nil, "InvitationStep3ProcessAnswer: InvitationStep3", err
|
|
}
|
|
client.GetConfig().GetIdentity().Save()
|
|
return peer, myCC, "", nil
|
|
}
|
|
|
|
// InvitationStep3Message builds and returns the packed server messages that send the
|
|
// initiator's full ContactCard to the invitee through the invitee's servers (STEP_3_SEND).
|
|
func InvitationStep3Message(invitationId string) ([][]byte, string, error) {
|
|
id := client.GetConfig().GetIdentity()
|
|
peer := id.Peers.GetFromInvitationId(invitationId)
|
|
if peer == nil {
|
|
return nil, "InvitationStep3Message: peer not found", errors.New("no peer for invitation id " + invitationId)
|
|
}
|
|
|
|
step3msg, err := peer.BuildInvitationStep3Message(peer.GetMyContact())
|
|
if err != nil {
|
|
return nil, "InvitationStep3Message: BuildInvitationStep3Message", err
|
|
}
|
|
// Step-3 must NOT use DR or sym layers: the invitee hasn't received those
|
|
// keys yet (they are carried inside this very message). Use plain asym only.
|
|
serialized, err := peer.SerializeUserMessage(step3msg)
|
|
if err != nil {
|
|
return nil, "InvitationStep3Message: SerializeUserMessage", err
|
|
}
|
|
enc, err := peer.AsymEncryptMessage(serialized)
|
|
if err != nil {
|
|
return nil, "InvitationStep3Message: AsymEncryptMessage", err
|
|
}
|
|
packedMsg := peer.PackUserMessage(enc.Data, enc.Signature)
|
|
|
|
var results [][]byte
|
|
for _, srvUid := range peer.ContactPullServers {
|
|
srv, err := id.MessageServers.LoadServer(srvUid)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
toSrvMsg := srv.BuildToServerMessageFromUserMessage(packedMsg)
|
|
bytemsg, err := srv.ProcessOutboundMessage(toSrvMsg)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
results = append(results, bytemsg)
|
|
}
|
|
if len(results) == 0 {
|
|
return nil, "InvitationStep3Message: no reachable invitee server", errors.New("could not build message for any invitee server")
|
|
}
|
|
return results, "", nil
|
|
}
|
|
|
|
// InvitationStep4ProcessStep3 is called by the invitee's message processing when a UserMessage
|
|
// with invitation.step==3 is received. It finalizes the initiator's peer entry.
|
|
func InvitationStep4ProcessStep3(usermsg *meowlib.UserMessage) (*client.Peer, string, error) {
|
|
if usermsg.Invitation == nil || usermsg.Invitation.Step != 3 {
|
|
return nil, "InvitationStep4ProcessStep3: unexpected step", errors.New("expected invitation step 3")
|
|
}
|
|
var initiatorCC meowlib.ContactCard
|
|
if err := proto.Unmarshal(usermsg.Invitation.Payload, &initiatorCC); err != nil {
|
|
return nil, "InvitationStep4ProcessStep3: Unmarshal ContactCard", err
|
|
}
|
|
// Patch the invitation ID from the outer message in case it was not set in the CC.
|
|
if initiatorCC.InvitationId == "" {
|
|
initiatorCC.InvitationId = usermsg.Invitation.Uuid
|
|
}
|
|
if err := client.GetConfig().GetIdentity().InvitationStep4(&initiatorCC); err != nil {
|
|
return nil, "InvitationStep4ProcessStep3: InvitationStep4", err
|
|
}
|
|
client.GetConfig().GetIdentity().Save()
|
|
peer := client.GetConfig().GetIdentity().Peers.GetFromInvitationId(initiatorCC.InvitationId)
|
|
return peer, "", nil
|
|
}
|
|
|
|
// InvitationStep4Message builds and returns the packed server messages that send the
|
|
// invitee's confirmation to the initiator through the initiator's servers (STEP_4).
|
|
func InvitationStep4Message(invitationId string) ([][]byte, string, error) {
|
|
id := client.GetConfig().GetIdentity()
|
|
peer := id.Peers.GetFromInvitationId(invitationId)
|
|
if peer == nil {
|
|
return nil, "InvitationStep4Message: peer not found", errors.New("no peer for invitation id " + invitationId)
|
|
}
|
|
|
|
step4msg, err := peer.BuildInvitationStep4Message()
|
|
if err != nil {
|
|
return nil, "InvitationStep4Message: BuildInvitationStep4Message", err
|
|
}
|
|
packedMsg, err := peer.ProcessOutboundUserMessage(step4msg)
|
|
if err != nil {
|
|
return nil, "InvitationStep4Message: ProcessOutboundUserMessage", err
|
|
}
|
|
|
|
var results [][]byte
|
|
for _, srvUid := range peer.ContactPullServers {
|
|
srv, err := id.MessageServers.LoadServer(srvUid)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
toSrvMsg := srv.BuildToServerMessageFromUserMessage(packedMsg)
|
|
bytemsg, err := srv.ProcessOutboundMessage(toSrvMsg)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
results = append(results, bytemsg)
|
|
}
|
|
if len(results) == 0 {
|
|
return nil, "InvitationStep4Message: no reachable initiator server", errors.New("could not build message for any initiator server")
|
|
}
|
|
return results, "", nil
|
|
}
|