diff --git a/be1-go/channel/federation/federation.go b/be1-go/channel/federation/federation.go index 542188d565..be0de6be22 100644 --- a/be1-go/channel/federation/federation.go +++ b/be1-go/channel/federation/federation.go @@ -6,10 +6,9 @@ import ( "encoding/hex" "encoding/json" "fmt" - "github.com/rs/zerolog" - "golang.org/x/xerrors" "popstellar/channel" "popstellar/channel/registry" + "popstellar/crypto" "popstellar/inbox" jsonrpc "popstellar/message" "popstellar/message/answer" @@ -22,6 +21,10 @@ import ( "strconv" "sync" "time" + + "github.com/rs/zerolog" + "go.dedis.ch/kyber/v3/sign/schnorr" + "golang.org/x/xerrors" ) const ( @@ -47,8 +50,9 @@ type remoteOrganization struct { // store the pop tokens of the other lao // popTokens map[string]struct{} - challenge messagedata.Challenge - socket socket.Socket + challenge messagedata.FederationChallenge + challengeMsg message.Message + socket socket.Socket state State sync.Mutex @@ -69,7 +73,7 @@ type Channel struct { remoteOrganizations map[string]*remoteOrganization // list of challenge requested but not used yet - challenges map[messagedata.Challenge]struct{} + challenges map[messagedata.FederationChallenge]struct{} sync.Mutex } @@ -88,7 +92,7 @@ func NewChannel(channelID string, hub channel.HubFunctionalities, log: log, localOrganizerPk: organizerPk, remoteOrganizations: make(map[string]*remoteOrganization), - challenges: make(map[messagedata.Challenge]struct{}), + challenges: make(map[messagedata.FederationChallenge]struct{}), } newChannel.registry = newChannel.NewFederationRegistry() @@ -155,6 +159,7 @@ func (c *Channel) NewFederationRegistry() registry.MessageRegistry { fedRegistry.Register(messagedata.FederationExpect{}, c.processFederationExpect) fedRegistry.Register(messagedata.FederationInit{}, c.processFederationInit) fedRegistry.Register(messagedata.FederationChallenge{}, c.processFederationChallenge) + fedRegistry.Register(messagedata.FederationResult{}, c.processFederationResult) return fedRegistry } @@ -230,10 +235,7 @@ func (c *Channel) processFederationInit(msg message.Message, remoteOrg.organizerPk = federationInit.PublicKey remoteOrg.laoId = federationInit.LaoId remoteOrg.fedChannel = fmt.Sprintf("/root/%s/federation", federationInit.LaoId) - remoteOrg.challenge = messagedata.Challenge{ - Value: federationChallenge.Value, - ValidUntil: federationChallenge.Timestamp, - } + remoteOrg.challenge = federationChallenge remoteOrg.socket, err = c.hub.ConnectToServerAsClient(federationInit.ServerAddress) if err != nil { @@ -268,6 +270,7 @@ func (c *Channel) processFederationInit(msg message.Message, } remoteOrg.socket.Send(buf) + remoteOrg.state = WaitResult return nil } @@ -293,7 +296,6 @@ func (c *Channel) processFederationExpect(msg message.Message, if err != nil { return xerrors.Errorf("failed to unmarshal federationExpect data: %v", err) } - remoteOrg := c.getRemoteOrganization(federationExpect.PublicKey) remoteOrg.Lock() defer remoteOrg.Unlock() @@ -301,23 +303,29 @@ func (c *Channel) processFederationExpect(msg message.Message, if remoteOrg.state != None { return answer.NewInternalServerError(invalidStateError, remoteOrg.state, msg) } + var federationChallenge messagedata.FederationChallenge + err = federationExpect.ChallengeMsg.UnmarshalData(&federationChallenge) + if err != nil { + return xerrors.Errorf("failed to unmarshal federationChallenge data: %v", err) + } c.Lock() - _, ok = c.challenges[federationExpect.Challenge] + _, ok = c.challenges[federationChallenge] // always remove the challenge, if present, to avoid challenge reuse - delete(c.challenges, federationExpect.Challenge) + delete(c.challenges, federationChallenge) c.Unlock() if !ok { return answer.NewAccessDeniedError("Invalid challenge %v", - federationExpect.Challenge) + federationChallenge) } remoteOrg.state = ExpectConnect - remoteOrg.challenge = federationExpect.Challenge + remoteOrg.challenge = federationChallenge remoteOrg.organizerPk = federationExpect.PublicKey remoteOrg.laoId = federationExpect.LaoId remoteOrg.fedChannel = fmt.Sprintf("/root/%s/federation", federationExpect.LaoId) + remoteOrg.challengeMsg = federationExpect.ChallengeMsg return nil } @@ -369,8 +377,63 @@ func (c *Channel) processFederationChallenge(msg message.Message, remoteOrg.state = WaitResult remoteOrg.socket = s - // Send Federation result to S1 - // c.remoteServer.Send(...) + + federationResultData := messagedata.FederationResult{ + Object: messagedata.FederationObject, + Action: messagedata.FederationActionResult, + Status: "success", + PublicKey: remoteOrg.organizerPk, + ChallengeMsg: remoteOrg.challengeMsg, + } + + dataBytes, err := json.Marshal(federationResultData) + if err != nil { + return xerrors.Errorf("failed to marshal federation result message data: %v", err) + } + + dataBase64 := base64.URLEncoding.EncodeToString(dataBytes) + signatureBytes, err := c.hub.Sign(dataBytes) + if err != nil { + return xerrors.Errorf("failed to sign federation result message: %v", err) + } + signatureBase64 := base64.URLEncoding.EncodeToString(signatureBytes) + + serverPubKey, err := c.hub.GetPubKeyServ().MarshalBinary() + if err != nil { + return xerrors.Errorf("failed to marshal public key of server: %v", err) + + } + + federationResultMsg := message.Message{ + Data: dataBase64, + Sender: base64.URLEncoding.EncodeToString(serverPubKey), + Signature: signatureBase64, + MessageID: messagedata.Hash(dataBase64, signatureBase64), + WitnessSignatures: []message.WitnessSignature{}, + } + + rpcMessage := method.Publish{ + Base: query.Base{ + JSONRPCBase: jsonrpc.JSONRPCBase{ + JSONRPC: "2.0", + }, + Method: "publish", + }, + + Params: struct { + Channel string `json:"channel"` + Message message.Message `json:"message"` + }{ + Channel: remoteOrg.fedChannel, + Message: federationResultMsg, + }, + } + buf, err := json.Marshal(&rpcMessage) + if err != nil { + return xerrors.Errorf("failed to marshal publish query: %v", err) + } + + remoteOrg.socket.Send(buf) return nil } @@ -405,22 +468,17 @@ func (c *Channel) processChallengeRequest(msg message.Message, } challengeValue := hex.EncodeToString(randomBytes) expirationTime := time.Now().Add(time.Minute * 5).Unix() - challenge := messagedata.Challenge{ + federationChallenge := messagedata.FederationChallenge{ + Object: messagedata.FederationObject, + Action: messagedata.FederationActionChallenge, Value: challengeValue, ValidUntil: expirationTime, } c.Lock() - c.challenges[challenge] = struct{}{} + c.challenges[federationChallenge] = struct{}{} c.Unlock() - federationChallenge := messagedata.FederationChallenge{ - Object: messagedata.FederationObject, - Action: messagedata.FederationActionChallenge, - Value: challengeValue, - Timestamp: expirationTime, - } - challengeData, err := json.Marshal(federationChallenge) if err != nil { return xerrors.Errorf( @@ -475,6 +533,83 @@ func (c *Channel) processChallengeRequest(msg message.Message, return nil } +func (c *Channel) processFederationResult(msg message.Message, + msgData interface{}, s socket.Socket) error { + _, ok := msgData.(*messagedata.FederationResult) + if !ok { + return xerrors.Errorf("message %v is not a federation#result message", + msgData) + } + + var federationResult messagedata.FederationResult + + err := msg.UnmarshalData(&federationResult) + if err != nil { + return xerrors.Errorf("failed to unmarshal FederationResult data: %v", err) + } + + if federationResult.Status != "success" { + if len(federationResult.Reason) > 0 { + return xerrors.Errorf("failed to establish federated connection: %v", federationResult.Reason) + } + return xerrors.Errorf("failed to establish federated connection") + } + + var federationChallenge messagedata.FederationChallenge + err = federationResult.ChallengeMsg.UnmarshalData(&federationChallenge) + if err != nil { + return xerrors.Errorf("failed to unmarshal challenge from FederationResult data: %v", err) + } + + challengeDataBytes, err := base64.URLEncoding.DecodeString(federationResult.ChallengeMsg.Data) + if err != nil { + return xerrors.Errorf("failed to decode challenge data in FederationResult: %v", err) + + } + + challengeSignatureBytes, err := base64.URLEncoding.DecodeString(federationResult.ChallengeMsg.Signature) + if err != nil { + return xerrors.Errorf("failed to decode challenge signature in FederationResult: %v", err) + + } + + remoteOrg := c.getRemoteOrganization(federationResult.ChallengeMsg.Sender) + remoteOrg.Lock() + defer remoteOrg.Unlock() + + if remoteOrg.state != WaitResult { + return answer.NewInternalServerError(invalidStateError, remoteOrg.state, msg) + + } + + pkBytes, err := base64.URLEncoding.DecodeString(remoteOrg.organizerPk) + if err != nil { + return xerrors.Errorf("failed to decode remote organizers public key: %v", err) + + } + + remotePk := crypto.Suite.Point() + + err = remotePk.UnmarshalBinary(pkBytes) + if err != nil { + return xerrors.Errorf("failed to decode remote organizers public key: %v", err) + + } + err = schnorr.Verify(crypto.Suite, remotePk, challengeDataBytes, challengeSignatureBytes) + if err != nil { + return xerrors.Errorf("failed to verify signature on challenge in FederationResult message: %v", err) + + } + + if c.localOrganizerPk != federationResult.PublicKey { + return xerrors.Errorf("invalid public key contained in FederationResult message") + } + + remoteOrg.state = Connected + + return nil +} + // getRemoteOrganization get the remoteOrganization for the given organizerPk // or return a new empty one. func (c *Channel) getRemoteOrganization(organizerPk string) *remoteOrganization { diff --git a/be1-go/channel/federation/federation_test.go b/be1-go/channel/federation/federation_test.go index 0f97396d2b..884cb02340 100644 --- a/be1-go/channel/federation/federation_test.go +++ b/be1-go/channel/federation/federation_test.go @@ -5,17 +5,12 @@ import ( "encoding/base64" "encoding/hex" "encoding/json" - "github.com/rs/zerolog" - "github.com/stretchr/testify/require" - "go.dedis.ch/kyber/v3" - "go.dedis.ch/kyber/v3/sign/schnorr" - "golang.org/x/sync/semaphore" - "golang.org/x/xerrors" "io" "os" "path/filepath" "popstellar/channel" "popstellar/crypto" + "popstellar/inbox" jsonrpc "popstellar/message" "popstellar/message/messagedata" "popstellar/message/query" @@ -26,6 +21,13 @@ import ( "sync" "testing" "time" + + "github.com/rs/zerolog" + "github.com/stretchr/testify/require" + "go.dedis.ch/kyber/v3" + "go.dedis.ch/kyber/v3/sign/schnorr" + "golang.org/x/sync/semaphore" + "golang.org/x/xerrors" ) const ( @@ -87,7 +89,7 @@ func Test_FederationRequestChallenge(t *testing.T) { require.Equal(t, messagedata.FederationObject, challenge.Object) require.Equal(t, messagedata.FederationActionChallenge, challenge.Action) - require.Greater(t, challenge.Timestamp, time.Now().Unix()) + require.Greater(t, challenge.ValidUntil, time.Now().Unix()) bytes, err := hex.DecodeString(challenge.Value) require.NoError(t, err) require.Len(t, bytes, 32) @@ -161,10 +163,7 @@ func Test_FederationExpect(t *testing.T) { LaoId: remoteLaoId, ServerAddress: remoteServerAddress, PublicKey: remoteOrganizerKeypair.publicKey, - Challenge: messagedata.Challenge{ - Value: challenge.Value, - ValidUntil: challenge.Timestamp, - }, + ChallengeMsg: challengeMsg, } federationMsg := generateMessage(t, organizerKeypair, federationExpect) @@ -212,9 +211,12 @@ func Test_FederationExpect_with_invalid_challenge(t *testing.T) { LaoId: remoteLaoId, ServerAddress: remoteServerAddress, PublicKey: remoteOrganizerKeypair.publicKey, - Challenge: messagedata.Challenge{ - Value: hex.EncodeToString(valueBytes), - ValidUntil: time.Now().Unix(), + ChallengeMsg: message.Message{ + Data: "aaaaaaaaaaa", + Sender: organizerKeypair.publicKey, + Signature: "bbbbbbbbbbb", + MessageID: messagedata.Hash("aaaaaaaaaaa", "bbbbbbbbbbb"), + WitnessSignatures: []message.WitnessSignature{}, }, } @@ -269,10 +271,7 @@ func Test_FederationChallenge_not_organizer(t *testing.T) { LaoId: remoteLaoId, ServerAddress: remoteServerAddress, PublicKey: remoteOrganizerKeypair.publicKey, - Challenge: messagedata.Challenge{ - Value: challenge.Value, - ValidUntil: challenge.Timestamp, - }, + ChallengeMsg: challengeMsg, } federationMsg := generateMessage(t, notOrganizerKeypair, federationExpect) @@ -348,6 +347,78 @@ func Test_FederationInit(t *testing.T) { } +func Test_FederationResult(t *testing.T) { + organizerKeypair := generateKeyPair(t) + remoteOrganizerKeypair := generateKeyPair(t) + fakeHub, err := NewFakeHub("", organizerKeypair.public, nolog, nil) + require.NoError(t, err) + + // dirty hack to manually create a channel, so we can then add the remote organizer pk without + // having to go through the init process + + box := inbox.NewInbox(localFedChannel) + + remoteOrg := &remoteOrganization{ + organizerPk: remoteOrganizerKeypair.publicKey, + state: None, + } + remoteOrg.organizerPk = remoteOrganizerKeypair.publicKey + remoteOrg.state = WaitResult + + var remoteOrgs = map[string]*remoteOrganization{ + remoteOrganizerKeypair.publicKey: remoteOrg, + } + + newChannel := &Channel{ + sockets: channel.NewSockets(), + inbox: box, + channelID: localFedChannel, + hub: fakeHub, + log: nolog, + localOrganizerPk: organizerKeypair.publicKey, + remoteOrganizations: remoteOrgs, + } + + newChannel.registry = newChannel.NewFederationRegistry() + + publicKeyBytes, err := organizerKeypair.public.MarshalBinary() + require.NoError(t, err) + //signedPublicKey, err := schnorr.Sign(crypto.Suite, remoteOrganizerKeypair.private, publicKeyBytes) + require.NoError(t, err) + + challengeFile := filepath.Join(relativeMsgDataExamplePath, + "federation_challenge", + "federation_challenge.json") + challengeBytes, err := os.ReadFile(challengeFile) + challengeBase64 := base64.URLEncoding.EncodeToString(challengeBytes) + require.NoError(t, err) + + //signedPublicKeyBase64 := base64.URLEncoding.EncodeToString(signedPublicKey) + signedChallengeBytes, err := schnorr.Sign(crypto.Suite, remoteOrganizerKeypair.private, challengeBytes) + require.NoError(t, err) + signedChallengeBase64 := base64.URLEncoding.EncodeToString(signedChallengeBytes) + + federationResultData := messagedata.FederationResult{ + Object: messagedata.FederationObject, + Action: messagedata.FederationActionResult, + Status: "success", + PublicKey: base64.URLEncoding.EncodeToString(publicKeyBytes), + ChallengeMsg: message.Message{ + Data: challengeBase64, + Sender: remoteOrganizerKeypair.publicKey, + Signature: signedChallengeBase64, + MessageID: messagedata.Hash(challengeBase64, signedChallengeBase64), + WitnessSignatures: []message.WitnessSignature{}, + }, + } + resultMsg := generateMessage(t, organizerKeypair, federationResultData) + publishMsg := generatePublish(t, localFedChannel, resultMsg) + socket := &fakeSocket{id: "sockSocket"} + + err = newChannel.Publish(publishMsg, socket) + require.NoError(t, err) +} + // ----------------------------------------------------------------------------- // Utility functions diff --git a/be1-go/message/messagedata/federation_challenge.go b/be1-go/message/messagedata/federation_challenge.go index af9909651f..1bf6a36db8 100644 --- a/be1-go/message/messagedata/federation_challenge.go +++ b/be1-go/message/messagedata/federation_challenge.go @@ -6,16 +6,15 @@ type FederationChallenge struct { Action string `json:"action"` // Value is a 32 bytes array encoded in hexadecimal - Value string `json:"value"` - // Timestamp is a Unix timestamp - Timestamp int64 `json:"timestamp"` -} - -type Challenge struct { Value string `json:"value"` - ValidUntil int64 `json:"valid_until"` + ValidUntil int64 `json:"timestamp"` } +//type Challenge struct { +// Value string `json:"value"` +// ValidUntil int64 `json:"valid_until"` +//} + // GetObject implements MessageData func (FederationChallenge) GetObject() string { return FederationObject diff --git a/be1-go/message/messagedata/federation_expect.json.go b/be1-go/message/messagedata/federation_expect.go similarity index 66% rename from be1-go/message/messagedata/federation_expect.json.go rename to be1-go/message/messagedata/federation_expect.go index f56bb4023d..7e909c62f3 100644 --- a/be1-go/message/messagedata/federation_expect.json.go +++ b/be1-go/message/messagedata/federation_expect.go @@ -1,14 +1,16 @@ package messagedata +import "popstellar/message/query/method/message" + // FederationExpect defines a message data type FederationExpect struct { Object string `json:"object"` Action string `json:"action"` - LaoId string `json:"lao_id"` - ServerAddress string `json:"server_address"` - PublicKey string `json:"public_key"` - Challenge Challenge `json:"challenge"` + LaoId string `json:"lao_id"` + ServerAddress string `json:"server_address"` + PublicKey string `json:"public_key"` + ChallengeMsg message.Message `json:"challenge"` } // GetObject implements MessageData diff --git a/be1-go/message/messagedata/federation_result.go b/be1-go/message/messagedata/federation_result.go new file mode 100644 index 0000000000..88a5987678 --- /dev/null +++ b/be1-go/message/messagedata/federation_result.go @@ -0,0 +1,30 @@ +package messagedata + +import "popstellar/message/query/method/message" + +// FederationResult defines a message data +type FederationResult struct { + Object string `json:"object"` + Action string `json:"action"` + Status string `json:"status"` + + Reason string `json:"reason,omitempty"` + + PublicKey string `json:"public_key,omitempty"` + ChallengeMsg message.Message `json:"challenge"` +} + +// GetObject implements MessageData +func (FederationResult) GetObject() string { + return FederationObject +} + +// GetAction implements MessageData +func (FederationResult) GetAction() string { + return FederationActionResult +} + +// NewEmpty implements MessageData +func (FederationResult) NewEmpty() MessageData { + return &FederationResult{} +} diff --git a/be1-go/message/messagedata/mod.go b/be1-go/message/messagedata/mod.go index b836ecbdb1..7fbc82e939 100644 --- a/be1-go/message/messagedata/mod.go +++ b/be1-go/message/messagedata/mod.go @@ -54,6 +54,7 @@ const ( FederationActionChallenge = "challenge" FederationActionInit = "init" FederationActionExpect = "expect" + FederationActionResult = "result" ChirpObject = "chirp" ChirpActionAdd = "add" diff --git a/protocol/examples/messageData/federation_expect/federation_expect.json b/protocol/examples/messageData/federation_expect/federation_expect.json index 4d09f9a06b..159c608a2d 100644 --- a/protocol/examples/messageData/federation_expect/federation_expect.json +++ b/protocol/examples/messageData/federation_expect/federation_expect.json @@ -5,7 +5,10 @@ "public_key": "UvViTxoKsB3XVP_ctkmOKCJpMWb7fCzrcb1XDmhNe7Q=", "server_address": "wss://ethz.ch:9000/server", "challenge": { - "value": "82eadde2a4ba832518b90bb93c8480ee1ae16a91d5efe9281e91e2ec11da03e4", - "valid_until": 1712854874 + "data": "eyJvYmplY3QiOiJmZWRlcmF0aW9uIiwiYWN0aW9uIjoiY2hhbGxlbmdlIiwidmFsdWUiOiI4MmVhZGRlMmE0YmE4MzI1MThiOTBiYjkzYzg0ODBlZTFhZTE2YTkxZDVlZmU5MjgxZTkxZTJlYzExZGEwM2U0IiwidmFsaWRfdW50aWwiOjE3MTI4NTQ4NzR9", + "sender": "zXgzQaa_NpUe-v0Zk_4q8k184ohQ5nTQhBDKgncHzq4=", + "signature": "BILYwYkT5tOBL4rCD7yvhBkhAYqRXOI3ajQ2uJ1gAk-g6nRc38vMMnlHShuNCQ3dQFXYZPn37cCFelhWGjY8Bg==", + "message_id": "sD_PdryBuOr14_65h8L-e1lzdQpDWxUAngtu1uwqgEI=", + "witness_signatures": [] } -} \ No newline at end of file +} diff --git a/protocol/examples/messageData/federation_result/federation_result.json b/protocol/examples/messageData/federation_result/federation_result.json new file mode 100644 index 0000000000..4682e9442b --- /dev/null +++ b/protocol/examples/messageData/federation_result/federation_result.json @@ -0,0 +1,13 @@ +{ + "object": "federation", + "action": "result", + "status": "success", + "public_key": "UvViTxoKsB3XVP_ctkmOKCJpMWb7fCzrcb1XDmhNe7Q=", + "challenge": { + "data": "eyJvYmplY3QiOiJmZWRlcmF0aW9uIiwiYWN0aW9uIjoiY2hhbGxlbmdlIiwidmFsdWUiOiJlYmEzZTI0ZWZjZDBiNTNmYTY5OTA4YmFkNWQxY2I2OTlkNzk4MGQ5MzEwOWRhMGIyYmZkNTAzN2MyYzg5ZWUwIiwidGltZXN0YW1wIjoxNzEzMzg1NTY4fQ==", + "sender": "zXgzQaa_NpUe-v0Zk_4q8k184ohQ5nTQhBDKgncHzq4=", + "signature": "BILYwYkT5tOBL4rCD7yvhBkhAYqRXOI3ajQ2uJ1gAk-g6nRc38vMMnlHShuNCQ3dQFXYZPn37cCFelhWGjY8Bg==", + "message_id": "sD_PdryBuOr14_65h8L-e1lzdQpDWxUAngtu1uwqgEI=", + "witness_signatures": [] + } +} diff --git a/protocol/query/method/message/data/data.json b/protocol/query/method/message/data/data.json index 0dceaba4d6..382d5eb1d0 100644 --- a/protocol/query/method/message/data/data.json +++ b/protocol/query/method/message/data/data.json @@ -64,6 +64,9 @@ { "$ref": "dataFederationChallenge.json" }, + { + "$ref": "dataFederationResult.json" + }, { "$ref": "dataWitnessMessage.json" }, diff --git a/protocol/query/method/message/data/dataFederationExpect.json b/protocol/query/method/message/data/dataFederationExpect.json index c1ce945a4d..9bd86f2bac 100644 --- a/protocol/query/method/message/data/dataFederationExpect.json +++ b/protocol/query/method/message/data/dataFederationExpect.json @@ -26,22 +26,8 @@ "$comment": "public key of the remote organizer" }, "challenge": { - "type": "object", - "properties": { - "value": { - "type": "string", - "contentEncoding": "hex", - "pattern": "^[0-9a-fA-F]{64}$", - "$comment": "A 32 bytes array encoded in hexadecimal" - }, - "valid_until": { - "type": "integer", - "description": "[Timestamp] of the expiration time", - "minimum": 0 - } - }, - "additionalProperties": false, - "required": ["value", "valid_until"] + "$ref": "../message.json", + "$comment": "message/message containing a FederationChallenge data" } }, "additionalProperties": false, @@ -53,4 +39,4 @@ "public_key", "challenge" ] -} \ No newline at end of file +} diff --git a/protocol/query/method/message/data/dataFederationResult.json b/protocol/query/method/message/data/dataFederationResult.json new file mode 100644 index 0000000000..512f1d6f08 --- /dev/null +++ b/protocol/query/method/message/data/dataFederationResult.json @@ -0,0 +1,73 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/dedis/popstellar/master/protocol/query/method/message/data/dataFederationResult.json", + "description": "Sent by an server to a remote server, to inform them about the result of the authentication procedure", + "type": "object", + "oneOf": [ + { + "type": "object", + "properties": { + "object": { + "const": "federation" + }, + "action": { + "const": "result" + }, + "status": { + "type": "string", + "pattern": "^failure$", + "$comment": "status of the authentication attempt" + }, + "reason": { + "type": "string", + "$comment": "to be used in failures, describing the error that happened" + }, + "challenge": { + "$ref": "../message.json", + "$comment": "message/message containing a FederationChallenge data" + } + }, + "additionalProperties": false, + "required": [ + "object", + "action", + "status", + "reason", + "challenge" + ] + }, + { + "type": "object", + "properties": { + "object": { + "const": "federation" + }, + "action": { + "const": "result" + }, + "status": { + "type": "string", + "pattern": "^success$", + "$comment": "status of the authentication attempt" + }, + "public_key": { + "type": "string", + "contentEncoding": "base64", + "$comment": "public key of the remote organizer" + }, + "challenge": { + "$ref": "../message.json", + "$comment": "message/message containing a FederationChallenge data" + } + }, + "additionalProperties": false, + "required": [ + "object", + "action", + "status", + "public_key", + "challenge" + ] + } + ] +} diff --git a/protocol/test/main.js b/protocol/test/main.js index 3075c2f29b..6a918a1b43 100644 --- a/protocol/test/main.js +++ b/protocol/test/main.js @@ -43,6 +43,7 @@ const message_data_federation_init_schema = require("../query/method/message/dat const message_data_federation_expect_schema = require("../query/method/message/data/dataFederationExpect.json") const message_data_federation_challenge_request_schema = require("../query/method/message/data/dataFederationChallengeRequest.json") const message_data_federation_challenge_schema = require("../query/method/message/data/dataFederationChallenge.json") +const message_data_federation_result_schema = require("../query/method/message/data/dataFederationResult.json") const message_data_chirp_add_schema = require("../query/method/message/data/dataAddChirp.json"); const message_data_chirp_notify_add_schema = require("../query/method/message/data/dataNotifyAddChirp.json"); @@ -112,6 +113,7 @@ ajv.addSchema([ message_data_federation_expect_schema, message_data_federation_challenge_request_schema, message_data_federation_challenge_schema, + message_data_federation_result_schema, message_data_chirp_notify_add_schema, message_data_chirp_add_schema, diff --git a/protocol/test/main.test.js b/protocol/test/main.test.js index 6ef0d13286..728da8d012 100644 --- a/protocol/test/main.test.js +++ b/protocol/test/main.test.js @@ -6,6 +6,7 @@ const ajv = require("./main"); const rootSchema = "https://raw.githubusercontent.com/dedis/popstellar/master/protocol/jsonRPC.json"; + const messageDataSchema = "https://raw.githubusercontent.com/dedis/popstellar/master/protocol/query/method/message/data/data.json"; @@ -263,6 +264,9 @@ test("message data: federation", () => { federation_challenge = require("../examples/messageData/federation_challenge/federation_challenge.json"); expect(federation_challenge).toBeValid(messageDataSchema); + federation_result = require("../examples/messageData/federation_result/federation_result.json"); + expect(federation_result).toBeValid(messageDataSchema); + }); test("message data: chirp", () => {