invitation process upgrade
continuous-integration/drone/push Build is failing

This commit is contained in:
ycc
2026-04-02 18:50:04 +02:00
parent 9f130a80b7
commit 61e6598392
22 changed files with 1216 additions and 638 deletions
+44 -4
View File
@@ -129,9 +129,20 @@ func ConsumeInboxFile(messageFilename string) ([]string, []string, string, error
if err != nil { if err != nil {
return nil, nil, "ReadMessage: Unmarshal FromServerMessage", err return nil, nil, "ReadMessage: Unmarshal FromServerMessage", err
} }
// check if invitation answer // check if invitation answer (step-2 answer waiting for the initiator)
if fromServerMessage.Invitation != nil { if fromServerMessage.Invitation != nil {
invitationGetAnswerReadResponse(fromServerMessage.Invitation) peer, _, _, invErr := InvitationStep3ProcessAnswer(fromServerMessage.Invitation)
if invErr == nil && peer != nil {
// Auto-send step-3 CC to invitee's servers.
msgs, _, sendErr := InvitationStep3Message(peer.InvitationId)
if sendErr == nil {
for i, bytemsg := range msgs {
if i < len(peer.ContactPullServers) {
meowlib.HttpPostMessage(peer.ContactPullServers[i], bytemsg, client.GetConfig().HttpTimeOut)
}
}
}
}
} }
// Chat messages // Chat messages
if len(fromServerMessage.Chat) > 0 { if len(fromServerMessage.Chat) > 0 {
@@ -142,12 +153,41 @@ func ConsumeInboxFile(messageFilename string) ([]string, []string, string, error
if peer == nil { if peer == nil {
return nil, nil, "ReadMessage: GetFromMyLookupKey", errors.New("no visible peer for that message") return nil, nil, "ReadMessage: GetFromMyLookupKey", errors.New("no visible peer for that message")
} }
// Unpack the message // Unpack the message — step-3 messages arrive before the initiator's identity
usermsg, err := peer.ProcessInboundUserMessage(packedUserMessage) // key is known, so skip signature verification for pending peers.
var usermsg *meowlib.UserMessage
if peer.InvitationPending() {
usermsg, err = peer.ProcessInboundStep3UserMessage(packedUserMessage)
} else {
usermsg, err = peer.ProcessInboundUserMessage(packedUserMessage)
}
if err != nil { if err != nil {
return nil, nil, "ReadMessage: ProcessInboundUserMessage", err return nil, nil, "ReadMessage: ProcessInboundUserMessage", err
} }
// Handle invitation step 3: initiator's full ContactCard arriving at the invitee.
if usermsg.Invitation != nil && usermsg.Invitation.Step == 3 {
finalizedPeer, _, finalErr := InvitationStep4ProcessStep3(usermsg)
if finalErr == nil && finalizedPeer != nil {
// Auto-send step-4 confirmation to initiator's servers.
step4msgs, _, sendErr := InvitationStep4Message(finalizedPeer.InvitationId)
if sendErr == nil {
for i, bytemsg := range step4msgs {
if i < len(finalizedPeer.ContactPullServers) {
meowlib.HttpPostMessage(finalizedPeer.ContactPullServers[i], bytemsg, client.GetConfig().HttpTimeOut)
}
}
}
}
continue
}
// Handle invitation step 4: invitee's confirmation arriving at the initiator.
if usermsg.Invitation != nil && usermsg.Invitation.Step == 4 {
// Contact is fully active — nothing more to do on the initiator side.
continue
}
// Check for received or processed already filled => it's an ack for one of our sent messages // Check for received or processed already filled => it's an ack for one of our sent messages
if len(usermsg.Data) == 0 && usermsg.Status != nil && usermsg.Status.Uuid != "" && if len(usermsg.Data) == 0 && usermsg.Status != nil && usermsg.Status.Uuid != "" &&
(usermsg.Status.Received != 0 || usermsg.Status.Processed != 0) { (usermsg.Status.Received != 0 || usermsg.Status.Processed != 0) {
+57 -108
View File
@@ -1,161 +1,110 @@
package helpers package helpers
import ( import (
"C" "errors"
"fmt"
"os" "os"
"strings" "strings"
"forge.redroom.link/yves/meowlib" "forge.redroom.link/yves/meowlib"
"forge.redroom.link/yves/meowlib/client" "forge.redroom.link/yves/meowlib/client"
) )
import (
"errors"
)
// InvitationAnswer
func InvitationAnswer(cc *meowlib.ContactCard, nickname string, myNickname string, serverUids []string) (*client.Peer, string, error) {
// InvitationStep2Answer creates the invitee's peer from an InvitationInitPayload and returns
// the new peer (STEP_2, invitee side — in-memory, no server involved).
func InvitationStep2Answer(payload *meowlib.InvitationInitPayload, nickname string, myNickname string, serverUids []string) (*client.Peer, string, error) {
mynick := myNickname mynick := myNickname
// my nickname for that contact
if myNickname == "" { if myNickname == "" {
mynick = client.GetConfig().GetIdentity().Nickname mynick = client.GetConfig().GetIdentity().Nickname
} }
peer, err := client.GetConfig().GetIdentity().InvitationStep2(mynick, nickname, serverUids, payload)
// build my contact card for that friend
peer, err := client.GetConfig().GetIdentity().AnswerInvitation(mynick, nickname, serverUids, cc)
if err != nil { if err != nil {
return nil, "InvitationAnswer: AnswerInvitation", err return nil, "InvitationStep2Answer: InvitationStep2", err
} }
client.GetConfig().GetIdentity().Save()
//peerstr, err := json.Marshal(peer)
//fmt.Println("InvitationAnswer: " + string(peerstr))
c := client.GetConfig()
c.GetIdentity().Save()
return peer, "", nil return peer, "", nil
} }
// InvitationAnswerFile // InvitationStep2AnswerFile reads an InvitationInitPayload from a .mwiv file and creates the
func InvitationAnswerFile(invitationFile string, nickname string, myNickname string, serverUids []string) (string, error) { // invitee's peer. It also writes the invitee's ContactCard response to a file (STEP_2_SEND, file variant).
format := "qr" func InvitationStep2AnswerFile(invitationFile string, nickname string, myNickname string, serverUids []string) (string, error) {
var filename string = ""
var cc *meowlib.ContactCard
c := client.GetConfig()
if _, err := os.Stat(invitationFile); os.IsNotExist(err) { if _, err := os.Stat(invitationFile); os.IsNotExist(err) {
return "InvitationAnswerFile : os.Stat", err return "InvitationStep2AnswerFile: os.Stat", err
} }
if strings.HasSuffix(invitationFile, ".mwiv") { if !strings.HasSuffix(invitationFile, ".mwiv") {
format = "mwiv" return "InvitationStep2AnswerFile: unsupported format", errors.New("only .mwiv files are supported")
data, err := os.ReadFile(invitationFile)
if err != nil {
return "InvitationAnswerFile : os.ReadFile", err
}
cc, err = meowlib.NewContactCardFromCompressed(data)
if err != nil {
return "InvitationAnswerFile : NewContactCardFromCompressed", err
}
} }
identity := client.GetConfig().GetIdentity() data, err := os.ReadFile(invitationFile)
if cc != nil { if err != nil {
isAnswer, proposed, received, _ := identity.CheckInvitation(cc) return "InvitationStep2AnswerFile: os.ReadFile", err
if isAnswer {
fmt.Fprintln(os.Stdout, "This is already a response "+proposed+" to your invitation.")
fmt.Fprintln(os.Stdout, "You cannot answer again.")
fmt.Fprintln(os.Stdout, "You should finalize it by importing "+proposed+" contact card to your meow.")
fmt.Fprintln(os.Stdout, "Use : 'meow invitation finalize "+invitationFile+"' to do it.")
} else {
mynick := myNickname
// my nickname for that contact
if myNickname == "" {
mynick = client.GetConfig().GetIdentity().Nickname
}
response, err := identity.AnswerInvitation(mynick, nickname, serverUids, cc)
if err != nil {
return "InvitationAnswerFile : AnswerInvitation", err
}
fmt.Fprintln(os.Stdout, "Invitation sent by "+received)
if format == "qr" {
filename = c.StoragePath + string(os.PathSeparator) + mynick + "-" + nickname + ".png"
response.GetMyContact().WriteQr(filename)
} else {
filename = c.StoragePath + string(os.PathSeparator) + mynick + "-" + nickname + ".mwiv"
response.GetMyContact().WriteCompressed(filename)
}
client.GetConfig().GetIdentity().Save()
}
} }
payload, err := meowlib.NewInvitationInitPayloadFromCompressed(data)
if err != nil {
return "InvitationStep2AnswerFile: NewInvitationInitPayloadFromCompressed", err
}
mynick := myNickname
if myNickname == "" {
mynick = client.GetConfig().GetIdentity().Nickname
}
c := client.GetConfig()
response, err := c.GetIdentity().InvitationStep2(mynick, nickname, serverUids, payload)
if err != nil {
return "InvitationStep2AnswerFile: InvitationStep2", err
}
filename := c.StoragePath + string(os.PathSeparator) + mynick + "-" + nickname + ".mwiv"
if err := response.GetMyContact().WriteCompressed(filename); err != nil {
return "InvitationStep2AnswerFile: WriteCompressed", err
}
c.GetIdentity().Save()
return "", nil return "", nil
} }
// InvitationAnswerMessage // InvitationStep2AnswerMessage builds and returns the packed server message that posts the
func InvitationAnswerMessage(invitationId string, invitationServerUid string, timeout int) ([]byte, string, error) { // invitee's ContactCard (encrypted with the initiator's temp key) to the invitation server
// (STEP_2_SEND, through-server variant).
// find the peer with that invitation id func InvitationStep2AnswerMessage(invitationId string, invitationServerUid string, timeout int) ([]byte, string, error) {
/*var peer *client.Peer
for i := len(client.GetConfig().GetIdentity().Peers) - 1; i >= 0; i-- { //! to allow self invitation : testing only, findinc the received peer before myself
// for i := 0; i < len(client.GetConfig().GetIdentity().Peers); i++ {
if client.GetConfig().GetIdentity().Peers[i].InvitationId == invitationId {
peer = client.GetConfig().GetIdentity().Peers[i]
break
}
}*/
peer := client.GetConfig().GetIdentity().Peers.GetFromInvitationId(invitationId) peer := client.GetConfig().GetIdentity().Peers.GetFromInvitationId(invitationId)
if peer == nil { if peer == nil {
// declare a custom go error for no peer found return nil, "InvitationStep2AnswerMessage: peer not found", errors.New("no peer with that invitation id")
return nil, "InvitationAnswerMessage: loop for peer", errors.New("no peer with that invitation id")
} }
answermsg, err := peer.BuildInvitationAnswerMessage(peer.GetMyContact())
answermsg, err := peer.BuildInvitationStep2Message(peer.GetMyContact())
if err != nil { if err != nil {
return nil, "InvitationAnswerMessage: BuildInvitationAnswserMessage", err return nil, "InvitationStep2AnswerMessage: BuildInvitationStep2Message", err
} }
// Server: get the invitation server
invitationServer, err := client.GetConfig().GetIdentity().MessageServers.LoadServer(invitationServerUid) invitationServer, err := client.GetConfig().GetIdentity().MessageServers.LoadServer(invitationServerUid)
if err != nil { if err != nil {
return nil, "InvitationAnswerMessage: LoadServer", err return nil, "InvitationStep2AnswerMessage: LoadServer", err
} }
// this will be the invitation's payload
packedMsg, err := peer.ProcessOutboundUserMessage(answermsg) packedMsg, err := peer.ProcessOutboundUserMessage(answermsg)
if err != nil { if err != nil {
return nil, "InvitationAnswerMessage: ProcessOutboundUserMessage", err return nil, "InvitationStep2AnswerMessage: ProcessOutboundUserMessage", err
} }
// Creating Server message for transporting the user message
toServerMessage, err := invitationServer.BuildToServerMessageInvitationAnswer(packedMsg, peer.MyIdentity.Public, invitationId, timeout) toServerMessage, err := invitationServer.BuildToServerMessageInvitationAnswer(packedMsg, peer.MyIdentity.Public, invitationId, timeout)
if err != nil { if err != nil {
return nil, "InvitationAnswerMessage: BuildToServerMessageInvitationAnswer", err return nil, "InvitationStep2AnswerMessage: BuildToServerMessageInvitationAnswer", err
} }
// Server outbound processing
bytemsg, err := invitationServer.ProcessOutboundMessage(toServerMessage) bytemsg, err := invitationServer.ProcessOutboundMessage(toServerMessage)
if err != nil { if err != nil {
return nil, "InvitationAnswerMessage: ProcessOutboundMessage", err return nil, "InvitationStep2AnswerMessage: ProcessOutboundMessage", err
} }
return bytemsg, "", nil return bytemsg, "", nil
} }
// InvitationAnswerMessageReadResponse // InvitationStep2AnswerMessageReadResponse reads the server acknowledgement of a Step2 answer.
// Called by the invitation receiver func InvitationStep2AnswerMessageReadResponse(invitationData []byte, invitationServerUid string) (*meowlib.Invitation, string, error) {
// invitationData: the data received from the server
// invitationServerUid: the uid of the server holding the invitation
func InvitationAnswerMessageReadResponse(invitationData []byte, invitationServerUid string) (*meowlib.Invitation, string, error) {
server, err := client.GetConfig().GetIdentity().MessageServers.LoadServer(invitationServerUid) server, err := client.GetConfig().GetIdentity().MessageServers.LoadServer(invitationServerUid)
if err != nil { if err != nil {
return nil, "InvitationAnswerMessageReadResponse: LoadServer", err return nil, "InvitationStep2AnswerMessageReadResponse: LoadServer", err
} }
// Server inbound processing : get the invitation server
serverMsg, err := server.ProcessInboundServerResponse(invitationData) serverMsg, err := server.ProcessInboundServerResponse(invitationData)
if err != nil { if err != nil {
return nil, "InvitationAnswerMessageReadResponse: ProcessInboundServerResponse", err return nil, "InvitationStep2AnswerMessageReadResponse: ProcessInboundServerResponse", err
} }
return serverMsg.Invitation, "", nil return serverMsg.Invitation, "", nil
} }
+22 -85
View File
@@ -7,84 +7,31 @@ import (
"forge.redroom.link/yves/meowlib/client" "forge.redroom.link/yves/meowlib/client"
) )
// InvitationCheck // InvitationStep2GetMessage builds and returns the packed server message that retrieves
// todo // the InvitationInitPayload from the server using the shortcode URL (STEP_2, invitee side).
/* func InvitationStep2GetMessage(invitationUrl string, serverPublicKey string, invitationPassword string) ([]byte, string, error) {
func InvitationCheck(invitationdata []byte) *C.char {
var jsoninv map[string]interface{}
err := json.Unmarshal([]byte(C.GoString(invitationdata)), &jsoninv)
if err != nil {
return C.CString(errorToJson(err, "InvitationCheck: "))
}
var cc *meowlib.ContactCard
if _, err := os.Stat(jsoninv["filename"].(string)); os.IsNotExist(err) {
return C.CString(errorToJson(err, "InvitationCheck: "))
}
if strings.HasSuffix(jsoninv["filename"].(string), ".mwiv") {
data, err := os.ReadFile(jsoninv["filename"].(string))
if err != nil {
return C.CString(errorToJson(err, "InvitationCheck: "))
}
cc, err = meowlib.NewContactCardFromCompressed(data)
if err != nil {
return C.CString(errorToJson(err, "InvitationCheck: "))
}
}
identity := client.GetConfig().GetIdentity()
result := map[string]string{}
if cc != nil {
isAnswer, proposed, received, invitationMessage := identity.CheckInvitation(cc)
if isAnswer { // answer to infitation
result["type"] = "answer"
result["to"] = proposed
result["from"] = received
result["invitation_message"] = invitationMessage
//fmt.Fprintln(os.Stdout, "Invitation sent to "+proposed+" received with "+received+" as suggested nickname")
} else { // finalization message
result["type"] = "finalize"
result["from"] = received
//fmt.Fprintln(os.Stdout, "Invitation sent by "+received)
}
}
val, err := json.Marshal(result)
if err != nil {
return C.CString(errorToJson(err, "InvitationCheck: "))
}
return C.CString(string(val))
}*/
// InvitationGetMessage
// Called by the invitation receiver
// invitationUrl: the url of server holding the invitation
// serverPublicKey: the public key of the server holding the invitation
// invitationPassword: the password of the invitation
func InvitationGetMessage(invitationUrl string, serverPublicKey string, invitationPassword string) ([]byte, string, error) {
meowurl := strings.Split(invitationUrl, "?") meowurl := strings.Split(invitationUrl, "?")
shortcode := meowurl[1] shortcode := meowurl[1]
srv, err := client.CreateServerFromMeowUrl(meowurl[0]) srv, err := client.CreateServerFromMeowUrl(meowurl[0])
if err != nil { if err != nil {
return nil, "InvitationGetMessage: CreateServerFromMeowUrl", err return nil, "InvitationStep2GetMessage: CreateServerFromMeowUrl", err
} }
// check if already in msg servers
// Reuse the server entry if already known.
dbsrv, err := client.GetConfig().GetIdentity().MessageServers.LoadServer(srv.Url) dbsrv, err := client.GetConfig().GetIdentity().MessageServers.LoadServer(srv.Url)
if err != nil { if err != nil {
return nil, "InvitationGetMessage: LoadServer", err return nil, "InvitationStep2GetMessage: LoadServer", err
} }
if dbsrv == nil { if dbsrv == nil {
// create a server object with url & pubkey
srv.PublicKey = serverPublicKey srv.PublicKey = serverPublicKey
k, err := meowlib.NewKeyPair() k, err := meowlib.NewKeyPair()
if err != nil { if err != nil {
return nil, "InvitationGetMessage: NewKeyPair", err return nil, "InvitationStep2GetMessage: NewKeyPair", err
} }
srv.UserKp = k srv.UserKp = k
// save it if err := client.GetConfig().GetIdentity().MessageServers.StoreServer(srv); err != nil {
err = client.GetConfig().GetIdentity().MessageServers.StoreServer(srv) return nil, "InvitationStep2GetMessage: StoreServer", err
if err != nil {
return nil, "InvitationGetMessage: StoreServer", err
} }
} else { } else {
if dbsrv.PublicKey != serverPublicKey { if dbsrv.PublicKey != serverPublicKey {
@@ -92,42 +39,32 @@ func InvitationGetMessage(invitationUrl string, serverPublicKey string, invitati
} }
srv = dbsrv srv = dbsrv
} }
// buildserver message
toSrvMsg, err := srv.BuildToServerMessageInvitationRequest(shortcode, invitationPassword) toSrvMsg, err := srv.BuildToServerMessageInvitationRequest(shortcode, invitationPassword)
if err != nil { if err != nil {
return nil, "InvitationGetMessage: BuildToServerMessageInvitationRequest", err return nil, "InvitationStep2GetMessage: BuildToServerMessageInvitationRequest", err
} }
// processoutbound
bytemsg, err := srv.ProcessOutboundMessage(toSrvMsg) bytemsg, err := srv.ProcessOutboundMessage(toSrvMsg)
if err != nil { if err != nil {
return nil, "InvitationGetMessage: ProcessOutboundMessage", err return nil, "InvitationStep2GetMessage: ProcessOutboundMessage", err
} }
return bytemsg, "", nil return bytemsg, "", nil
} }
// InvitationGetMessageReadResponse // InvitationStep2ReadResponse decodes the server response to a Step2 get-message and returns
// Called by the invitation receiver // the InvitationInitPayload sent by the initiator.
// invitationData: the data received from the server func InvitationStep2ReadResponse(invitationData []byte, invitationServerUid string) (*meowlib.InvitationInitPayload, string, error) {
// invitationServerUid: the uid of the server holding the invitation
func InvitationGetMessageReadResponse(invitationData []byte, invitationServerUid string) (*meowlib.ContactCard, string, error) {
server, err := client.GetConfig().GetIdentity().MessageServers.LoadServer(invitationServerUid) server, err := client.GetConfig().GetIdentity().MessageServers.LoadServer(invitationServerUid)
if err != nil { if err != nil {
return nil, "InvitationGetMessageReadResponse: LoadServer", err return nil, "InvitationStep2ReadResponse: LoadServer", err
} }
// Server inbound processing : get the invitation server
serverMsg, err := server.ProcessInboundServerResponse(invitationData) serverMsg, err := server.ProcessInboundServerResponse(invitationData)
if err != nil { if err != nil {
return nil, "InvitationGetMessageReadResponse: ProcessInboundServerResponse", err return nil, "InvitationStep2ReadResponse: ProcessInboundServerResponse", err
} }
// fmt.Println("Inbound OK, Invitation Step: ", serverMsg.Invitation.Step, len(serverMsg.Invitation.Payload)) payload, err := meowlib.NewInvitationInitPayloadFromCompressed(serverMsg.Invitation.Payload)
// fmt.Println("Invitation Check")
// fmt.Println(hex.EncodeToString(serverMsg.Invitation.Payload))
// contactCard decode
cc, err := meowlib.NewContactCardFromCompressed(serverMsg.Invitation.Payload)
if err != nil { if err != nil {
return nil, "InvitationGetMessageReadResponse: NewContactCardFromCompressed", err return nil, "InvitationStep2ReadResponse: NewInvitationInitPayloadFromCompressed", err
} }
return cc, "", nil return payload, "", nil
} }
+46 -87
View File
@@ -8,136 +8,95 @@ import (
"forge.redroom.link/yves/meowlib/client" "forge.redroom.link/yves/meowlib/client"
) )
// InvitationCreatePeer creates a new peer and returns it // InvitationStep1CreatePeer creates a minimal pending peer and returns the InvitationInitPayload
// Called by invitation initiator // to be transmitted to the invitee (STEP_1).
// name: the name of the peer func InvitationStep1CreatePeer(contactName string, myNickname string, invitationMessage string, serverUids []string) (*meowlib.InvitationInitPayload, *client.Peer, string, error) {
// myNickname: my nickname for that peer
// invitationMessage: the message to send to the peer
// serverUids: the list of server uids
func InvitationCreatePeer(name string, myNickname string, invitationMessage string, serverUids []string) (*client.Peer, string, error) {
mynick := myNickname mynick := myNickname
if myNickname == "" { if myNickname == "" {
mynick = client.GetConfig().GetIdentity().Nickname mynick = client.GetConfig().GetIdentity().Nickname
} }
payload, peer, err := client.GetConfig().GetIdentity().InvitationStep1(mynick, contactName, serverUids, invitationMessage)
// build my contact card for that friend
peer, err := client.GetConfig().GetIdentity().InvitePeer(mynick, name, serverUids, invitationMessage)
if err != nil { if err != nil {
return nil, "InvitationCreate: InvitePeer", err return nil, nil, "InvitationStep1CreatePeer: InvitationStep1", err
} }
client.GetConfig().GetIdentity().Save() client.GetConfig().GetIdentity().Save()
return payload, peer, "", nil
return peer, "", nil
} }
// InvitationCreateFile creates a new peer and writes the invitation to a file // InvitationStep1File creates a pending peer and writes the InvitationInitPayload to a file
// Called by invitation initiator // (format: "qr" for QR-code PNG, anything else for compressed binary .mwiv).
// name: the name of the peer func InvitationStep1File(contactName string, myNickname string, invitationMessage string, serverUids []string, format string) (*client.Peer, string, error) {
// myNickname: my nickname for that peer payload, peer, errdata, err := InvitationStep1CreatePeer(contactName, myNickname, invitationMessage, serverUids)
// invitationMessage: the message to send to the peer
// serverUids: the list of server uids
// format: the format of the file (qr or mwiv)
func InvitationCreateFile(name string, myNickname string, invitationMessage string, serverUids []string, format string) (*client.Peer, string, error) {
peer, errdata, err := InvitationCreatePeer(name, myNickname, invitationMessage, serverUids)
if err != nil { if err != nil {
return nil, errdata, err return nil, errdata, err
} }
c := client.GetConfig() c := client.GetConfig()
var filename string = ""
if format == "qr" { if format == "qr" {
filename = c.StoragePath + string(os.PathSeparator) + peer.MyName + "-" + peer.Name + ".png" filename := c.StoragePath + string(os.PathSeparator) + peer.MyName + "-" + peer.Name + ".png"
err := peer.GetMyContact().WriteQr(filename) if err := payload.WriteQr(filename); err != nil {
if err != nil { return nil, "InvitationStep1File: WriteQr", err
return nil, "InvitationCreateFile: WriteQr", err
} }
} else { } else {
filename = c.StoragePath + string(os.PathSeparator) + peer.MyName + "-" + peer.Name + ".mwiv" filename := c.StoragePath + string(os.PathSeparator) + peer.MyName + "-" + peer.Name + ".mwiv"
err := peer.GetMyContact().WriteCompressed(filename) if err := payload.WriteCompressed(filename); err != nil {
if err != nil { return nil, "InvitationStep1File: WriteCompressed", err
return nil, "InvitationCreateFile: WriteCompressed", err
} }
} }
return peer, "", nil return peer, "", nil
} }
// InvitationCreateMessage creates a new invitation message for an invited peer // InvitationStep1Message builds and returns the packed server message that posts the
// Called by invitation initiator // InvitationInitPayload to the invitation server (STEP_1 through-server variant).
// invitationId: the invitation id of the peer func InvitationStep1Message(invitationId string, invitationServerUid string, timeOut int, urlLen int, password string) ([]byte, string, error) {
// invitationServerUid: the uid of the server for sending the invitation
// timeOut: the timeout for the invitation
// urlLen: the length of the invitation url
// password: the password for the invitation
func InvitationCreateMessage(invitationId string, invitationServerUid string, timeOut int, urlLen int, password string) ([]byte, string, error) {
// lookup for peer with "invitation_id"
var myContact *meowlib.ContactCard
/* for i := 0; i < len(client.GetConfig().GetIdentity().Peers); i++ {
if client.GetConfig().GetIdentity().Peers[i].InvitationId == invitationId {
myContact = client.GetConfig().GetIdentity().Peers[i].GetMyContact()
break
}
}*/
peer := client.GetConfig().GetIdentity().Peers.GetFromInvitationId(invitationId) peer := client.GetConfig().GetIdentity().Peers.GetFromInvitationId(invitationId)
myContact = peer.GetMyContact() if peer == nil {
// todo handle not found !! return nil, "InvitationStep1Message: peer not found", nil
// lookup for message server with "invitation_server"
invitationServer, err := client.GetConfig().GetIdentity().MessageServers.LoadServer(invitationServerUid) //.GetServerByIdx(int(jsoninv["invitation_server"].(float64)))
if err != nil {
return nil, "InvitationCreateMessage: LoadServer", err
} }
// call server.buildinviattion if peer.InvitationKp == nil {
msg, err := invitationServer.BuildToServerMessageInvitationCreation(myContact, password, timeOut, urlLen) return nil, "InvitationStep1Message: peer has no InvitationKp", nil
if err != nil { }
return nil, "InvitationCreateMessage: BuildToServerMessageInvitationCreation", err initPayload := &meowlib.InvitationInitPayload{
Uuid: peer.InvitationId,
Name: peer.MyName,
PublicKey: peer.InvitationKp.Public,
InvitationMessage: peer.InvitationMessage,
}
invitationServer, err := client.GetConfig().GetIdentity().MessageServers.LoadServer(invitationServerUid)
if err != nil {
return nil, "InvitationStep1Message: LoadServer", err
}
msg, err := invitationServer.BuildToServerMessageInvitationStep1(initPayload, password, timeOut, urlLen)
if err != nil {
return nil, "InvitationStep1Message: BuildToServerMessageInvitationStep1", err
} }
// fmt.Println("Invitation Create")
// fmt.Println(hex.EncodeToString(msg.Invitation.Payload))
bytemsg, err := invitationServer.ProcessOutboundMessage(msg) bytemsg, err := invitationServer.ProcessOutboundMessage(msg)
if err != nil { if err != nil {
return nil, "InvitationCreateMessage: ProcessOutboundMessage", err return nil, "InvitationStep1Message: ProcessOutboundMessage", err
} }
return bytemsg, "", nil return bytemsg, "", nil
} }
// InvitationCreateReadResponse reads the response of an invitation creation (url, expiry) // InvitationStep1ReadResponse reads the server response to a Step1 message (shortcode URL + expiry).
// Called by invitation initiator func InvitationStep1ReadResponse(invitationServerUid string, invitationResponse []byte) (*meowlib.Invitation, string, error) {
// invitationServerUid: the uid of the server where we sent the invitation
// invitationResponse: the response we got from the server
func InvitationCreateReadResponse(invitationServerUid string, invitationResponse []byte) (*meowlib.Invitation, string, error) {
server, err := client.GetConfig().GetIdentity().MessageServers.LoadServer(invitationServerUid) server, err := client.GetConfig().GetIdentity().MessageServers.LoadServer(invitationServerUid)
if err != nil { if err != nil {
return nil, "InvitationCreateReadResponse: LoadServer", err return nil, "InvitationStep1ReadResponse: LoadServer", err
} }
serverMsg, err := server.ProcessInboundServerResponse(invitationResponse) serverMsg, err := server.ProcessInboundServerResponse(invitationResponse)
if err != nil { if err != nil {
return nil, "InvitationCreateReadResponse: ProcessInboundServerResponse", err return nil, "InvitationStep1ReadResponse: ProcessInboundServerResponse", err
} }
return serverMsg.Invitation, "", nil return serverMsg.Invitation, "", nil
} }
// InvitationSetUrlInfo sets the url info for an invitation // InvitationSetUrlInfo stores the shortcode URL and expiry on the pending peer.
// Called by invitation initiator
// invitationId: the invitation id of the peer
// url: the url of the invitation we got from the server
func InvitationSetUrlInfo(invitationId string, url string, expiry int64) { func InvitationSetUrlInfo(invitationId string, url string, expiry int64) {
id := client.GetConfig().GetIdentity() id := client.GetConfig().GetIdentity()
// lookup for peer with "invitation_id"
peer := id.Peers.GetFromInvitationId(invitationId) peer := id.Peers.GetFromInvitationId(invitationId)
if peer == nil {
return
}
peer.InvitationUrl = url peer.InvitationUrl = url
peer.InvitationExpiry = time.Unix(expiry, 0) peer.InvitationExpiry = time.Unix(expiry, 0)
id.Peers.StorePeer(peer) id.Peers.StorePeer(peer)
/* for i := 0; i < len(client.GetConfig().GetIdentity().Peers); i++ {
if client.GetConfig().GetIdentity().Peers[i].InvitationId == invitationId {
client.GetConfig().GetIdentity().Peers[i].InvitationUrl = url
client.GetConfig().GetIdentity().Peers[i].InvitationExpiry = time.Unix(expiry, 0)
break
}
}
client.GetConfig().GetIdentity().Save()*/
} }
+136 -39
View File
@@ -1,53 +1,150 @@
package helpers package helpers
import ( import (
"errors"
"forge.redroom.link/yves/meowlib" "forge.redroom.link/yves/meowlib"
"forge.redroom.link/yves/meowlib/client" "forge.redroom.link/yves/meowlib/client"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
) )
// Got it by the message background check // InvitationStep3ProcessAnswer is called by the initiator's background service when a
// => noInvitationGetAnswer // 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,
// invitationGetAnswerReadResponse // and returns the peer and the initiator's ContactCard ready for STEP_3_SEND.
// Called by the initiator's background service only func InvitationStep3ProcessAnswer(invitation *meowlib.Invitation) (*client.Peer, *meowlib.ContactCard, string, error) {
// invitationAnswerData: the data received from the server
// invitationServerUid: the uid of the server holding the invitation
func invitationGetAnswerReadResponse(invitation *meowlib.Invitation) (*client.Peer, string, error) {
// decode the payload
var invitationAnswer meowlib.PackedUserMessage var invitationAnswer meowlib.PackedUserMessage
err := proto.Unmarshal(invitation.Payload, &invitationAnswer) if err := proto.Unmarshal(invitation.Payload, &invitationAnswer); err != nil {
if err != nil { return nil, nil, "InvitationStep3ProcessAnswer: Unmarshal PackedUserMessage", err
return nil, "InvitationGetAnswerReadResponse: Unmarshal", err
} }
// retreive user public key to check usermessage signature
// contactPublikKey := serverMsg.Invitation.From
peer := client.GetConfig().GetIdentity().Peers.GetFromInvitationId(invitation.Uuid) peer := client.GetConfig().GetIdentity().Peers.GetFromInvitationId(invitation.Uuid)
peer.ContactPublicKey = invitation.From if peer == nil {
if peer != nil { return nil, nil, "InvitationStep3ProcessAnswer: peer not found", errors.New("no peer for invitation uuid " + invitation.Uuid)
// process the packed user message
usermsg, err := peer.ProcessInboundUserMessage(&invitationAnswer)
if err != nil {
return nil, "InvitationGetAnswerReadResponse: ProcessInboundUserMessage", err
}
decodedInvitation := usermsg.Invitation
var cc meowlib.ContactCard
err = proto.Unmarshal(decodedInvitation.Payload, &cc)
if err != nil {
return nil, "InvitationGetAnswerReadResponse: Unmarshal", err
}
// finalize the invitation
// id := client.GetConfig().GetIdentity()
peer.ContactLookupKey = cc.ContactPublicKey
peer.ContactEncryption = cc.EncryptionPublicKey
for _, server := range cc.PullServers {
peer.ContactPullServers = append(peer.ContactPullServers, server.GetUid())
}
client.GetConfig().GetIdentity().Save()
} }
// 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 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
}
+128 -114
View File
@@ -80,89 +80,44 @@ func (id *Identity) WipeFolder() error {
return nil return nil
} }
// Creates an invitation for a peer, returns the newly created peer including infos to provide a ContactCard // InvitationStep1 creates a minimal pending peer with only a temporary keypair and returns
func (id *Identity) InvitePeer(MyName string, ContactName string, MessageServerUids []string, InvitationMessage string) (*Peer, error) { // 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 peer Peer
var err error var err error
peer.Uid = uuid.New().String() 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.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.MyName = MyName
peer.InvitationId = uuid.New().String()
peer.InvitationMessage = InvitationMessage peer.InvitationMessage = InvitationMessage
peer.MyPullServers = MessageServerUids
// Generate DR keypair and root key for the initiator side // Temporary keypair: public key is sent to invitee for step-2 encryption and as
drKp, err := doubleratchet.DefaultCrypto{}.GenerateDH() // the server-side lookup key where the invitee will post their answer.
peer.InvitationKp, err = meowlib.NewKeyPair()
if err != nil { 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) id.Peers.StorePeer(&peer)
return &peer, nil payload := &meowlib.InvitationInitPayload{
} Uuid: peer.InvitationId,
Name: MyName,
// Checks if the received contact card is an answer to an invitation, returns true if it is, and the proposed and received nicknames PublicKey: peer.InvitationKp.Public,
func (id *Identity) CheckInvitation(ReceivedContact *meowlib.ContactCard) (isAnswer bool, proposedNick string, receivedNick string, invitationMessage string) { InvitationMessage: InvitationMessage,
// 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
}
} }
return payload, &peer, nil
// it's an invitation
return false, "", ReceivedContact.Name, ReceivedContact.InvitationMessage*/
return id.Peers.CheckInvitation(ReceivedContact)
} }
// Answers an invitation, returns the newly created peer including infos to provide a ContactCard // InvitationStep2 creates the invitee's peer entry from the received InvitationInitPayload
func (id *Identity) AnswerInvitation(MyName string, ContactName string, MessageServerIdxs []string, ReceivedContact *meowlib.ContactCard) (*Peer, error) { // 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 peer Peer
var err error var err error
var newsrv *Server
//var myContactCard meowlib.ContactCard
peer.Uid = uuid.New().String() peer.Uid = uuid.New().String()
peer.MyIdentity, err = meowlib.NewKeyPair() peer.MyIdentity, err = meowlib.NewKeyPair()
if err != nil { if err != nil {
@@ -179,66 +134,116 @@ func (id *Identity) AnswerInvitation(MyName string, ContactName string, MessageS
if ContactName != "" { if ContactName != "" {
peer.Name = ContactName peer.Name = ContactName
} else { } else {
peer.Name = ReceivedContact.Name peer.Name = payload.Name
} }
peer.ContactEncryption = ReceivedContact.EncryptionPublicKey // The initiator's temp key is used for both encrypting the answer and as destination.
peer.ContactLookupKey = ReceivedContact.LookupPublicKey peer.ContactEncryption = payload.PublicKey
peer.ContactPublicKey = ReceivedContact.ContactPublicKey peer.ContactLookupKey = payload.PublicKey
peer.MySymKey = ReceivedContact.SymetricKey peer.InvitationId = payload.Uuid
peer.InvitationId = ReceivedContact.InvitationId peer.InvitationMessage = payload.InvitationMessage
peer.InvitationMessage = ReceivedContact.InvitationMessage peer.MyPullServers = MessageServerUids
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
peer.MyName = MyName 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) id.Peers.StorePeer(&peer)
return &peer, nil return &peer, nil
} }
// Finalizes an invitation, returns nil if successful // InvitationStep3 is called by the initiator after receiving and decrypting the invitee's
func (id *Identity) FinalizeInvitation(ReceivedContact *meowlib.ContactCard) error { // 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 err error
var newsrv *Server peer := id.Peers.GetFromInvitationId(inviteeContact.InvitationId)
/*for i, p := range id.Peers { if peer == nil {
if p.InvitationId == ReceivedContact.InvitationId { return nil, nil, errors.New("no pending peer found for invitation id " + inviteeContact.InvitationId)
//id.Peers[i].Name = ReceivedContact.Name }
id.Peers[i].ContactEncryption = ReceivedContact.EncryptionPublicKey
id.Peers[i].ContactLookupKey = ReceivedContact.LookupPublicKey // Generate full keypairs now that the invitee's identity is known.
id.Peers[i].ContactPublicKey = ReceivedContact.ContactPublicKey peer.MyIdentity, err = meowlib.NewKeyPair()
srvs := []string{} if err != nil {
for srv := range ReceivedContact.PullServers { return nil, nil, err
srvs = append(srvs, ReceivedContact.PullServers[srv].GetUid()) }
} peer.MyEncryptionKp, err = meowlib.NewKeyPair()
id.Peers[i].ContactPullServers = srvs if err != nil {
return 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)*/ // Drop the temporary invitation keypair — no longer needed.
for srv := range ReceivedContact.PullServers { peer.InvitationKp = nil
newsrv, err = CreateServerFromUid(ReceivedContact.PullServers[srv].GetUid())
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 { if err != nil {
return err return err
} }
id.MessageServers.StoreServerIfNotExists(newsrv) 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 // LoadIdentity loads an identity from an encrypted file
@@ -386,9 +391,18 @@ func (id *Identity) GetRequestJobs() []RequestsJob {
return nil return nil
} }
for _, peer := range peers { for _, peer := range peers {
// check if peer inviation is accepted
for _, server := range peer.MyPullServers { 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 // add hidden peers
+4 -6
View File
@@ -142,14 +142,12 @@ func TestGetRequestJobs(t *testing.T) {
// Call GetRequestJobs // Call GetRequestJobs
jobs := id.GetRequestJobs() jobs := id.GetRequestJobs()
// Check that the returned list is as expected // All 10 test peers use server1 and server2, so exactly 2 jobs are expected.
assert.Equal(t, 6, len(jobs), "Expected 6 jobs") assert.Equal(t, 2, len(jobs), "Expected 2 jobs (server1 and server2)")
// Check that each job has the correct server and lookup keys
for _, job := range jobs { for _, job := range jobs {
//fmt.Println(job.Server.GetUid(), job.LookupKeys) assert.Contains(t, []string{"server1", "server2"}, job.Server.GetUid(), "Unexpected server UID")
assert.Contains(t, []string{"server1", "server2", "server3", "server4", "server5", "server6"}, job.Server.GetUid(), "Unexpected server UID") assert.Len(t, job.LookupKeys, 10, "Expected 10 lookup keys (one per test peer) per job")
assert.Len(t, job.LookupKeys, 1, "Expected 1 lookup key per job")
} }
// Clean up // Clean up
+44
View File
@@ -0,0 +1,44 @@
-----BEGIN PGP MESSAGE-----
Comment: https://gopenpgp.org
Version: GopenPGP 2.8.3
wy4ECQMIgUuEGbIAQdTg1Y0LVbCcIFEHJ3MkTGXl7hjJ6KuaEkdm83kI3ID/mesB
0uoB/RojNQvrAnW+1W4xFutE/1S0gG9ejWYhCWiI7sxDmLoNnB1H3Rld2N7dEYnf
sD4baoJC3dOhfbjCUqwtA1aMEmsvJI0VsxEWAj6Uq16iTNmL7HcIaH8aDL7EA8UZ
RTC0bQGdvkf+azASRM6uB29Cm7aIviVyt5MfF/BDoauefibHrP4Z0sYH5P0KJC2i
AqnObuyiqeYNp9yUzVtZywSjjt2C72DkuQIwgPf0FNE3zduxOZ2Ds80tS2Zyobxx
6e+9KUaadUEkcdv/AOOqvQOtRYSVlF5o6gWRF+A16NuwalWAnHJ41k9Y3SSIQLiz
Ppbkw77hrHYIXqopCyxnls2FJaO4QDDjd4JGEdejpxIKognZlgJIIK03khFjUc8/
ilM3Hgbjs6dudJ76lHT8BKaiJPfJPNPL1wf45kLhFc383OdWGJ30NB/w6TbeQKvw
fNNyI/ksfsGbssFm6Zlc0xCpnkEjW9Q9aeHqn34n2jLiDyugwigYhYFKMD8gsQVw
0CRcde7A13/FTa83X9sZ1/rm05FN9M24bIhvG3+8YE4B6nIX43LvYkq18tpGbRLD
uZ33c3bHjbE4PvSf0AdXaML0vGZzxMhBHpgSvPMKt1YiBVr9Kx05txuEAAQ8xaax
KLhhTzVUF7jo4qVeMzvgne6As02yQBdMRYSk92uKm49IWSRzaprP8bx+HktaXJCy
tG/98FXa+05BlTceL4BPaNWrYJlYi4Vpcd3jBm6DAT30gTprJPizUVcGfTkBXII9
sHXLYvca72ItcCzIozOJIdB+y4pV/ZWH8DQdAeZEOfaNUpYbNs9DufxuOhbgx5xQ
JvCKBHAz6fo5O/vkJ1AatihNQ8I8R+7iJ3q4xXxKuDhv+9+V2KG1kG6L1RLKfzpy
GZ6pnmEKbLSa0SO048g6LBhDJyk9I955LHps3HIGoFtE9Oq/2T3fBuZjJgQW0kKj
9ddK3sDOo0/U0Ojz5tfPTkIZvYiEmDoJdfj/jBtTc4F16pf9r4chhzKnkxw9JzfR
Ntj9KThmWOmKHNNlHlwSerxBfNmRjKjfrJ4l1nJPQRDbynTPLzCR59uKVFj5e2t4
F6pGVBrwARQ/kX0QqyqOB6UaE2ulV2EYwnNljegOd1NoDf5kr59K5IBZNx2PvEZe
dM+7jPIojk7pbM6sCCneVXvMG5nzG82boevlc8HJnGEP/9dJ9uWHHu+LFXf71EIQ
npcVOrw8JXTLYhiI9ssH0Tr0C2otkAMkr3DNXcfC5BxLQ+0Ayw0Wr+MNnUbP40Dq
vLhI5YjFdFF/X0QUeVQ9srGk/JWTTPOR1liIGYbzouGQjzzmJOBLtEPoGAdjXbhg
QXZDkpWMTh6qwbWroyQw06Ywwiex0NkTZ+I2UDdby7Dk1V33KmL6EKYm07I3eorn
QRyL/Qs8DpYlwjw1yvbsbj2EIF9UakNLUfFg+VAd6gsgSG2500e6+5Eyjvs8Htpa
wdxqyKgjURK7BkDYSdC6z/eNU7AhkdhYEo0PIOf0loXu2boKKtau7oSWfrJKep9Y
qlpKOzvgxGUx3dRNGmJKAOOLhyHVjBfl5dalzVMikpt3AXhy+an4ogiY6AZgg+gH
bSOJ73h5V/w0xCtD/Lrc4vSDlx1+93B/4m1wXItkBXSi1C2ivjDcPY2d5gd4EfCE
JaHak6zI+P//9zoXJLycJnl/tw0Guw5oJBrhn9ReINNV/CO1pur1H19zBEwuV9c6
u+vx9gcwN6EJEh5nDIOXXU/NoNsMpXERwzohob1plWpYUgB7cLyW4sNsHSSdWrOH
ipAatW+uyPJXQd0YuMm6FLB/DfkNl1BAI3QhmAyGLBxma4KesxcjDImuiGNFvWvZ
M7D3vz4ziOzauanZ/HNDYRa/ey9XJ0iLyLIDsZ0ZrK0T1E2z7PdY4y5JWUGu3a2c
C71RBuTfAmXIAGn/jaF9jfx7dezW91VO0PZ9fKcU7x5khA4Z9gK3oCD2RhXOkIje
bgtYGyWnaz0qcV1JUmRSo1Zwb84NVr5jCc5n743D7+fjedGMZtLQAGCUFttgO/9u
KZbI3UUVcTREZvUKEAyWN/EhixL3Uf7Uv4M12v3RRTydxFPhUUNPbX0+kL9flTaF
Fph4UBuGguu5VygBq0p3YUVYdlS9L8U5WD9DGL4tKW+WJb02jAnsRyWQQcc7PDFw
u1jGIDbaCu/JQco95wpDx0rUGtC1NOVIJFSqPcNf+NHRQaLNks6zzUa67qbJgS5p
nvrfSEVBd7AoSGP1gAuL0qzDHR0x06Fxe9uREHg1R7eojRyAHHs6ZEuK6CmzbTrr
Ky8vdxcfOBwfzJF/J2VHY8lkIfNULqjQMIYpJcD7bMeH12Q0Y0BV11LsYA==
=C05v
-----END PGP MESSAGE-----
+205
View File
@@ -0,0 +1,205 @@
package client
import (
"os"
"testing"
"forge.redroom.link/yves/meowlib"
"github.com/stretchr/testify/assert"
)
// setupInvitationTest creates two independent identities with separate storage paths.
func setupInvitationTest(t *testing.T) (initiator *Identity, invitee *Identity, cleanup func()) {
t.Helper()
cfg := GetConfig()
cfg.IdentityFile = "inv_test_init.id"
cfg.SetMemPass("testpass")
initiator, err := CreateIdentity("initiator")
if err != nil {
t.Fatal(err)
}
invitee, err = CreateIdentity("invitee")
if err != nil {
t.Fatal(err)
}
// Give each identity a pull server UID.
srvInit, _ := CreateServerFromUrl("http://init.server/meow/")
initiator.MessageServers.StoreServer(srvInit)
srvInvitee, _ := CreateServerFromUrl("http://invitee.server/meow/")
invitee.MessageServers.StoreServer(srvInvitee)
cleanup = func() {
os.Remove("inv_test_init.id")
os.RemoveAll(cfg.StoragePath + "/" + initiator.Uuid)
os.RemoveAll(cfg.StoragePath + "/" + invitee.Uuid)
}
return initiator, invitee, cleanup
}
// TestInvitationStep1 verifies that InvitationStep1 creates a minimal peer with only
// InvitationKp set (no full keypairs yet) and returns a valid InvitationInitPayload.
func TestInvitationStep1(t *testing.T) {
initiator, _, cleanup := setupInvitationTest(t)
defer cleanup()
payload, peer, err := initiator.InvitationStep1("Alice", "Bob", []string{"http://init.server/meow/"}, "Hello Bob!")
assert.NoError(t, err)
assert.NotNil(t, payload)
assert.NotNil(t, peer)
assert.NotEmpty(t, payload.Uuid)
assert.Equal(t, "Alice", payload.Name)
assert.NotEmpty(t, payload.PublicKey)
assert.Equal(t, "Hello Bob!", payload.InvitationMessage)
// Full keypairs must NOT be set yet.
assert.Nil(t, peer.MyIdentity)
assert.Nil(t, peer.MyEncryptionKp)
assert.Nil(t, peer.MyLookupKp)
// Temp keypair must be set.
assert.NotNil(t, peer.InvitationKp)
assert.Equal(t, payload.PublicKey, peer.InvitationKp.Public)
}
// TestInvitationStep1PayloadRoundTrip verifies Compress/Decompress of InvitationInitPayload.
func TestInvitationStep1PayloadRoundTrip(t *testing.T) {
initiator, _, cleanup := setupInvitationTest(t)
defer cleanup()
payload, _, err := initiator.InvitationStep1("Alice", "Bob", nil, "test msg")
assert.NoError(t, err)
compressed, err := payload.Compress()
assert.NoError(t, err)
assert.NotEmpty(t, compressed)
restored, err := meowlib.NewInvitationInitPayloadFromCompressed(compressed)
assert.NoError(t, err)
assert.Equal(t, payload.Uuid, restored.Uuid)
assert.Equal(t, payload.Name, restored.Name)
assert.Equal(t, payload.PublicKey, restored.PublicKey)
assert.Equal(t, payload.InvitationMessage, restored.InvitationMessage)
}
// TestInvitationStep2 verifies that InvitationStep2 creates a peer with full keypairs and
// sets the initiator's temp key as both ContactEncryption and ContactLookupKey.
func TestInvitationStep2(t *testing.T) {
initiator, invitee, cleanup := setupInvitationTest(t)
defer cleanup()
payload, _, err := initiator.InvitationStep1("Alice", "Bob", nil, "Hi")
assert.NoError(t, err)
peer, err := invitee.InvitationStep2("Bob", "Alice", []string{"http://invitee.server/meow/"}, payload)
assert.NoError(t, err)
assert.NotNil(t, peer)
// Full keypairs must be set on invitee's peer.
assert.NotNil(t, peer.MyIdentity)
assert.NotNil(t, peer.MyEncryptionKp)
assert.NotNil(t, peer.MyLookupKp)
// Contact fields must point to initiator's temp key.
assert.Equal(t, payload.PublicKey, peer.ContactEncryption)
assert.Equal(t, payload.PublicKey, peer.ContactLookupKey)
assert.Equal(t, payload.Uuid, peer.InvitationId)
}
// TestInvitationFullFlow exercises the complete 4-step invitation handshake end-to-end,
// verifying that both peers end up with each other's full contact information.
func TestInvitationFullFlow(t *testing.T) {
initiator, invitee, cleanup := setupInvitationTest(t)
defer cleanup()
// STEP_1: initiator creates init payload.
payload, initPeer, err := initiator.InvitationStep1("Alice", "Bob", []string{"http://init.server/meow/"}, "Hello!")
assert.NoError(t, err)
assert.NotNil(t, initPeer.InvitationKp)
assert.Nil(t, initPeer.MyIdentity)
// STEP_2: invitee creates their peer from the payload.
srvCard := &meowlib.ServerCard{Name: "InviteeServer", Url: "http://invitee.server/meow/"}
inviteePeer, err := invitee.InvitationStep2("Bob", "Alice", []string{"http://invitee.server/meow/"}, payload)
assert.NoError(t, err)
inviteeCC := inviteePeer.GetMyContact()
inviteeCC.PullServers = append(inviteeCC.PullServers, srvCard)
// STEP_3: initiator receives invitee's CC, generates full keypairs.
myCC, _, err := initiator.InvitationStep3(inviteeCC)
assert.NoError(t, err)
assert.NotNil(t, myCC)
assert.NotEmpty(t, myCC.ContactPublicKey)
assert.NotEmpty(t, myCC.EncryptionPublicKey)
assert.NotEmpty(t, myCC.LookupPublicKey)
assert.NotEmpty(t, myCC.DrRootKey)
assert.NotEmpty(t, myCC.DrPublicKey)
// After step 3, initiator's peer must have full keypairs and invitee's contact info.
updatedInitPeer := initiator.Peers.GetFromInvitationId(payload.Uuid)
assert.NotNil(t, updatedInitPeer.MyIdentity)
assert.NotNil(t, updatedInitPeer.MyEncryptionKp)
assert.NotNil(t, updatedInitPeer.MyLookupKp)
assert.Equal(t, inviteePeer.MyIdentity.Public, updatedInitPeer.ContactPublicKey)
assert.Equal(t, inviteePeer.MyEncryptionKp.Public, updatedInitPeer.ContactEncryption)
assert.Nil(t, updatedInitPeer.InvitationKp) // temp key must be cleared
// STEP_4: invitee finalizes from initiator's full CC.
srvCardInit := &meowlib.ServerCard{Name: "InitServer", Url: "http://init.server/meow/"}
myCC.PullServers = append(myCC.PullServers, srvCardInit)
err = invitee.InvitationStep4(myCC)
assert.NoError(t, err)
// Both peers must now be fully finalized (ContactPublicKey set → not pending).
finalInitPeer := initiator.Peers.GetFromInvitationId(payload.Uuid)
assert.False(t, finalInitPeer.InvitationPending())
finalInviteePeer := invitee.Peers.GetFromInvitationId(payload.Uuid)
assert.False(t, finalInviteePeer.InvitationPending())
assert.Equal(t, updatedInitPeer.MyIdentity.Public, finalInviteePeer.ContactPublicKey)
assert.Equal(t, updatedInitPeer.MyEncryptionKp.Public, finalInviteePeer.ContactEncryption)
assert.Equal(t, updatedInitPeer.MyLookupKp.Public, finalInviteePeer.ContactLookupKey)
assert.NotEmpty(t, finalInviteePeer.DrRootKey)
}
// TestInvitationStep3NotFound verifies that InvitationStep3 returns an error when no
// pending peer exists for the given invitation ID.
func TestInvitationStep3NotFound(t *testing.T) {
initiator, _, cleanup := setupInvitationTest(t)
defer cleanup()
cc := &meowlib.ContactCard{InvitationId: "nonexistent-uuid", ContactPublicKey: "pub"}
_, _, err := initiator.InvitationStep3(cc)
assert.Error(t, err)
}
// TestGetRequestJobsPendingPeer verifies that pending (step-1 only) peers contribute
// their InvitationKp to GetRequestJobs instead of MyLookupKp.
func TestGetRequestJobsPendingPeer(t *testing.T) {
cfg := GetConfig()
cfg.SetMemPass("testpass")
id, err := CreateIdentity("testjobs")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(cfg.StoragePath + "/" + id.Uuid)
cfg.SetIdentity(id)
id.MessageServers = ServerStorage{DbFile: "testjobs.db"}
defer os.RemoveAll("testjobs.db")
srv, _ := CreateServerFromUrl("http://srv1.test/meow/")
id.MessageServers.StoreServer(srv)
// Create a step-1 pending peer.
_, _, err = id.InvitationStep1("Me", "Friend", []string{"http://srv1.test/meow/"}, "Hi")
assert.NoError(t, err)
jobs := id.GetRequestJobs()
// At least one job should have a lookup key (the InvitationKp).
total := 0
for _, j := range jobs {
total += len(j.LookupKeys)
}
assert.Greater(t, total, 0)
}
+61 -4
View File
@@ -56,8 +56,10 @@ type Peer struct {
DbIds []string `json:"db_ids,omitempty"` DbIds []string `json:"db_ids,omitempty"`
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
PersonnaeDbId string `json:"personnae_db_id,omitempty"` PersonnaeDbId string `json:"personnae_db_id,omitempty"`
// Invitation temporary keypair (step 1 only — discarded after step 3)
InvitationKp *meowlib.KeyPair `json:"invitation_kp,omitempty"`
// Double Ratchet state // Double Ratchet state
DrKpPublic string `json:"dr_kp_public,omitempty"` DrKpPublic string `json:"dr_kp_public,omitempty"`
DrKpPrivate string `json:"dr_kp_private,omitempty"` DrKpPrivate string `json:"dr_kp_private,omitempty"`
DrRootKey string `json:"dr_root_key,omitempty"` DrRootKey string `json:"dr_root_key,omitempty"`
DrInitiator bool `json:"dr_initiator,omitempty"` DrInitiator bool `json:"dr_initiator,omitempty"`
@@ -171,9 +173,28 @@ func (p *Peer) BuildSingleFileMessage(filename string, message []byte) ([]meowli
return msgs, nil return msgs, nil
} }
// Builds an invitation answer user message. // BuildInvitationStep2Message builds the invitee's answer UserMessage (STEP_2_SEND).
// it takes as input a contactcard generated by Identity.AnswerInvitation // The ContactCard is encrypted with the initiator's temp public key via ProcessOutboundUserMessage.
func (p *Peer) BuildInvitationAnswerMessage(myContactCard *meowlib.ContactCard) (*meowlib.UserMessage, error) { func (p *Peer) BuildInvitationStep2Message(myContactCard *meowlib.ContactCard) (*meowlib.UserMessage, error) {
var msg meowlib.UserMessage
var invitation meowlib.Invitation
invitation.Step = 2
out, err := proto.Marshal(myContactCard)
if err != nil {
return nil, err
}
invitation.Uuid = p.InvitationId
invitation.Payload = out
msg.Destination = p.ContactLookupKey
msg.Invitation = &invitation
msg.From = p.MyIdentity.Public
msg.Type = "1"
return &msg, nil
}
// BuildInvitationStep3Message builds the initiator's full ContactCard UserMessage (STEP_3_SEND).
// Sent through the invitee's servers after the initiator has finalized their keypairs.
func (p *Peer) BuildInvitationStep3Message(myContactCard *meowlib.ContactCard) (*meowlib.UserMessage, error) {
var msg meowlib.UserMessage var msg meowlib.UserMessage
var invitation meowlib.Invitation var invitation meowlib.Invitation
invitation.Step = 3 invitation.Step = 3
@@ -190,6 +211,42 @@ func (p *Peer) BuildInvitationAnswerMessage(myContactCard *meowlib.ContactCard)
return &msg, nil return &msg, nil
} }
// BuildInvitationStep4Message builds the invitee's confirmation UserMessage (STEP_4).
// Sent through the initiator's servers to signal the invitation is complete.
func (p *Peer) BuildInvitationStep4Message() (*meowlib.UserMessage, error) {
var msg meowlib.UserMessage
var invitation meowlib.Invitation
invitation.Step = 4
invitation.Uuid = p.InvitationId
msg.Destination = p.ContactLookupKey
msg.Invitation = &invitation
msg.From = p.MyIdentity.Public
msg.Type = "1"
return &msg, nil
}
// ProcessInboundStep2UserMessage decrypts the invitee's step-2 answer using the
// initiator's temporary InvitationKp private key. inviteePublicKey is the sender's
// identity public key (carried in Invitation.From by the server).
func (p *Peer) ProcessInboundStep2UserMessage(packed *meowlib.PackedUserMessage, inviteePublicKey string) (*meowlib.UserMessage, error) {
dec, err := meowlib.AsymDecryptAndCheck(p.InvitationKp.Private, inviteePublicKey, packed.Payload, packed.Signature)
if err != nil {
return nil, err
}
return p.DeserializeUserMessage(dec)
}
// ProcessInboundStep3UserMessage decrypts the initiator's step-3 full ContactCard using
// the invitee's MyEncryptionKp. Signature verification is skipped because the
// initiator's identity key is not yet known — it is extracted from the decrypted payload.
func (p *Peer) ProcessInboundStep3UserMessage(packed *meowlib.PackedUserMessage) (*meowlib.UserMessage, error) {
dec, err := meowlib.AsymDecrypt(p.MyEncryptionKp.Private, packed.Payload)
if err != nil {
return nil, err
}
return p.DeserializeUserMessage(dec)
}
// //
// Messages encryption and packaging // Messages encryption and packaging
// //
+39 -3
View File
@@ -228,7 +228,7 @@ func TestBuildSingleFileMessage_EmptyFile(t *testing.T) {
// BuildInvitationAnswerMessage // BuildInvitationAnswerMessage
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
func TestBuildInvitationAnswerMessage(t *testing.T) { func TestBuildInvitationStep2Message(t *testing.T) {
p := &Peer{ p := &Peer{
ContactLookupKey: "dest-lookup", ContactLookupKey: "dest-lookup",
MyIdentity: &meowlib.KeyPair{Public: "my-pub"}, MyIdentity: &meowlib.KeyPair{Public: "my-pub"},
@@ -239,13 +239,13 @@ func TestBuildInvitationAnswerMessage(t *testing.T) {
ContactPublicKey: "alice-pub", ContactPublicKey: "alice-pub",
} }
msg, err := p.BuildInvitationAnswerMessage(contactCard) msg, err := p.BuildInvitationStep2Message(contactCard)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "dest-lookup", msg.Destination) assert.Equal(t, "dest-lookup", msg.Destination)
assert.Equal(t, "my-pub", msg.From) assert.Equal(t, "my-pub", msg.From)
assert.Equal(t, "1", msg.Type) assert.Equal(t, "1", msg.Type)
assert.NotNil(t, msg.Invitation) assert.NotNil(t, msg.Invitation)
assert.Equal(t, int32(3), msg.Invitation.Step) assert.Equal(t, int32(2), msg.Invitation.Step)
assert.Equal(t, "inv-uuid-123", msg.Invitation.Uuid) assert.Equal(t, "inv-uuid-123", msg.Invitation.Uuid)
// Payload is the proto-serialized contact card // Payload is the proto-serialized contact card
@@ -256,6 +256,42 @@ func TestBuildInvitationAnswerMessage(t *testing.T) {
assert.Equal(t, "alice-pub", decoded.ContactPublicKey) assert.Equal(t, "alice-pub", decoded.ContactPublicKey)
} }
func TestBuildInvitationStep3Message(t *testing.T) {
p := &Peer{
ContactLookupKey: "dest-lookup",
MyIdentity: &meowlib.KeyPair{Public: "my-pub"},
InvitationId: "inv-uuid-456",
}
contactCard := &meowlib.ContactCard{
Name: "Initiator",
ContactPublicKey: "init-pub",
}
msg, err := p.BuildInvitationStep3Message(contactCard)
assert.NoError(t, err)
assert.Equal(t, int32(3), msg.Invitation.Step)
assert.Equal(t, "inv-uuid-456", msg.Invitation.Uuid)
var decoded meowlib.ContactCard
err = proto.Unmarshal(msg.Invitation.Payload, &decoded)
assert.NoError(t, err)
assert.Equal(t, "Initiator", decoded.Name)
}
func TestBuildInvitationStep4Message(t *testing.T) {
p := &Peer{
ContactLookupKey: "dest-lookup",
MyIdentity: &meowlib.KeyPair{Public: "my-pub"},
InvitationId: "inv-uuid-789",
}
msg, err := p.BuildInvitationStep4Message()
assert.NoError(t, err)
assert.Equal(t, int32(4), msg.Invitation.Step)
assert.Equal(t, "inv-uuid-789", msg.Invitation.Uuid)
assert.Nil(t, msg.Invitation.Payload)
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Serialize / Deserialize // Serialize / Deserialize
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
+4 -4
View File
@@ -199,12 +199,12 @@ func (ints *Server) BuildVideoRoomRequestMessage(users []string, expiry uint64)
return &msg, nil return &msg, nil
} }
// BuildToServerMessageInvitation creates an invitation message to server and returns it as a meowlib.ToServerMessage // BuildToServerMessageInvitationStep1 sends the InvitationInitPayload to the server (STEP_1).
// it takes as input a contactcard generated by Identity.InvitePeer // The server stores it and returns a shortcode URL.
func (ints *Server) BuildToServerMessageInvitationCreation(invitation *meowlib.ContactCard, password string, timeout int, shortCodeLen int) (*meowlib.ToServerMessage, error) { func (ints *Server) BuildToServerMessageInvitationStep1(initPayload *meowlib.InvitationInitPayload, password string, timeout int, shortCodeLen int) (*meowlib.ToServerMessage, error) {
var msg meowlib.ToServerMessage var msg meowlib.ToServerMessage
var inv meowlib.Invitation var inv meowlib.Invitation
payload, err := invitation.Compress() payload, err := initPayload.Compress()
if err != nil { if err != nil {
return nil, err return nil, err
} }
+14 -11
View File
@@ -454,16 +454,18 @@ func TestServer_BuildVideoRoomRequestMessage_SingleUser(t *testing.T) {
// BuildToServerMessageInvitationCreation // BuildToServerMessageInvitationCreation
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
func TestServer_BuildToServerMessageInvitationCreation(t *testing.T) { func TestServer_BuildToServerMessageInvitationStep1(t *testing.T) {
srv, err := CreateServerFromUrl("https://example.com/meow") srv, err := CreateServerFromUrl("https://example.com/meow")
assert.NoError(t, err) assert.NoError(t, err)
cc := &meowlib.ContactCard{ initPayload := &meowlib.InvitationInitPayload{
Name: "Alice", Uuid: "test-uuid",
ContactPublicKey: "alice-pub", Name: "Alice",
PublicKey: "alice-temp-pub",
InvitationMessage: "Hello!",
} }
msg, err := srv.BuildToServerMessageInvitationCreation(cc, "secret", 300, 8) msg, err := srv.BuildToServerMessageInvitationStep1(initPayload, "secret", 300, 8)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "1", msg.Type) assert.Equal(t, "1", msg.Type)
assert.Equal(t, srv.UserKp.Public, msg.From) assert.Equal(t, srv.UserKp.Public, msg.From)
@@ -474,18 +476,19 @@ func TestServer_BuildToServerMessageInvitationCreation(t *testing.T) {
assert.Equal(t, int32(8), msg.Invitation.ShortcodeLen) assert.Equal(t, int32(8), msg.Invitation.ShortcodeLen)
assert.NotEmpty(t, msg.Invitation.Payload) assert.NotEmpty(t, msg.Invitation.Payload)
// Payload is a compressed ContactCard — decompress and verify // Payload is a compressed InvitationInitPayload — decompress and verify
restored, err := meowlib.NewContactCardFromCompressed(msg.Invitation.Payload) restored, err := meowlib.NewInvitationInitPayloadFromCompressed(msg.Invitation.Payload)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "Alice", restored.Name) assert.Equal(t, "Alice", restored.Name)
assert.Equal(t, "alice-pub", restored.ContactPublicKey) assert.Equal(t, "alice-temp-pub", restored.PublicKey)
assert.Equal(t, "test-uuid", restored.Uuid)
} }
func TestServer_BuildToServerMessageInvitationCreation_NoPassword(t *testing.T) { func TestServer_BuildToServerMessageInvitationStep1_NoPassword(t *testing.T) {
srv, _ := CreateServerFromUrl("https://example.com/meow") srv, _ := CreateServerFromUrl("https://example.com/meow")
cc := &meowlib.ContactCard{Name: "Bob"} initPayload := &meowlib.InvitationInitPayload{Name: "Bob", Uuid: "bob-uuid", PublicKey: "bob-pub"}
msg, err := srv.BuildToServerMessageInvitationCreation(cc, "", 60, 6) msg, err := srv.BuildToServerMessageInvitationStep1(initPayload, "", 60, 6)
assert.NoError(t, err) assert.NoError(t, err)
assert.Empty(t, msg.Invitation.Password) assert.Empty(t, msg.Invitation.Password)
assert.Equal(t, int32(1), msg.Invitation.Step) assert.Equal(t, int32(1), msg.Invitation.Step)
+44
View File
@@ -0,0 +1,44 @@
-----BEGIN PGP MESSAGE-----
Comment: https://gopenpgp.org
Version: GopenPGP 2.8.3
wy4ECQMIlftc5WyUrBjgI1MbXSAWh3ZqBpILi+RN79+v4HuvB/xmqoEJtZVeypwh
0uoBc2FevnicfVu4wOUlglRjhPWLcE25+gQxlKB7RzX6cQND3+Nw3qiexvK+psrm
mW7nOIHE/9EVXzAlRrCgMlPcZpPB+5q5X9t01BQ/tTV6OytcLS3J6byrMmefA7jG
ki/U9oSkdwFYPosG5PKhiHCe03AIjY++s/Wgn1OMtsLWX/8/dJ6CNkzvwnX4CVti
x8KGj7IwJefG7BGApU3eg9OcqRz8KubWI1mWfiC2uVOoFgVlnAOjP8qzUFs65LK9
cBglhUNuG/Jc2ojCa9ndWYIaDJ2pzGpvhlGsj7kU0Fyh3AMTTzrJeRwAoqcLv8P5
B6ERBv0rG16arkhpC4v6BFT3UekMzBMhpGSb8PPu3BmDayHmWG+Q3Lt7ufnm/UId
naLVfnQKD6An05KkqZNqHjPsbHPg8gFcV3N87LCtCMYGGDgxbsKBDh/ig0FQwnnq
P5Hj4VZTUcuJ25BSV/Tbbo8Z9XGKQ02OnX7h7qies+oVAan9Pq3YgjoqFB06wDTq
hBxrSMgexfB2Dj23pioC72Ege22n1I6PBwuM5p6Ja0btZQrfhL/yY/y102MvgUXh
Qh84zxtTKKR8b3sL3WeEckOPBcEOvbmLf+sTjWdIIcQMB0IGhDhzCvf0sGtk48eJ
rKNruG7RMHGjBZkZnpJVArJchxmRZkuGLjwsQTRbdRPQc6vMmvPhqCuFPMhnTaL9
nss0tnzQ2DdLOwO8JsQH41IoRi0STl6ndDT4wbGlmuh57xqMdrNjkur84zsi6G76
wQOtGQ7A+9xCz/cnAaTPlmUUe+0Fg2vHQbGPfZy3TfERAkGYg9EsQbww/nNSOQua
e+DbLNbBPp5egkfR6TDDbiTgwWXn6R673qLQ27MpHBY2eQ8IaJqz/jdm6/UPbuh3
bpBF0G7HVwxfhDAPBKPObJM8doHB67d5hoxcqfINexVXsX5Dd3OzCY1mUKgn95kF
Tzl4VGu4kIxcFRXMR49XaHC4/CQbv70c/2NiJf739fxcLkGUQ5wXA44uMKwEbzwW
x53fhFKKjGC/AWubs9jnVVJz7EfiFX9VvhEYvXp3++emM9Nbv6BaRobq9JIKmdMl
E69BcHrqZ7ahMDTENSpVZTlohs4AnaxeZesCPq7t75STAx2/jj3YtgfeYarE3d9I
rn8VofS5uI41VNO4noQtj8a18YzNW5V+aGLjD2ZxvxMYfp8NfsJpEuWpXRNE5yZq
AzeXlGlcMHc/n6+vgdTirSTbrwY2chBgxwWAdpcezimAl6VpT4gZ1pmtDxtQA5v0
yC6LRujp+p9yPfrVEB/tuduo3DpnBJjkAcBlDtGuSew98QoIDKI/UcMUqGZW+n4U
/QugOpd9aY7UhIFiWHZ14PnZwiUhdxZTEE4wo8TVVFRmP4L6oxLBjOByLPOH4ct+
eNrL5cXABE0rwm3/Ywxuxy3hV07tazm+GpxdUjX4+cjBJZCwYO/JyT0OI2sPsKIY
6WO2zkobs8fn0j3ba1ovRWGmAU0MnGCg1ZnJOiXtUn17QXoe3CnjvQu9wS15ms2F
htQtIZwnosXuHcXUzNNtv4SFdZAFsy8tj4TYtQ3qtxYKjxyLlmPZ9yT0DD2VDcFL
ra7II59iElBCyC0JS/q1JQxdgVPhD0ZU+x9F/koquS+35gtqjemVmeLb9W+nEWc0
3H4W0i0k0wkSwWX4FUmGbqHczOCoVoTuKkp+ypAfzZ8L/nHybz4eK7RdGKfWeYbG
N3zlTLaTTd2D7D1s5+df0itoM/VS0pSHPHMkNCJ/CmC8gwlIENU4cRqvvBXF2dEA
Far8qCMJLscaoKvbQVQwhqzq9nEyra5CscJzD7nq3aiS5gwOfzy6G1qvk4KFxcaX
PLBEAegTueaMj7KvTwDd+Yz7lnbk2fmNo4lJlGkUJMyEDLCjYg0sqLokOO7MMYyC
V69bnJCoQPwfaE0vETiZn6TFGXG0oQg4ki87lhNzzXlT8JiTK4RMWWGtw8QBHmsv
PWVBMuooqrPXpBEty7O7+Cxef/P0My8CxwgMOEPA2dAtWrvXrOM3wHCWoLK4FJlS
XxHNHPwyZ49vCuEWhUJArge1oXWwZUTCpGEJLd0taUI+T9GU+5VG/VrbHprBdod4
FjRAXxpO4Sx/Z7L/vccFjOjHeobNMKGmC4BDDmUSECCszWqT37/XFbGJrHdYqnht
yzdRDeI11rEIpNyF65PgJR6A5hEnZk0IsSqiTvPcIodUlPkhlSVPoc+NSrYATuJa
VviYI8AhTUxrAcZyG/unEKKQfCBB8XBn8gUTkodxOaI27GVJ/T4WgGERsPNQm/Fl
HCbvaphsM7nszn8iuoRv5PWiWiZsetl+HvXVKWUUb4jxq6xgpIpsBJw=
=BI6k
-----END PGP MESSAGE-----
+11 -4
View File
@@ -1,6 +1,13 @@
@startuml General Invitation Steps @startuml General Invitation Steps
InitiatingUser -> InvitedUser: STEP_1=InitiatingUser_TmpId generate a public key, invitation uid & message for InvitedUser optionnally password protected InitiatingUser -> InitiatingUser : STEP_1 = Create InivitedUser_Id generate a public key, invitation uid & message for InvitedUser optionnally password protected
InvitedUser -> InitiatingUser: STEP_2=InvitedUser_Id Create invitation for alice (Generate InvitedUser ContactCard and create InitiatingUser pending contact) InitiatingUser -> InvitedUser: STEP_1_SEND= transmit step 1 data (QR Code, Bluetooth, messaging, mail, ...) optional password being tranmitted through another channel
InitiatingUser -> InvitedUser: STEP_3=InitiatingUser_Id Accept Invitation and create answer (Generate InitiatingUser ContactCard and create finalized InvitedUser contact)
InvitedUser -> InitiatingUser: STEP_4=InvitedUser_OK Review Answer, invitation finalize (Finalize InitiatingUser contact and notify InitiatingUser that communication is possible) InvitedUser -> InvitedUser :Create InitatingUser_Id & InvitedUser ContactCard
InvitedUser -> InitiatingUser: STEP_2_SEND=transmit InvitedUser ContactCard (QR Codes, Bluetooth, messaging, mail, ...) encrypted with initiating user pub key
InitiatingUser -> InitiatingUser : STEP_3=InitiatingUser_Id Accept Invitation and create answer (Generate InitiatingUser ContactCard and create finalized InvitedUser contact)
InitiatingUser -> InvitedUser: STEP_3_SEND=Send answer through invited user's message servers from contact card
InvitedUser -> InvitedUser : Finalize InitiatingUser from its ContactCard
InvitedUser -> InitiatingUser: STEP_4= Send confirmation to InitiatingUser that communication is possible through initiating user's message servers from contact card
@enduml @enduml
-9
View File
@@ -1,9 +0,0 @@
@startuml Detailled Invitation Steps
InitiatingUser -> MeowInitiatingUser: STEP 1 generate a public key & message for InvitedUser optionnally password protected
InitiatingUser -> InvitedUser: send public key
InvitedUser -> MeowInvitedUser: STEP 2 Create invitation for alice (Generate InvitedUser ContactCard and create InitiatingUser pending contact)
InvitedUser -> InitiatingUser: Send invitation (InvitedUser ContactCard encrypted with InitiatingUser public key)
InitiatingUser -> MeowInitiatingUser: STEP 3 Accept Invitation and create answer (Generate InitiatingUser ContactCard and create finalized InvitedUser contact)
InitiatingUser -> InvitedUser: Send answer (InitiatingUser ContactCard)
InvitedUser -> MeowInvitedUser: STEP 4 Review Answer, invitation finalize (Finalize InitiatingUser contact and notify InitiatingUser that communication is possible)
@enduml
+2 -1
View File
@@ -2,7 +2,7 @@
InitiatingUser -> Bastet : contact name InitiatingUser -> Bastet : contact name
InitiatingUser -> Bastet : invitationMessage InitiatingUser -> Bastet : invitationMessage
InitiatingUser -> Bastet : select invitation server InitiatingUser -> Bastet : select invitation server
InitiatingUser -> Bastet : optional password InitiatingUser -> Bastet : optional passwords ([payload], [url])
Bastet -> NativeLib : send invitation Bastet -> NativeLib : send invitation
NativeLib -> NativeLib : create contact and invtation KP NativeLib -> NativeLib : create contact and invtation KP
NativeLib -> Server : send invitation NativeLib -> Server : send invitation
@@ -12,4 +12,5 @@ Server -> NativeLib : invitation URL
NativeLib -> Bastet : invitation URL NativeLib -> Bastet : invitation URL
Bastet -> InitiatingUser : invitation URL Bastet -> InitiatingUser : invitation URL
InitiatingUser -> InvitedUser : invitation URL InitiatingUser -> InvitedUser : invitation URL
InitiatingUser -> InvitedUser : [invitation passwords] through another channel
@enduml @enduml
+34 -33
View File
@@ -32,58 +32,59 @@ func TestEndToEnd(t *testing.T) {
srv = client.Server{Name: "MyServer", Url: "meow://127.0.0.1"} srv = client.Server{Name: "MyServer", Url: "meow://127.0.0.1"}
Me.MessageServers.StoreServer(&srv) Me.MessageServers.StoreServer(&srv)
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Create an invitation for a friend, I want him/her to know me as Bender // // STEP_1: Create an invitation — only a temp keypair, no full ContactCard //
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
fmt.Println("Creating an invitation for the first friend...") fmt.Println("Creating an invitation for the first friend...")
peer, err := Me.InvitePeer("Bender", "myfirstfriend", []string{"http://127.0.0.1/meow/", "mqtt://127.0.0.1"}, "welcome, it's me!") initPayload, peer, err := Me.InvitationStep1("Bender", "myfirstfriend", []string{"http://127.0.0.1/meow/", "mqtt://127.0.0.1"}, "welcome, it's me!")
if err != nil { if err != nil {
println(err) println(err)
} }
println(peer.Name) println(peer.Name)
// print my invitation a, _ := json.Marshal(initPayload)
a, _ := json.Marshal(peer.GetMyContact()) fmt.Println("InvitationInitPayload:", string(a))
fmt.Println(string(a)) data, err := initPayload.Compress()
// TODO : Convert invitation to QR Code
peer.GetMyContact().WritePng("invitation.png")
data, err := peer.GetMyContact().Compress()
if err != nil { if err != nil {
println(err) println(err)
} }
peer.GetMyContact().WriteQr("qrcode.png") initPayload.WriteQr("qrcode.png")
println("Compressed contact card :", len(data)) println("Compressed init payload :", len(data))
///////////////////////////////////////
// Simulate peer invitation response //
///////////////////////////////////////
fmt.Println("Simulating first friend answer...")
var ReceivedContact meowlib.ContactCard
// Friend simulated invitation ///////////////////////////////////////////////////////
FirstFriendContactKp, err := meowlib.NewKeyPair() // STEP_2: Simulate friend receiving the payload and answering //
///////////////////////////////////////////////////////
fmt.Println("Simulating first friend answer (STEP_2)...")
friendMe, err := client.CreateIdentity("friendname")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
FirstFriendEncryptionKp, err := meowlib.NewKeyPair() friendPeer, err := friendMe.InvitationStep2("FriendNick", "Bender", []string{}, initPayload)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
FirstFriendLookupKp, err := meowlib.NewKeyPair() friendCC := friendPeer.GetMyContact()
if err != nil {
t.Fatal(err)
}
ReceivedContact.Name = "I'm the friend"
ReceivedContact.ContactPublicKey = FirstFriendContactKp.Public
ReceivedContact.EncryptionPublicKey = FirstFriendEncryptionKp.Public
ReceivedContact.LookupPublicKey = FirstFriendLookupKp.Public
ReceivedContact.InvitationId = peer.GetMyContact().InvitationId
FriendServer1KP, err := meowlib.NewKeyPair() FriendServer1KP, err := meowlib.NewKeyPair()
if err != nil {
t.Fatal(err)
}
FriendServer1 := meowlib.ServerCard{Name: "FriendServer1", Url: "http://myfriend.org/meow/", PublicKey: FriendServer1KP.Public, Description: "Fancy description"} FriendServer1 := meowlib.ServerCard{Name: "FriendServer1", Url: "http://myfriend.org/meow/", PublicKey: FriendServer1KP.Public, Description: "Fancy description"}
ReceivedContact.PullServers = append(ReceivedContact.PullServers, &FriendServer1) friendCC.PullServers = append(friendCC.PullServers, &FriendServer1)
/////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// Finalize the contact with the invitation response // // STEP_3: Initiator receives friend's CC, generates full keypairs //
/////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
Me.FinalizeInvitation(&ReceivedContact) myCC, _, err := Me.InvitationStep3(friendCC)
if err != nil {
t.Fatal(err)
}
fmt.Println("Initiator ContactCard ready:", myCC.ContactPublicKey != "")
////////////////////////////////////////////////////
// STEP_4: Friend finalizes initiator's ContactCard //
////////////////////////////////////////////////////
err = friendMe.InvitationStep4(myCC)
if err != nil {
t.Fatal(err)
}
err = Me.Save() err = Me.Save()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
+31
View File
@@ -0,0 +1,31 @@
# Context
The invitation process might be performed by file exchange (raw or maybe qr codes later) or though server.
In the current code the first step provides first peer data without any encryption (invitation create), this has to be changed.
# Requested improvement
## Library implementation
An initial step shall be added befoe the current first step where the initiator will send almost only it's public key for initiating invitation. The required structure InvitationInitPayload is described in @pb/messages.proto. Invitation struct in the same file has also been adapted to the new flow.
Then the full workflow is described in @doc/invitation/sq_invitation.puml
this will allow to adapt the base invitation functions attached to the @client/identity.go that allow the invitation steps to be performed.
Then the helper functions @client/helpers/invitation*.go allow to implement the full flow, through files exchanges or through server invitation.
The "through server" flow is described in @doc/invitation/sq_srvinv*.puml
## Server implementation
Most of the server code is in @server/router.go invitation process consistency with that code should be checked/upgraded
## Cli client implementation
The cli client is available in @../meowcli/ it should also be adapted to the new process
# Constraints
The functions should be renamed according to the sequence diagrams flow stps to improve clarity, instead od create/answer/finalize...
# Testing
Already present test files should be adapted and improved to fit the changes, new test files may be created.
# Stop condition
Once all changed have beed edited, and library unit testing performed, you will stop. I will then review and commit changes, integrate new lib in server and cli, and then we'll iterate over end to end tests.
+80
View File
@@ -0,0 +1,80 @@
package meowlib
import (
"bytes"
"compress/gzip"
"io"
"os"
"github.com/makiuchi-d/gozxing"
"github.com/makiuchi-d/gozxing/qrcode"
"google.golang.org/protobuf/proto"
"image/png"
)
func (p *InvitationInitPayload) Serialize() ([]byte, error) {
return proto.Marshal(p)
}
func (p *InvitationInitPayload) Compress() ([]byte, error) {
out, err := p.Serialize()
if err != nil {
return nil, err
}
var b bytes.Buffer
gz, err := gzip.NewWriterLevel(&b, gzip.BestCompression)
if err != nil {
return nil, err
}
if _, err := gz.Write(out); err != nil {
return nil, err
}
if err := gz.Close(); err != nil {
return nil, err
}
return b.Bytes(), nil
}
func NewInvitationInitPayloadFromCompressed(compressed []byte) (*InvitationInitPayload, error) {
p := &InvitationInitPayload{}
reader := bytes.NewReader(compressed)
gzreader, err := gzip.NewReader(reader)
if err != nil {
return nil, err
}
output, err := io.ReadAll(gzreader)
if err != nil {
return nil, err
}
if err := proto.Unmarshal(output, p); err != nil {
return nil, err
}
return p, nil
}
func (p *InvitationInitPayload) WriteCompressed(filename string) error {
out, err := p.Compress()
if err != nil {
return err
}
return os.WriteFile(filename, out, 0600)
}
func (p *InvitationInitPayload) WriteQr(filename string) error {
data, err := p.Compress()
if err != nil {
return err
}
qwriter := qrcode.NewQRCodeWriter()
code, err := qwriter.Encode(string(data), gozxing.BarcodeFormat_QR_CODE, 512, 512, nil)
if err != nil {
return err
}
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
return png.Encode(file, code)
}
+201 -125
View File
@@ -97,15 +97,15 @@ func (x *PackedServerMessage) GetSignature() []byte {
// structure to hold an invitation through a server // structure to hold an invitation through a server
type Invitation struct { type Invitation struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Payload []byte `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"` // invitation payload, encrypted after step 2 Payload []byte `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"` // invitation payload, optionaly encrypted with payload password(transmitted OOB) on step 1
Timeout int32 `protobuf:"varint,2,opt,name=timeout,proto3" json:"timeout,omitempty"` // how long do I want the invitation to remain available on the server Timeout int32 `protobuf:"varint,2,opt,name=timeout,proto3" json:"timeout,omitempty"` // how long do I want the invitation to remain available on the server
ShortcodeLen int32 `protobuf:"varint,3,opt,name=shortcodeLen,proto3" json:"shortcodeLen,omitempty"` // len of the shortcode you wish for short url transmission ShortcodeLen int32 `protobuf:"varint,3,opt,name=shortcode_len,json=shortcodeLen,proto3" json:"shortcode_len,omitempty"` // len of the shortcode you wish for short url transmission
Shortcode string `protobuf:"bytes,4,opt,name=shortcode,proto3" json:"shortcode,omitempty"` // shortcode that the friend shall request to get the invitation Shortcode string `protobuf:"bytes,4,opt,name=shortcode,proto3" json:"shortcode,omitempty"` // shortcode that the friend shall request to get the invitation
Password string `protobuf:"bytes,5,opt,name=password,proto3" json:"password,omitempty"` // password to set for accessing invitation (optional) Password string `protobuf:"bytes,5,opt,name=password,proto3" json:"password,omitempty"` // optional password(transmitted OOB) to set for accessing invitation (server check)
Uuid string `protobuf:"bytes,6,opt,name=uuid,proto3" json:"uuid,omitempty"` // id that the friend gave you, that you should include to your reply to get recognized Uuid string `protobuf:"bytes,6,opt,name=uuid,proto3" json:"uuid,omitempty"` // invitation uuid
Expiry int64 `protobuf:"varint,7,opt,name=expiry,proto3" json:"expiry,omitempty"` // the server allowed expiry date, it may be samller than the requested timeout according to server policy Expiry int64 `protobuf:"varint,7,opt,name=expiry,proto3" json:"expiry,omitempty"` // the server allowed expiry date, it may be smaller than the requested timeout according to server policy
Step int32 `protobuf:"varint,8,opt,name=step,proto3" json:"step,omitempty"` // progress in the inviattion process : 1=invite friend, 2=friend requests invitation, 3=friend's answer Step int32 `protobuf:"varint,8,opt,name=step,proto3" json:"step,omitempty"` // progress in the invitation process : 1=initiator pub key, 2=invited data enc with pub key, 3=initator data full encrypted, 4=invited All OK !
From string `protobuf:"bytes,9,opt,name=from,proto3" json:"from,omitempty"` // used in step 3 the answer public key to check the signature in user message From string `protobuf:"bytes,9,opt,name=from,proto3" json:"from,omitempty"` // still useful ?
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@@ -203,6 +203,75 @@ func (x *Invitation) GetFrom() string {
return "" return ""
} }
// This payload migh be used for file serialization as well as Invitation/payload in case of through server invitation
type InvitationInitPayload struct {
state protoimpl.MessageState `protogen:"open.v1"`
Uuid string `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` // uuid of the invitation, it is set here on init cause the payload might be encrypted
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // name of the initiator
PublicKey string `protobuf:"bytes,3,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` // public key to be used for step 2 encryption
InvitationMessage string `protobuf:"bytes,4,opt,name=invitation_message,json=invitationMessage,proto3" json:"invitation_message,omitempty"` // message for the invited peer
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *InvitationInitPayload) Reset() {
*x = InvitationInitPayload{}
mi := &file_messages_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *InvitationInitPayload) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*InvitationInitPayload) ProtoMessage() {}
func (x *InvitationInitPayload) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use InvitationInitPayload.ProtoReflect.Descriptor instead.
func (*InvitationInitPayload) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{2}
}
func (x *InvitationInitPayload) GetUuid() string {
if x != nil {
return x.Uuid
}
return ""
}
func (x *InvitationInitPayload) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *InvitationInitPayload) GetPublicKey() string {
if x != nil {
return x.PublicKey
}
return ""
}
func (x *InvitationInitPayload) GetInvitationMessage() string {
if x != nil {
return x.InvitationMessage
}
return ""
}
// structure for requesting incoming messages // structure for requesting incoming messages
type ConversationRequest struct { type ConversationRequest struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
@@ -216,7 +285,7 @@ type ConversationRequest struct {
func (x *ConversationRequest) Reset() { func (x *ConversationRequest) Reset() {
*x = ConversationRequest{} *x = ConversationRequest{}
mi := &file_messages_proto_msgTypes[2] mi := &file_messages_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -228,7 +297,7 @@ func (x *ConversationRequest) String() string {
func (*ConversationRequest) ProtoMessage() {} func (*ConversationRequest) ProtoMessage() {}
func (x *ConversationRequest) ProtoReflect() protoreflect.Message { func (x *ConversationRequest) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[2] mi := &file_messages_proto_msgTypes[3]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -241,7 +310,7 @@ func (x *ConversationRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use ConversationRequest.ProtoReflect.Descriptor instead. // Deprecated: Use ConversationRequest.ProtoReflect.Descriptor instead.
func (*ConversationRequest) Descriptor() ([]byte, []int) { func (*ConversationRequest) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{2} return file_messages_proto_rawDescGZIP(), []int{3}
} }
func (x *ConversationRequest) GetLookupKey() string { func (x *ConversationRequest) GetLookupKey() string {
@@ -283,7 +352,7 @@ type Meet struct {
func (x *Meet) Reset() { func (x *Meet) Reset() {
*x = Meet{} *x = Meet{}
mi := &file_messages_proto_msgTypes[3] mi := &file_messages_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -295,7 +364,7 @@ func (x *Meet) String() string {
func (*Meet) ProtoMessage() {} func (*Meet) ProtoMessage() {}
func (x *Meet) ProtoReflect() protoreflect.Message { func (x *Meet) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[3] mi := &file_messages_proto_msgTypes[4]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -308,7 +377,7 @@ func (x *Meet) ProtoReflect() protoreflect.Message {
// Deprecated: Use Meet.ProtoReflect.Descriptor instead. // Deprecated: Use Meet.ProtoReflect.Descriptor instead.
func (*Meet) Descriptor() ([]byte, []int) { func (*Meet) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{3} return file_messages_proto_rawDescGZIP(), []int{4}
} }
func (x *Meet) GetPublicStatus() string { func (x *Meet) GetPublicStatus() string {
@@ -344,7 +413,7 @@ type Credentials struct {
func (x *Credentials) Reset() { func (x *Credentials) Reset() {
*x = Credentials{} *x = Credentials{}
mi := &file_messages_proto_msgTypes[4] mi := &file_messages_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -356,7 +425,7 @@ func (x *Credentials) String() string {
func (*Credentials) ProtoMessage() {} func (*Credentials) ProtoMessage() {}
func (x *Credentials) ProtoReflect() protoreflect.Message { func (x *Credentials) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[4] mi := &file_messages_proto_msgTypes[5]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -369,7 +438,7 @@ func (x *Credentials) ProtoReflect() protoreflect.Message {
// Deprecated: Use Credentials.ProtoReflect.Descriptor instead. // Deprecated: Use Credentials.ProtoReflect.Descriptor instead.
func (*Credentials) Descriptor() ([]byte, []int) { func (*Credentials) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{4} return file_messages_proto_rawDescGZIP(), []int{5}
} }
func (x *Credentials) GetLogin() string { func (x *Credentials) GetLogin() string {
@@ -422,7 +491,7 @@ type ToServerMessage struct {
func (x *ToServerMessage) Reset() { func (x *ToServerMessage) Reset() {
*x = ToServerMessage{} *x = ToServerMessage{}
mi := &file_messages_proto_msgTypes[5] mi := &file_messages_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -434,7 +503,7 @@ func (x *ToServerMessage) String() string {
func (*ToServerMessage) ProtoMessage() {} func (*ToServerMessage) ProtoMessage() {}
func (x *ToServerMessage) ProtoReflect() protoreflect.Message { func (x *ToServerMessage) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[5] mi := &file_messages_proto_msgTypes[6]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -447,7 +516,7 @@ func (x *ToServerMessage) ProtoReflect() protoreflect.Message {
// Deprecated: Use ToServerMessage.ProtoReflect.Descriptor instead. // Deprecated: Use ToServerMessage.ProtoReflect.Descriptor instead.
func (*ToServerMessage) Descriptor() ([]byte, []int) { func (*ToServerMessage) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{5} return file_messages_proto_rawDescGZIP(), []int{6}
} }
func (x *ToServerMessage) GetType() string { func (x *ToServerMessage) GetType() string {
@@ -561,7 +630,7 @@ type FromServerMessage struct {
func (x *FromServerMessage) Reset() { func (x *FromServerMessage) Reset() {
*x = FromServerMessage{} *x = FromServerMessage{}
mi := &file_messages_proto_msgTypes[6] mi := &file_messages_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -573,7 +642,7 @@ func (x *FromServerMessage) String() string {
func (*FromServerMessage) ProtoMessage() {} func (*FromServerMessage) ProtoMessage() {}
func (x *FromServerMessage) ProtoReflect() protoreflect.Message { func (x *FromServerMessage) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[6] mi := &file_messages_proto_msgTypes[7]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -586,7 +655,7 @@ func (x *FromServerMessage) ProtoReflect() protoreflect.Message {
// Deprecated: Use FromServerMessage.ProtoReflect.Descriptor instead. // Deprecated: Use FromServerMessage.ProtoReflect.Descriptor instead.
func (*FromServerMessage) Descriptor() ([]byte, []int) { func (*FromServerMessage) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{6} return file_messages_proto_rawDescGZIP(), []int{7}
} }
func (x *FromServerMessage) GetType() string { func (x *FromServerMessage) GetType() string {
@@ -678,7 +747,7 @@ type MatriochkaServer struct {
func (x *MatriochkaServer) Reset() { func (x *MatriochkaServer) Reset() {
*x = MatriochkaServer{} *x = MatriochkaServer{}
mi := &file_messages_proto_msgTypes[7] mi := &file_messages_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -690,7 +759,7 @@ func (x *MatriochkaServer) String() string {
func (*MatriochkaServer) ProtoMessage() {} func (*MatriochkaServer) ProtoMessage() {}
func (x *MatriochkaServer) ProtoReflect() protoreflect.Message { func (x *MatriochkaServer) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[7] mi := &file_messages_proto_msgTypes[8]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -703,7 +772,7 @@ func (x *MatriochkaServer) ProtoReflect() protoreflect.Message {
// Deprecated: Use MatriochkaServer.ProtoReflect.Descriptor instead. // Deprecated: Use MatriochkaServer.ProtoReflect.Descriptor instead.
func (*MatriochkaServer) Descriptor() ([]byte, []int) { func (*MatriochkaServer) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{7} return file_messages_proto_rawDescGZIP(), []int{8}
} }
func (x *MatriochkaServer) GetUrl() string { func (x *MatriochkaServer) GetUrl() string {
@@ -746,7 +815,7 @@ type Matriochka struct {
func (x *Matriochka) Reset() { func (x *Matriochka) Reset() {
*x = Matriochka{} *x = Matriochka{}
mi := &file_messages_proto_msgTypes[8] mi := &file_messages_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -758,7 +827,7 @@ func (x *Matriochka) String() string {
func (*Matriochka) ProtoMessage() {} func (*Matriochka) ProtoMessage() {}
func (x *Matriochka) ProtoReflect() protoreflect.Message { func (x *Matriochka) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[8] mi := &file_messages_proto_msgTypes[9]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -771,7 +840,7 @@ func (x *Matriochka) ProtoReflect() protoreflect.Message {
// Deprecated: Use Matriochka.ProtoReflect.Descriptor instead. // Deprecated: Use Matriochka.ProtoReflect.Descriptor instead.
func (*Matriochka) Descriptor() ([]byte, []int) { func (*Matriochka) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{8} return file_messages_proto_rawDescGZIP(), []int{9}
} }
func (x *Matriochka) GetLookupKey() string { func (x *Matriochka) GetLookupKey() string {
@@ -818,7 +887,7 @@ type ServerCard struct {
func (x *ServerCard) Reset() { func (x *ServerCard) Reset() {
*x = ServerCard{} *x = ServerCard{}
mi := &file_messages_proto_msgTypes[9] mi := &file_messages_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -830,7 +899,7 @@ func (x *ServerCard) String() string {
func (*ServerCard) ProtoMessage() {} func (*ServerCard) ProtoMessage() {}
func (x *ServerCard) ProtoReflect() protoreflect.Message { func (x *ServerCard) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[9] mi := &file_messages_proto_msgTypes[10]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -843,7 +912,7 @@ func (x *ServerCard) ProtoReflect() protoreflect.Message {
// Deprecated: Use ServerCard.ProtoReflect.Descriptor instead. // Deprecated: Use ServerCard.ProtoReflect.Descriptor instead.
func (*ServerCard) Descriptor() ([]byte, []int) { func (*ServerCard) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{9} return file_messages_proto_rawDescGZIP(), []int{10}
} }
func (x *ServerCard) GetName() string { func (x *ServerCard) GetName() string {
@@ -915,7 +984,7 @@ type ContactCard struct {
func (x *ContactCard) Reset() { func (x *ContactCard) Reset() {
*x = ContactCard{} *x = ContactCard{}
mi := &file_messages_proto_msgTypes[10] mi := &file_messages_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -927,7 +996,7 @@ func (x *ContactCard) String() string {
func (*ContactCard) ProtoMessage() {} func (*ContactCard) ProtoMessage() {}
func (x *ContactCard) ProtoReflect() protoreflect.Message { func (x *ContactCard) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[10] mi := &file_messages_proto_msgTypes[11]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -940,7 +1009,7 @@ func (x *ContactCard) ProtoReflect() protoreflect.Message {
// Deprecated: Use ContactCard.ProtoReflect.Descriptor instead. // Deprecated: Use ContactCard.ProtoReflect.Descriptor instead.
func (*ContactCard) Descriptor() ([]byte, []int) { func (*ContactCard) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{10} return file_messages_proto_rawDescGZIP(), []int{11}
} }
func (x *ContactCard) GetName() string { func (x *ContactCard) GetName() string {
@@ -1035,7 +1104,7 @@ type PackedUserMessage struct {
func (x *PackedUserMessage) Reset() { func (x *PackedUserMessage) Reset() {
*x = PackedUserMessage{} *x = PackedUserMessage{}
mi := &file_messages_proto_msgTypes[11] mi := &file_messages_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -1047,7 +1116,7 @@ func (x *PackedUserMessage) String() string {
func (*PackedUserMessage) ProtoMessage() {} func (*PackedUserMessage) ProtoMessage() {}
func (x *PackedUserMessage) ProtoReflect() protoreflect.Message { func (x *PackedUserMessage) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[11] mi := &file_messages_proto_msgTypes[12]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -1060,7 +1129,7 @@ func (x *PackedUserMessage) ProtoReflect() protoreflect.Message {
// Deprecated: Use PackedUserMessage.ProtoReflect.Descriptor instead. // Deprecated: Use PackedUserMessage.ProtoReflect.Descriptor instead.
func (*PackedUserMessage) Descriptor() ([]byte, []int) { func (*PackedUserMessage) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{11} return file_messages_proto_rawDescGZIP(), []int{12}
} }
func (x *PackedUserMessage) GetDestination() string { func (x *PackedUserMessage) GetDestination() string {
@@ -1108,7 +1177,7 @@ func (x *PackedUserMessage) GetDrHeader() []byte {
type ConversationStatus struct { type ConversationStatus struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Uuid string `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` // uuid of message, or uuid of related message if uuid_action is not empty Uuid string `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` // uuid of message, or uuid of related message if uuid_action is not empty
Reactions []*Reaction `protobuf:"bytes,2,rep,name=reactions,proto3" json:"reactions,omitempty"` // empty => normal message, 1: receivedack, 2: processedack, 3:reaction Reactions []*Reaction `protobuf:"bytes,2,rep,name=reactions,proto3" json:"reactions,omitempty"` // reaction to the message per peer
ReplyToUuid string `protobuf:"bytes,3,opt,name=reply_to_uuid,json=replyToUuid,proto3" json:"reply_to_uuid,omitempty"` // this message replies to the specified uuid ReplyToUuid string `protobuf:"bytes,3,opt,name=reply_to_uuid,json=replyToUuid,proto3" json:"reply_to_uuid,omitempty"` // this message replies to the specified uuid
LocalSequence uint64 `protobuf:"varint,4,opt,name=local_sequence,json=localSequence,proto3" json:"local_sequence,omitempty"` // seq number in local conversation for custom reordering LocalSequence uint64 `protobuf:"varint,4,opt,name=local_sequence,json=localSequence,proto3" json:"local_sequence,omitempty"` // seq number in local conversation for custom reordering
Sent uint64 `protobuf:"varint,5,opt,name=sent,proto3" json:"sent,omitempty"` // timestamp of the message sent Sent uint64 `protobuf:"varint,5,opt,name=sent,proto3" json:"sent,omitempty"` // timestamp of the message sent
@@ -1122,7 +1191,7 @@ type ConversationStatus struct {
func (x *ConversationStatus) Reset() { func (x *ConversationStatus) Reset() {
*x = ConversationStatus{} *x = ConversationStatus{}
mi := &file_messages_proto_msgTypes[12] mi := &file_messages_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -1134,7 +1203,7 @@ func (x *ConversationStatus) String() string {
func (*ConversationStatus) ProtoMessage() {} func (*ConversationStatus) ProtoMessage() {}
func (x *ConversationStatus) ProtoReflect() protoreflect.Message { func (x *ConversationStatus) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[12] mi := &file_messages_proto_msgTypes[13]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -1147,7 +1216,7 @@ func (x *ConversationStatus) ProtoReflect() protoreflect.Message {
// Deprecated: Use ConversationStatus.ProtoReflect.Descriptor instead. // Deprecated: Use ConversationStatus.ProtoReflect.Descriptor instead.
func (*ConversationStatus) Descriptor() ([]byte, []int) { func (*ConversationStatus) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{12} return file_messages_proto_rawDescGZIP(), []int{13}
} }
func (x *ConversationStatus) GetUuid() string { func (x *ConversationStatus) GetUuid() string {
@@ -1223,7 +1292,7 @@ type Reaction struct {
func (x *Reaction) Reset() { func (x *Reaction) Reset() {
*x = Reaction{} *x = Reaction{}
mi := &file_messages_proto_msgTypes[13] mi := &file_messages_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -1235,7 +1304,7 @@ func (x *Reaction) String() string {
func (*Reaction) ProtoMessage() {} func (*Reaction) ProtoMessage() {}
func (x *Reaction) ProtoReflect() protoreflect.Message { func (x *Reaction) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[13] mi := &file_messages_proto_msgTypes[14]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -1248,7 +1317,7 @@ func (x *Reaction) ProtoReflect() protoreflect.Message {
// Deprecated: Use Reaction.ProtoReflect.Descriptor instead. // Deprecated: Use Reaction.ProtoReflect.Descriptor instead.
func (*Reaction) Descriptor() ([]byte, []int) { func (*Reaction) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{13} return file_messages_proto_rawDescGZIP(), []int{14}
} }
func (x *Reaction) GetReaction() string { func (x *Reaction) GetReaction() string {
@@ -1275,7 +1344,7 @@ type Group struct {
func (x *Group) Reset() { func (x *Group) Reset() {
*x = Group{} *x = Group{}
mi := &file_messages_proto_msgTypes[14] mi := &file_messages_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -1287,7 +1356,7 @@ func (x *Group) String() string {
func (*Group) ProtoMessage() {} func (*Group) ProtoMessage() {}
func (x *Group) ProtoReflect() protoreflect.Message { func (x *Group) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[14] mi := &file_messages_proto_msgTypes[15]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -1300,7 +1369,7 @@ func (x *Group) ProtoReflect() protoreflect.Message {
// Deprecated: Use Group.ProtoReflect.Descriptor instead. // Deprecated: Use Group.ProtoReflect.Descriptor instead.
func (*Group) Descriptor() ([]byte, []int) { func (*Group) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{14} return file_messages_proto_rawDescGZIP(), []int{15}
} }
func (x *Group) GetName() string { func (x *Group) GetName() string {
@@ -1339,7 +1408,7 @@ type UserMessage struct {
func (x *UserMessage) Reset() { func (x *UserMessage) Reset() {
*x = UserMessage{} *x = UserMessage{}
mi := &file_messages_proto_msgTypes[15] mi := &file_messages_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -1351,7 +1420,7 @@ func (x *UserMessage) String() string {
func (*UserMessage) ProtoMessage() {} func (*UserMessage) ProtoMessage() {}
func (x *UserMessage) ProtoReflect() protoreflect.Message { func (x *UserMessage) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[15] mi := &file_messages_proto_msgTypes[16]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -1364,7 +1433,7 @@ func (x *UserMessage) ProtoReflect() protoreflect.Message {
// Deprecated: Use UserMessage.ProtoReflect.Descriptor instead. // Deprecated: Use UserMessage.ProtoReflect.Descriptor instead.
func (*UserMessage) Descriptor() ([]byte, []int) { func (*UserMessage) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{15} return file_messages_proto_rawDescGZIP(), []int{16}
} }
func (x *UserMessage) GetDestination() string { func (x *UserMessage) GetDestination() string {
@@ -1470,7 +1539,7 @@ type File struct {
func (x *File) Reset() { func (x *File) Reset() {
*x = File{} *x = File{}
mi := &file_messages_proto_msgTypes[16] mi := &file_messages_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -1482,7 +1551,7 @@ func (x *File) String() string {
func (*File) ProtoMessage() {} func (*File) ProtoMessage() {}
func (x *File) ProtoReflect() protoreflect.Message { func (x *File) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[16] mi := &file_messages_proto_msgTypes[17]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -1495,7 +1564,7 @@ func (x *File) ProtoReflect() protoreflect.Message {
// Deprecated: Use File.ProtoReflect.Descriptor instead. // Deprecated: Use File.ProtoReflect.Descriptor instead.
func (*File) Descriptor() ([]byte, []int) { func (*File) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{16} return file_messages_proto_rawDescGZIP(), []int{17}
} }
func (x *File) GetFilename() string { func (x *File) GetFilename() string {
@@ -1538,7 +1607,7 @@ type Location struct {
func (x *Location) Reset() { func (x *Location) Reset() {
*x = Location{} *x = Location{}
mi := &file_messages_proto_msgTypes[17] mi := &file_messages_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -1550,7 +1619,7 @@ func (x *Location) String() string {
func (*Location) ProtoMessage() {} func (*Location) ProtoMessage() {}
func (x *Location) ProtoReflect() protoreflect.Message { func (x *Location) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[17] mi := &file_messages_proto_msgTypes[18]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -1563,7 +1632,7 @@ func (x *Location) ProtoReflect() protoreflect.Message {
// Deprecated: Use Location.ProtoReflect.Descriptor instead. // Deprecated: Use Location.ProtoReflect.Descriptor instead.
func (*Location) Descriptor() ([]byte, []int) { func (*Location) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{17} return file_messages_proto_rawDescGZIP(), []int{18}
} }
func (x *Location) GetTime() uint64 { func (x *Location) GetTime() uint64 {
@@ -1615,7 +1684,7 @@ type DbMessage struct {
func (x *DbMessage) Reset() { func (x *DbMessage) Reset() {
*x = DbMessage{} *x = DbMessage{}
mi := &file_messages_proto_msgTypes[18] mi := &file_messages_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -1627,7 +1696,7 @@ func (x *DbMessage) String() string {
func (*DbMessage) ProtoMessage() {} func (*DbMessage) ProtoMessage() {}
func (x *DbMessage) ProtoReflect() protoreflect.Message { func (x *DbMessage) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[18] mi := &file_messages_proto_msgTypes[19]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -1640,7 +1709,7 @@ func (x *DbMessage) ProtoReflect() protoreflect.Message {
// Deprecated: Use DbMessage.ProtoReflect.Descriptor instead. // Deprecated: Use DbMessage.ProtoReflect.Descriptor instead.
func (*DbMessage) Descriptor() ([]byte, []int) { func (*DbMessage) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{18} return file_messages_proto_rawDescGZIP(), []int{19}
} }
func (x *DbMessage) GetOutbound() bool { func (x *DbMessage) GetOutbound() bool {
@@ -1747,7 +1816,7 @@ type VideoData struct {
func (x *VideoData) Reset() { func (x *VideoData) Reset() {
*x = VideoData{} *x = VideoData{}
mi := &file_messages_proto_msgTypes[19] mi := &file_messages_proto_msgTypes[20]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -1759,7 +1828,7 @@ func (x *VideoData) String() string {
func (*VideoData) ProtoMessage() {} func (*VideoData) ProtoMessage() {}
func (x *VideoData) ProtoReflect() protoreflect.Message { func (x *VideoData) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[19] mi := &file_messages_proto_msgTypes[20]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -1772,7 +1841,7 @@ func (x *VideoData) ProtoReflect() protoreflect.Message {
// Deprecated: Use VideoData.ProtoReflect.Descriptor instead. // Deprecated: Use VideoData.ProtoReflect.Descriptor instead.
func (*VideoData) Descriptor() ([]byte, []int) { func (*VideoData) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{19} return file_messages_proto_rawDescGZIP(), []int{20}
} }
func (x *VideoData) GetUrl() string { func (x *VideoData) GetUrl() string {
@@ -1821,7 +1890,7 @@ type VideoCredential struct {
func (x *VideoCredential) Reset() { func (x *VideoCredential) Reset() {
*x = VideoCredential{} *x = VideoCredential{}
mi := &file_messages_proto_msgTypes[20] mi := &file_messages_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -1833,7 +1902,7 @@ func (x *VideoCredential) String() string {
func (*VideoCredential) ProtoMessage() {} func (*VideoCredential) ProtoMessage() {}
func (x *VideoCredential) ProtoReflect() protoreflect.Message { func (x *VideoCredential) ProtoReflect() protoreflect.Message {
mi := &file_messages_proto_msgTypes[20] mi := &file_messages_proto_msgTypes[21]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -1846,7 +1915,7 @@ func (x *VideoCredential) ProtoReflect() protoreflect.Message {
// Deprecated: Use VideoCredential.ProtoReflect.Descriptor instead. // Deprecated: Use VideoCredential.ProtoReflect.Descriptor instead.
func (*VideoCredential) Descriptor() ([]byte, []int) { func (*VideoCredential) Descriptor() ([]byte, []int) {
return file_messages_proto_rawDescGZIP(), []int{20} return file_messages_proto_rawDescGZIP(), []int{21}
} }
func (x *VideoCredential) GetUsername() string { func (x *VideoCredential) GetUsername() string {
@@ -1878,18 +1947,24 @@ const file_messages_proto_rawDesc = "" +
"\x13PackedServerMessage\x12\x12\n" + "\x13PackedServerMessage\x12\x12\n" +
"\x04from\x18\x01 \x01(\tR\x04from\x12\x18\n" + "\x04from\x18\x01 \x01(\tR\x04from\x12\x18\n" +
"\apayload\x18\x02 \x01(\fR\apayload\x12\x1c\n" + "\apayload\x18\x02 \x01(\fR\apayload\x12\x1c\n" +
"\tsignature\x18\x03 \x01(\fR\tsignature\"\xf2\x01\n" + "\tsignature\x18\x03 \x01(\fR\tsignature\"\xf3\x01\n" +
"\n" + "\n" +
"Invitation\x12\x18\n" + "Invitation\x12\x18\n" +
"\apayload\x18\x01 \x01(\fR\apayload\x12\x18\n" + "\apayload\x18\x01 \x01(\fR\apayload\x12\x18\n" +
"\atimeout\x18\x02 \x01(\x05R\atimeout\x12\"\n" + "\atimeout\x18\x02 \x01(\x05R\atimeout\x12#\n" +
"\fshortcodeLen\x18\x03 \x01(\x05R\fshortcodeLen\x12\x1c\n" + "\rshortcode_len\x18\x03 \x01(\x05R\fshortcodeLen\x12\x1c\n" +
"\tshortcode\x18\x04 \x01(\tR\tshortcode\x12\x1a\n" + "\tshortcode\x18\x04 \x01(\tR\tshortcode\x12\x1a\n" +
"\bpassword\x18\x05 \x01(\tR\bpassword\x12\x12\n" + "\bpassword\x18\x05 \x01(\tR\bpassword\x12\x12\n" +
"\x04uuid\x18\x06 \x01(\tR\x04uuid\x12\x16\n" + "\x04uuid\x18\x06 \x01(\tR\x04uuid\x12\x16\n" +
"\x06expiry\x18\a \x01(\x03R\x06expiry\x12\x12\n" + "\x06expiry\x18\a \x01(\x03R\x06expiry\x12\x12\n" +
"\x04step\x18\b \x01(\x05R\x04step\x12\x12\n" + "\x04step\x18\b \x01(\x05R\x04step\x12\x12\n" +
"\x04from\x18\t \x01(\tR\x04from\"\xb1\x01\n" + "\x04from\x18\t \x01(\tR\x04from\"\x8d\x01\n" +
"\x15InvitationInitPayload\x12\x12\n" +
"\x04uuid\x18\x01 \x01(\tR\x04uuid\x12\x12\n" +
"\x04name\x18\x02 \x01(\tR\x04name\x12\x1d\n" +
"\n" +
"public_key\x18\x03 \x01(\tR\tpublicKey\x12-\n" +
"\x12invitation_message\x18\x04 \x01(\tR\x11invitationMessage\"\xb1\x01\n" +
"\x13ConversationRequest\x12\x1d\n" + "\x13ConversationRequest\x12\x1d\n" +
"\n" + "\n" +
"lookup_key\x18\x01 \x01(\tR\tlookupKey\x12)\n" + "lookup_key\x18\x01 \x01(\tR\tlookupKey\x12)\n" +
@@ -2072,66 +2147,67 @@ func file_messages_proto_rawDescGZIP() []byte {
return file_messages_proto_rawDescData return file_messages_proto_rawDescData
} }
var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 21) var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 22)
var file_messages_proto_goTypes = []any{ var file_messages_proto_goTypes = []any{
(*PackedServerMessage)(nil), // 0: meowlib.PackedServerMessage (*PackedServerMessage)(nil), // 0: meowlib.PackedServerMessage
(*Invitation)(nil), // 1: meowlib.Invitation (*Invitation)(nil), // 1: meowlib.Invitation
(*ConversationRequest)(nil), // 2: meowlib.ConversationRequest (*InvitationInitPayload)(nil), // 2: meowlib.InvitationInitPayload
(*Meet)(nil), // 3: meowlib.Meet (*ConversationRequest)(nil), // 3: meowlib.ConversationRequest
(*Credentials)(nil), // 4: meowlib.Credentials (*Meet)(nil), // 4: meowlib.Meet
(*ToServerMessage)(nil), // 5: meowlib.ToServerMessage (*Credentials)(nil), // 5: meowlib.Credentials
(*FromServerMessage)(nil), // 6: meowlib.FromServerMessage (*ToServerMessage)(nil), // 6: meowlib.ToServerMessage
(*MatriochkaServer)(nil), // 7: meowlib.MatriochkaServer (*FromServerMessage)(nil), // 7: meowlib.FromServerMessage
(*Matriochka)(nil), // 8: meowlib.Matriochka (*MatriochkaServer)(nil), // 8: meowlib.MatriochkaServer
(*ServerCard)(nil), // 9: meowlib.ServerCard (*Matriochka)(nil), // 9: meowlib.Matriochka
(*ContactCard)(nil), // 10: meowlib.ContactCard (*ServerCard)(nil), // 10: meowlib.ServerCard
(*PackedUserMessage)(nil), // 11: meowlib.PackedUserMessage (*ContactCard)(nil), // 11: meowlib.ContactCard
(*ConversationStatus)(nil), // 12: meowlib.ConversationStatus (*PackedUserMessage)(nil), // 12: meowlib.PackedUserMessage
(*Reaction)(nil), // 13: meowlib.Reaction (*ConversationStatus)(nil), // 13: meowlib.ConversationStatus
(*Group)(nil), // 14: meowlib.Group (*Reaction)(nil), // 14: meowlib.Reaction
(*UserMessage)(nil), // 15: meowlib.UserMessage (*Group)(nil), // 15: meowlib.Group
(*File)(nil), // 16: meowlib.File (*UserMessage)(nil), // 16: meowlib.UserMessage
(*Location)(nil), // 17: meowlib.Location (*File)(nil), // 17: meowlib.File
(*DbMessage)(nil), // 18: meowlib.DbMessage (*Location)(nil), // 18: meowlib.Location
(*VideoData)(nil), // 19: meowlib.VideoData (*DbMessage)(nil), // 19: meowlib.DbMessage
(*VideoCredential)(nil), // 20: meowlib.VideoCredential (*VideoData)(nil), // 20: meowlib.VideoData
(*VideoCredential)(nil), // 21: meowlib.VideoCredential
} }
var file_messages_proto_depIdxs = []int32{ var file_messages_proto_depIdxs = []int32{
10, // 0: meowlib.Meet.contact_card:type_name -> meowlib.ContactCard 11, // 0: meowlib.Meet.contact_card:type_name -> meowlib.ContactCard
2, // 1: meowlib.ToServerMessage.pull_request:type_name -> meowlib.ConversationRequest 3, // 1: meowlib.ToServerMessage.pull_request:type_name -> meowlib.ConversationRequest
11, // 2: meowlib.ToServerMessage.messages:type_name -> meowlib.PackedUserMessage 12, // 2: meowlib.ToServerMessage.messages:type_name -> meowlib.PackedUserMessage
9, // 3: meowlib.ToServerMessage.known_servers:type_name -> meowlib.ServerCard 10, // 3: meowlib.ToServerMessage.known_servers:type_name -> meowlib.ServerCard
8, // 4: meowlib.ToServerMessage.matriochka_message:type_name -> meowlib.Matriochka 9, // 4: meowlib.ToServerMessage.matriochka_message:type_name -> meowlib.Matriochka
1, // 5: meowlib.ToServerMessage.invitation:type_name -> meowlib.Invitation 1, // 5: meowlib.ToServerMessage.invitation:type_name -> meowlib.Invitation
11, // 6: meowlib.ToServerMessage.device_messages:type_name -> meowlib.PackedUserMessage 12, // 6: meowlib.ToServerMessage.device_messages:type_name -> meowlib.PackedUserMessage
19, // 7: meowlib.ToServerMessage.video_data:type_name -> meowlib.VideoData 20, // 7: meowlib.ToServerMessage.video_data:type_name -> meowlib.VideoData
4, // 8: meowlib.ToServerMessage.credentials:type_name -> meowlib.Credentials 5, // 8: meowlib.ToServerMessage.credentials:type_name -> meowlib.Credentials
11, // 9: meowlib.FromServerMessage.chat:type_name -> meowlib.PackedUserMessage 12, // 9: meowlib.FromServerMessage.chat:type_name -> meowlib.PackedUserMessage
9, // 10: meowlib.FromServerMessage.known_servers:type_name -> meowlib.ServerCard 10, // 10: meowlib.FromServerMessage.known_servers:type_name -> meowlib.ServerCard
1, // 11: meowlib.FromServerMessage.invitation:type_name -> meowlib.Invitation 1, // 11: meowlib.FromServerMessage.invitation:type_name -> meowlib.Invitation
11, // 12: meowlib.FromServerMessage.device_messages:type_name -> meowlib.PackedUserMessage 12, // 12: meowlib.FromServerMessage.device_messages:type_name -> meowlib.PackedUserMessage
19, // 13: meowlib.FromServerMessage.video_data:type_name -> meowlib.VideoData 20, // 13: meowlib.FromServerMessage.video_data:type_name -> meowlib.VideoData
10, // 14: meowlib.FromServerMessage.contact_card:type_name -> meowlib.ContactCard 11, // 14: meowlib.FromServerMessage.contact_card:type_name -> meowlib.ContactCard
7, // 15: meowlib.Matriochka.prev:type_name -> meowlib.MatriochkaServer 8, // 15: meowlib.Matriochka.prev:type_name -> meowlib.MatriochkaServer
7, // 16: meowlib.Matriochka.next:type_name -> meowlib.MatriochkaServer 8, // 16: meowlib.Matriochka.next:type_name -> meowlib.MatriochkaServer
9, // 17: meowlib.ContactCard.pull_servers:type_name -> meowlib.ServerCard 10, // 17: meowlib.ContactCard.pull_servers:type_name -> meowlib.ServerCard
13, // 18: meowlib.ConversationStatus.reactions:type_name -> meowlib.Reaction 14, // 18: meowlib.ConversationStatus.reactions:type_name -> meowlib.Reaction
10, // 19: meowlib.ConversationStatus.my_next_identity:type_name -> meowlib.ContactCard 11, // 19: meowlib.ConversationStatus.my_next_identity:type_name -> meowlib.ContactCard
10, // 20: meowlib.Group.members:type_name -> meowlib.ContactCard 11, // 20: meowlib.Group.members:type_name -> meowlib.ContactCard
12, // 21: meowlib.UserMessage.status:type_name -> meowlib.ConversationStatus 13, // 21: meowlib.UserMessage.status:type_name -> meowlib.ConversationStatus
10, // 22: meowlib.UserMessage.contact:type_name -> meowlib.ContactCard 11, // 22: meowlib.UserMessage.contact:type_name -> meowlib.ContactCard
9, // 23: meowlib.UserMessage.known_servers:type_name -> meowlib.ServerCard 10, // 23: meowlib.UserMessage.known_servers:type_name -> meowlib.ServerCard
14, // 24: meowlib.UserMessage.group:type_name -> meowlib.Group 15, // 24: meowlib.UserMessage.group:type_name -> meowlib.Group
16, // 25: meowlib.UserMessage.files:type_name -> meowlib.File 17, // 25: meowlib.UserMessage.files:type_name -> meowlib.File
17, // 26: meowlib.UserMessage.current_location:type_name -> meowlib.Location 18, // 26: meowlib.UserMessage.current_location:type_name -> meowlib.Location
1, // 27: meowlib.UserMessage.invitation:type_name -> meowlib.Invitation 1, // 27: meowlib.UserMessage.invitation:type_name -> meowlib.Invitation
19, // 28: meowlib.UserMessage.video_data:type_name -> meowlib.VideoData 20, // 28: meowlib.UserMessage.video_data:type_name -> meowlib.VideoData
12, // 29: meowlib.DbMessage.status:type_name -> meowlib.ConversationStatus 13, // 29: meowlib.DbMessage.status:type_name -> meowlib.ConversationStatus
10, // 30: meowlib.DbMessage.contact:type_name -> meowlib.ContactCard 11, // 30: meowlib.DbMessage.contact:type_name -> meowlib.ContactCard
14, // 31: meowlib.DbMessage.group:type_name -> meowlib.Group 15, // 31: meowlib.DbMessage.group:type_name -> meowlib.Group
17, // 32: meowlib.DbMessage.current_location:type_name -> meowlib.Location 18, // 32: meowlib.DbMessage.current_location:type_name -> meowlib.Location
1, // 33: meowlib.DbMessage.invitation:type_name -> meowlib.Invitation 1, // 33: meowlib.DbMessage.invitation:type_name -> meowlib.Invitation
20, // 34: meowlib.VideoData.credentials:type_name -> meowlib.VideoCredential 21, // 34: meowlib.VideoData.credentials:type_name -> meowlib.VideoCredential
35, // [35:35] is the sub-list for method output_type 35, // [35:35] is the sub-list for method output_type
35, // [35:35] is the sub-list for method input_type 35, // [35:35] is the sub-list for method input_type
35, // [35:35] is the sub-list for extension type_name 35, // [35:35] is the sub-list for extension type_name
@@ -2150,7 +2226,7 @@ func file_messages_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_messages_proto_rawDesc), len(file_messages_proto_rawDesc)), RawDescriptor: unsafe.Slice(unsafe.StringData(file_messages_proto_rawDesc), len(file_messages_proto_rawDesc)),
NumEnums: 0, NumEnums: 0,
NumMessages: 21, NumMessages: 22,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },
+9 -1
View File
@@ -30,7 +30,15 @@ message Invitation {
string uuid = 6; // invitation uuid string uuid = 6; // invitation uuid
int64 expiry = 7; // the server allowed expiry date, it may be smaller than the requested timeout according to server policy int64 expiry = 7; // the server allowed expiry date, it may be smaller than the requested timeout according to server policy
int32 step = 8; // progress in the invitation process : 1=initiator pub key, 2=invited data enc with pub key, 3=initator data full encrypted, 4=invited All OK ! int32 step = 8; // progress in the invitation process : 1=initiator pub key, 2=invited data enc with pub key, 3=initator data full encrypted, 4=invited All OK !
string from = 9; // used in step 1 the public key to encrypt step 2 message string from = 9; // still useful ?
}
// This payload migh be used for file serialization as well as Invitation/payload in case of through server invitation
message InvitationInitPayload {
string uuid = 1; // uuid of the invitation, it is set here on init cause the payload might be encrypted
string name = 2; // name of the initiator
string public_key = 3; // public key to be used for step 2 encryption
string invitation_message = 4; // message for the invited peer
} }
// structure for requesting incoming messages // structure for requesting incoming messages