This commit is contained in:
@@ -80,89 +80,44 @@ func (id *Identity) WipeFolder() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Creates an invitation for a peer, returns the newly created peer including infos to provide a ContactCard
|
||||
func (id *Identity) InvitePeer(MyName string, ContactName string, MessageServerUids []string, InvitationMessage string) (*Peer, error) {
|
||||
// InvitationStep1 creates a minimal pending peer with only a temporary keypair and returns
|
||||
// the InvitationInitPayload to be transmitted to the invitee (via file, QR code, or server).
|
||||
// Full keypairs are only generated in InvitationStep3, after the invitee's answer is received.
|
||||
func (id *Identity) InvitationStep1(MyName string, ContactName string, MessageServerUids []string, InvitationMessage string) (*meowlib.InvitationInitPayload, *Peer, error) {
|
||||
var peer Peer
|
||||
var err error
|
||||
peer.Uid = uuid.New().String()
|
||||
peer.MyIdentity, err = meowlib.NewKeyPair()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
peer.MyEncryptionKp, err = meowlib.NewKeyPair()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
peer.MyLookupKp, err = meowlib.NewKeyPair()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
peer.Name = ContactName
|
||||
peer.InvitationId = uuid.New().String() // todo as param to identify then update url
|
||||
symKeyBytes := make([]byte, 32)
|
||||
if _, err = rand.Read(symKeyBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
peer.MySymKey = base64.StdEncoding.EncodeToString(symKeyBytes)
|
||||
/* if id.MessageServers.Servers == nil {
|
||||
return nil, errors.New("no message servers defined in your identity")
|
||||
}
|
||||
for _, i := range MessageServerIdxs {
|
||||
if i > len(id.MessageServers.Servers)-1 {
|
||||
return nil, errors.New("requested server out of range of defined message servers")
|
||||
}
|
||||
}
|
||||
for _, i := range MessageServerIdxs {
|
||||
srv := id.MessageServers.Servers[i].GetServerCard()
|
||||
peer.MyContact.PullServers = append(peer.MyContact.PullServers, srv)
|
||||
}*/
|
||||
/* pullServers, err := id.MessageServers.LoadServerCardsFromUids(MessageServerUids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}*/
|
||||
peer.MyPullServers = MessageServerUids
|
||||
peer.MyName = MyName
|
||||
peer.InvitationId = uuid.New().String()
|
||||
peer.InvitationMessage = InvitationMessage
|
||||
peer.MyPullServers = MessageServerUids
|
||||
|
||||
// Generate DR keypair and root key for the initiator side
|
||||
drKp, err := doubleratchet.DefaultCrypto{}.GenerateDH()
|
||||
// Temporary keypair: public key is sent to invitee for step-2 encryption and as
|
||||
// the server-side lookup key where the invitee will post their answer.
|
||||
peer.InvitationKp, err = meowlib.NewKeyPair()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
peer.DrKpPrivate = base64.StdEncoding.EncodeToString(drKp.PrivateKey())
|
||||
peer.DrKpPublic = base64.StdEncoding.EncodeToString(drKp.PublicKey())
|
||||
drRootKey := make([]byte, 32)
|
||||
if _, err = rand.Read(drRootKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
peer.DrRootKey = base64.StdEncoding.EncodeToString(drRootKey)
|
||||
peer.DrInitiator = true
|
||||
|
||||
id.Peers.StorePeer(&peer)
|
||||
|
||||
return &peer, nil
|
||||
}
|
||||
|
||||
// Checks if the received contact card is an answer to an invitation, returns true if it is, and the proposed and received nicknames
|
||||
func (id *Identity) CheckInvitation(ReceivedContact *meowlib.ContactCard) (isAnswer bool, proposedNick string, receivedNick string, invitationMessage string) {
|
||||
// invitation Id found, this is an answer to an invitation
|
||||
/*for _, p := range id.Peers {
|
||||
if p.InvitationId == ReceivedContact.InvitationId {
|
||||
return true, p.Name, ReceivedContact.Name, ReceivedContact.InvitationMessage
|
||||
}
|
||||
payload := &meowlib.InvitationInitPayload{
|
||||
Uuid: peer.InvitationId,
|
||||
Name: MyName,
|
||||
PublicKey: peer.InvitationKp.Public,
|
||||
InvitationMessage: InvitationMessage,
|
||||
}
|
||||
|
||||
// it's an invitation
|
||||
return false, "", ReceivedContact.Name, ReceivedContact.InvitationMessage*/
|
||||
return id.Peers.CheckInvitation(ReceivedContact)
|
||||
return payload, &peer, nil
|
||||
}
|
||||
|
||||
// Answers an invitation, returns the newly created peer including infos to provide a ContactCard
|
||||
func (id *Identity) AnswerInvitation(MyName string, ContactName string, MessageServerIdxs []string, ReceivedContact *meowlib.ContactCard) (*Peer, error) {
|
||||
// InvitationStep2 creates the invitee's peer entry from the received InvitationInitPayload
|
||||
// and returns the peer. The invitee generates their full keypairs here.
|
||||
// The initiator's temporary public key (payload.PublicKey) is used both as the encryption
|
||||
// target for the step-2 answer and as the server-side lookup address.
|
||||
func (id *Identity) InvitationStep2(MyName string, ContactName string, MessageServerUids []string, payload *meowlib.InvitationInitPayload) (*Peer, error) {
|
||||
var peer Peer
|
||||
var err error
|
||||
var newsrv *Server
|
||||
//var myContactCard meowlib.ContactCard
|
||||
peer.Uid = uuid.New().String()
|
||||
peer.MyIdentity, err = meowlib.NewKeyPair()
|
||||
if err != nil {
|
||||
@@ -179,66 +134,116 @@ func (id *Identity) AnswerInvitation(MyName string, ContactName string, MessageS
|
||||
if ContactName != "" {
|
||||
peer.Name = ContactName
|
||||
} else {
|
||||
peer.Name = ReceivedContact.Name
|
||||
peer.Name = payload.Name
|
||||
}
|
||||
peer.ContactEncryption = ReceivedContact.EncryptionPublicKey
|
||||
peer.ContactLookupKey = ReceivedContact.LookupPublicKey
|
||||
peer.ContactPublicKey = ReceivedContact.ContactPublicKey
|
||||
peer.MySymKey = ReceivedContact.SymetricKey
|
||||
peer.InvitationId = ReceivedContact.InvitationId
|
||||
peer.InvitationMessage = ReceivedContact.InvitationMessage
|
||||
for srv := range ReceivedContact.PullServers {
|
||||
peer.ContactPullServers = append(peer.ContactPullServers, ReceivedContact.PullServers[srv].GetUid())
|
||||
newsrv, err = CreateServerFromUid(ReceivedContact.PullServers[srv].GetUid())
|
||||
id.MessageServers.StoreServerIfNotExists(newsrv)
|
||||
}
|
||||
/* for _, i := range MessageServerIdxs {
|
||||
srv := id.MessageServers.Servers[i].GetServerCard()
|
||||
peer.MyContact.PullServers = append(peer.MyContact.PullServers, srv)
|
||||
}*/
|
||||
/* srvCards, err := GetConfig().GetIdentity().MessageServers.LoadServerCardsFromUids(MessageServerIdxs)
|
||||
if err != nil {
|
||||
peer.MyContact.PullServers = srvCards
|
||||
}*/
|
||||
peer.MyPullServers = MessageServerIdxs
|
||||
// The initiator's temp key is used for both encrypting the answer and as destination.
|
||||
peer.ContactEncryption = payload.PublicKey
|
||||
peer.ContactLookupKey = payload.PublicKey
|
||||
peer.InvitationId = payload.Uuid
|
||||
peer.InvitationMessage = payload.InvitationMessage
|
||||
peer.MyPullServers = MessageServerUids
|
||||
peer.MyName = MyName
|
||||
peer.InvitationId = ReceivedContact.InvitationId
|
||||
// Adopt DR material from the initiator's ContactCard
|
||||
peer.DrRootKey = ReceivedContact.DrRootKey
|
||||
peer.ContactDrPublicKey = ReceivedContact.DrPublicKey
|
||||
peer.DrInitiator = false
|
||||
id.Peers.StorePeer(&peer)
|
||||
|
||||
return &peer, nil
|
||||
}
|
||||
|
||||
// Finalizes an invitation, returns nil if successful
|
||||
func (id *Identity) FinalizeInvitation(ReceivedContact *meowlib.ContactCard) error {
|
||||
// InvitationStep3 is called by the initiator after receiving and decrypting the invitee's
|
||||
// ContactCard (step-2 answer). It generates the initiator's full keypairs and DR material,
|
||||
// updates the pending peer with the invitee's contact info, and returns the initiator's
|
||||
// full ContactCard to be sent to the invitee (STEP_3_SEND).
|
||||
func (id *Identity) InvitationStep3(inviteeContact *meowlib.ContactCard) (*meowlib.ContactCard, *Peer, error) {
|
||||
var err error
|
||||
var newsrv *Server
|
||||
/*for i, p := range id.Peers {
|
||||
if p.InvitationId == ReceivedContact.InvitationId {
|
||||
//id.Peers[i].Name = ReceivedContact.Name
|
||||
id.Peers[i].ContactEncryption = ReceivedContact.EncryptionPublicKey
|
||||
id.Peers[i].ContactLookupKey = ReceivedContact.LookupPublicKey
|
||||
id.Peers[i].ContactPublicKey = ReceivedContact.ContactPublicKey
|
||||
srvs := []string{}
|
||||
for srv := range ReceivedContact.PullServers {
|
||||
srvs = append(srvs, ReceivedContact.PullServers[srv].GetUid())
|
||||
}
|
||||
id.Peers[i].ContactPullServers = srvs
|
||||
return nil
|
||||
peer := id.Peers.GetFromInvitationId(inviteeContact.InvitationId)
|
||||
if peer == nil {
|
||||
return nil, nil, errors.New("no pending peer found for invitation id " + inviteeContact.InvitationId)
|
||||
}
|
||||
|
||||
// Generate full keypairs now that the invitee's identity is known.
|
||||
peer.MyIdentity, err = meowlib.NewKeyPair()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
peer.MyEncryptionKp, err = meowlib.NewKeyPair()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
peer.MyLookupKp, err = meowlib.NewKeyPair()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
symKeyBytes := make([]byte, 32)
|
||||
if _, err = rand.Read(symKeyBytes); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
peer.MySymKey = base64.StdEncoding.EncodeToString(symKeyBytes)
|
||||
|
||||
// Generate DR keypair and root key.
|
||||
drKp, err := doubleratchet.DefaultCrypto{}.GenerateDH()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
peer.DrKpPrivate = base64.StdEncoding.EncodeToString(drKp.PrivateKey())
|
||||
peer.DrKpPublic = base64.StdEncoding.EncodeToString(drKp.PublicKey())
|
||||
drRootKey := make([]byte, 32)
|
||||
if _, err = rand.Read(drRootKey); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
peer.DrRootKey = base64.StdEncoding.EncodeToString(drRootKey)
|
||||
peer.DrInitiator = true
|
||||
|
||||
// Store invitee contact info.
|
||||
peer.ContactPublicKey = inviteeContact.ContactPublicKey
|
||||
peer.ContactEncryption = inviteeContact.EncryptionPublicKey
|
||||
peer.ContactLookupKey = inviteeContact.LookupPublicKey
|
||||
for _, srv := range inviteeContact.PullServers {
|
||||
peer.ContactPullServers = append(peer.ContactPullServers, srv.GetUid())
|
||||
newsrv, err := CreateServerFromUid(srv.GetUid())
|
||||
if err == nil {
|
||||
id.MessageServers.StoreServerIfNotExists(newsrv)
|
||||
}
|
||||
}
|
||||
return errors.New("no matching contact found for invitationId " + ReceivedContact.InvitationId)*/
|
||||
for srv := range ReceivedContact.PullServers {
|
||||
newsrv, err = CreateServerFromUid(ReceivedContact.PullServers[srv].GetUid())
|
||||
// Drop the temporary invitation keypair — no longer needed.
|
||||
peer.InvitationKp = nil
|
||||
|
||||
id.Peers.StorePeer(peer)
|
||||
|
||||
return peer.GetMyContact(), peer, nil
|
||||
}
|
||||
|
||||
// InvitationStep4 is called by the invitee upon receiving the initiator's full ContactCard
|
||||
// (carried as a regular UserMessage with invitation.step=3). It finalizes the peer entry.
|
||||
func (id *Identity) InvitationStep4(initiatorContact *meowlib.ContactCard) error {
|
||||
var err error
|
||||
var newsrv *Server
|
||||
for _, srv := range initiatorContact.PullServers {
|
||||
newsrv, err = CreateServerFromUid(srv.GetUid())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
id.MessageServers.StoreServerIfNotExists(newsrv)
|
||||
}
|
||||
return id.Peers.FinalizeInvitation(ReceivedContact)
|
||||
peer := id.Peers.GetFromInvitationId(initiatorContact.InvitationId)
|
||||
if peer == nil {
|
||||
return errors.New("no pending peer found for invitation id " + initiatorContact.InvitationId)
|
||||
}
|
||||
peer.ContactPublicKey = initiatorContact.ContactPublicKey
|
||||
peer.ContactEncryption = initiatorContact.EncryptionPublicKey
|
||||
peer.ContactLookupKey = initiatorContact.LookupPublicKey
|
||||
peer.MySymKey = initiatorContact.SymetricKey
|
||||
peer.DrRootKey = initiatorContact.DrRootKey
|
||||
peer.ContactDrPublicKey = initiatorContact.DrPublicKey
|
||||
peer.DrInitiator = false
|
||||
for _, srv := range initiatorContact.PullServers {
|
||||
peer.ContactPullServers = append(peer.ContactPullServers, srv.GetUid())
|
||||
}
|
||||
id.Peers.StorePeer(peer)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckInvitation checks if the received ContactCard is an answer to one of our pending
|
||||
// invitations. Returns true when it is, with the proposed and received nicknames.
|
||||
func (id *Identity) CheckInvitation(ReceivedContact *meowlib.ContactCard) (isAnswer bool, proposedNick string, receivedNick string, invitationMessage string) {
|
||||
return id.Peers.CheckInvitation(ReceivedContact)
|
||||
}
|
||||
|
||||
// LoadIdentity loads an identity from an encrypted file
|
||||
@@ -386,9 +391,18 @@ func (id *Identity) GetRequestJobs() []RequestsJob {
|
||||
return nil
|
||||
}
|
||||
for _, peer := range peers {
|
||||
// check if peer inviation is accepted
|
||||
for _, server := range peer.MyPullServers {
|
||||
srvs[server].LookupKeys = append(srvs[server].LookupKeys, peer.MyLookupKp)
|
||||
if srvs[server] == nil {
|
||||
continue
|
||||
}
|
||||
if peer.MyLookupKp != nil {
|
||||
// Active peer — use the permanent lookup key.
|
||||
srvs[server].LookupKeys = append(srvs[server].LookupKeys, peer.MyLookupKp)
|
||||
} else if peer.InvitationKp != nil {
|
||||
// Step-1 pending peer — poll using the temp invitation keypair so the
|
||||
// server-stored step-2 answer can be retrieved.
|
||||
srvs[server].LookupKeys = append(srvs[server].LookupKeys, peer.InvitationKp)
|
||||
}
|
||||
}
|
||||
}
|
||||
// add hidden peers
|
||||
|
||||
Reference in New Issue
Block a user