Skip to content
Snippets Groups Projects
Select Git revision
  • 969c7756ab492d4fbc6e904fabb3adecb8247c3a
  • release default
  • master protected
  • hotfix/gtnNoToken
  • XX-4441
  • Jakub/rootless-CI
  • jonah/refactorProviders
  • Ace/Huawei
  • AceVentura/AccountBackup
  • hotfix/delete-error
  • waitingRoundsRewrite
  • dev
  • quantumSecure
  • hotfix/ratelimit
  • fullRateLimit
  • XX-3564/TlsCipherSuite
  • hotfix/notifications-db
  • hotfix/groupNotification
  • Project/LastMile
  • notls
  • url-repo-rename
  • v2.3.0
  • v2.2.0
  • v2.1.0
  • v2.0.0
  • v1.0.0
26 results

go.sum

Blame
  • This project manages its dependencies using Go Modules. Learn more
    broadcast.go 6.71 KiB
    ////////////////////////////////////////////////////////////////////////////////
    // Copyright © 2022 xx foundation                                             //
    //                                                                            //
    // Use of this source code is governed by a license that can be found in the  //
    // LICENSE file.                                                              //
    ////////////////////////////////////////////////////////////////////////////////
    
    package bindings
    
    import (
    	"encoding/json"
    	"github.com/pkg/errors"
    	"gitlab.com/elixxir/client/broadcast"
    	"gitlab.com/elixxir/client/cmix"
    	"gitlab.com/elixxir/client/cmix/identity/receptionID"
    	"gitlab.com/elixxir/client/cmix/rounds"
    	cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast"
    	"gitlab.com/xx_network/crypto/signature/rsa"
    	"gitlab.com/xx_network/primitives/id/ephemeral"
    )
    
    // Channel is a bindings-level struct encapsulating the broadcast.Channel client
    // object.
    type Channel struct {
    	ch broadcast.Channel
    }
    
    // ChannelDef is the bindings representation of an elixxir/crypto
    // broadcast.Channel object.
    //
    // Example JSON:
    //  {
    //    "Name": "My broadcast channel",
    //    "Description": "A broadcast channel for me to test things",
    //    "Salt": "gpUqW7N22sffMXsvPLE7BA==",
    //    "PubKey": "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1DZ0NJUUN2YkZVckJKRFpqT3Y0Y0MvUHZZdXNvQkFtUTFkb3Znb044aHRuUjA2T3F3SURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0="
    //  }
    type ChannelDef struct {
    	Name        string
    	Description string
    	Salt        []byte
    	PubKey      []byte
    }
    
    // BroadcastMessage is the bindings representation of a broadcast message.
    //
    // BroadcastMessage Example JSON:
    //  {
    // 	 "RoundID":42,
    //   "EphID":[0,0,0,0,0,0,24,61],
    //   "RoundURL":"https://dashboard.xx.network/rounds/25?xxmessenger=true",
    //   "Payload":"SGVsbG8sIGJyb2FkY2FzdCBmcmllbmRzIQ=="
    //  }
    type BroadcastMessage struct {
    	BroadcastReport
    	Payload []byte
    }
    
    // BroadcastReport is the bindings representation of the info on how a broadcast
    // message was sent
    //
    // BroadcastReport Example JSON:
    //  {
    //	 "Rounds": [25, 26, 29],
    //   "EphID":[0,0,0,0,0,0,24,61],
    //   "RoundURL":"https://dashboard.xx.network/rounds/25?xxmessenger=true"
    //  }
    type BroadcastReport struct {
    	RoundsList
    	RoundURL string
    	EphID    ephemeral.Id
    }
    
    // BroadcastListener is the public function type bindings can use to listen for
    // broadcast messages.
    //
    // Parameters:
    //  - []byte - the JSON marshalled bytes of the BroadcastMessage object, which
    //    can be passed into WaitForRoundResult to see if the broadcast succeeded.
    type BroadcastListener interface {
    	Callback([]byte, error)
    }
    
    // NewBroadcastChannel creates a bindings-layer broadcast channel and starts
    // listening for new messages.
    //
    // Parameters:
    //  - cmixId - internal ID of cmix
    //  - channelDefinition - JSON marshalled ChannelDef object
    func NewBroadcastChannel(cmixId int, channelDefinition []byte) (*Channel, error) {
    	c, err := cmixTrackerSingleton.get(cmixId)
    	if err != nil {
    		return nil, err
    	}
    
    	def := &ChannelDef{}
    	err = json.Unmarshal(channelDefinition, def)
    	if err != nil {
    		return nil, errors.WithMessage(err, "Failed to unmarshal underlying channel definition")
    	}
    
    	channelID, err := cryptoBroadcast.NewChannelID(def.Name, def.Description, def.Salt, def.PubKey)
    	if err != nil {
    		return nil, errors.WithMessage(err, "Failed to generate channel ID")
    	}
    	chanPubLoaded, err := rsa.LoadPublicKeyFromPem(def.PubKey)
    	if err != nil {
    		return nil, errors.WithMessage(err, "Failed to load public key")
    	}
    
    	ch, err := broadcast.NewBroadcastChannel(&cryptoBroadcast.Channel{
    		ReceptionID: channelID,
    		Name:        def.Name,
    		Description: def.Description,
    		Salt:        def.Salt,
    		RsaPubKey:   chanPubLoaded,
    	}, c.api.GetCmix(), c.api.GetRng())
    	if err != nil {
    		return nil, errors.WithMessage(err, "Failed to create broadcast channel client")
    	}
    
    	return &Channel{ch: ch}, nil
    }
    
    // Listen registers a BroadcastListener for a given method. This allows users to
    // handle incoming broadcast messages.
    //
    // Parameters:
    //  - l - BroadcastListener object
    //  - method - int corresponding to broadcast.Method constant, 0 for symmetric
    //    or 1 for asymmetric
    func (c *Channel) Listen(l BroadcastListener, method int) error {
    	broadcastMethod := broadcast.Method(method)
    	listen := func(payload []byte,
    		receptionID receptionID.EphemeralIdentity, round rounds.Round) {
    		l.Callback(json.Marshal(&BroadcastMessage{
    			BroadcastReport: BroadcastReport{
    				RoundsList: makeRoundsList(round.ID),
    				RoundURL:   getRoundURL(round.ID),
    				EphID:      receptionID.EphId,
    			},
    			Payload: payload,
    		}))
    	}
    	return c.ch.RegisterListener(listen, broadcastMethod)
    }
    
    // Broadcast sends a given payload over the broadcast channel using symmetric
    // broadcast.
    //
    // Returns:
    //  - []byte - the JSON marshalled bytes of the BroadcastReport object, which
    //    can be passed into Cmix.WaitForRoundResult to see if the broadcast
    //    succeeded.
    func (c *Channel) Broadcast(payload []byte) ([]byte, error) {
    	rid, eid, err := c.ch.Broadcast(payload, cmix.GetDefaultCMIXParams())
    	if err != nil {
    		return nil, err
    	}
    	return json.Marshal(BroadcastReport{
    		RoundURL:   getRoundURL(rid.ID),
    		RoundsList: makeRoundsList(rid.ID),
    		EphID:      eid,
    	})
    }
    
    // BroadcastAsymmetric sends a given payload over the broadcast channel using
    // asymmetric broadcast. This mode of encryption requires a private key.
    //
    // Returns:
    //  - []byte - the JSON marshalled bytes of the BroadcastReport object, which
    //    can be passed into WaitForRoundResult to see if the broadcast succeeded.
    func (c *Channel) BroadcastAsymmetric(payload, pk []byte) ([]byte, error) {
    	pkLoaded, err := rsa.LoadPrivateKeyFromPem(pk)
    	if err != nil {
    		return nil, err
    	}
    	rid, eid, err := c.ch.BroadcastAsymmetric(pkLoaded, payload, cmix.GetDefaultCMIXParams())
    	if err != nil {
    		return nil, err
    	}
    	return json.Marshal(BroadcastReport{
    		RoundsList: makeRoundsList(rid.ID),
    		RoundURL:   getRoundURL(rid.ID),
    		EphID:      eid,
    	})
    }
    
    // MaxPayloadSize returns the maximum possible payload size which can be
    // broadcast.
    func (c *Channel) MaxPayloadSize() int {
    	return c.ch.MaxPayloadSize()
    }
    
    // MaxAsymmetricPayloadSize returns the maximum possible payload size which can
    // be broadcast.
    func (c *Channel) MaxAsymmetricPayloadSize() int {
    	return c.ch.MaxAsymmetricPayloadSize()
    }
    
    // Get returns the result of calling json.Marshal on a ChannelDef based on the
    // underlying crypto broadcast.Channel.
    func (c *Channel) Get() ([]byte, error) {
    	def := c.ch.Get()
    	return json.Marshal(&ChannelDef{
    		Name:        def.Name,
    		Description: def.Description,
    		Salt:        def.Salt,
    		PubKey:      rsa.CreatePublicKeyPem(def.RsaPubKey),
    	})
    }
    
    // Stop stops the channel from listening for more messages.
    func (c *Channel) Stop() {
    	c.ch.Stop()
    }