From 01a91724a3040956eb93ab5081580355f80f5261 Mon Sep 17 00:00:00 2001 From: ffranr Date: Mon, 11 Sep 2023 14:50:41 +0100 Subject: [PATCH] tapfreighter: validate proof courier address before commencing send --- proof/courier.go | 4 ++-- tapfreighter/chain_porter.go | 9 +++++++++ tapfreighter/parcel.go | 37 ++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/proof/courier.go b/proof/courier.go index 9abc876ed..2272dd073 100644 --- a/proof/courier.go +++ b/proof/courier.go @@ -97,8 +97,8 @@ func ParseCourierAddrUrl(addr url.URL) (CourierAddr, error) { return NewHashMailCourierAddr(addr) } - return nil, fmt.Errorf("unknown courier address protocol: %v", - addr.Scheme) + return nil, fmt.Errorf("unknown courier address protocol "+ + "(consider updating tapd): %v", addr.Scheme) } // HashMailCourierAddr is a hashmail protocol specific implementation of the diff --git a/tapfreighter/chain_porter.go b/tapfreighter/chain_porter.go index 9978a3009..6859a60c8 100644 --- a/tapfreighter/chain_porter.go +++ b/tapfreighter/chain_porter.go @@ -172,6 +172,15 @@ func (p *ChainPorter) Stop() error { // RequestShipment is the main external entry point to the porter. This request // a new transfer take place. func (p *ChainPorter) RequestShipment(req Parcel) (*OutboundParcel, error) { + // Perform validation on the parcel before we continue. This is a good + // point to perform validation because it is at the external entry point + // to the porter. We will therefore catch invalid parcels before locking + // coins or broadcasting. + err := req.Validate() + if err != nil { + return nil, fmt.Errorf("failed to validate parcel: %w", err) + } + if !fn.SendOrQuit(p.exportReqs, req, p.Quit) { return nil, fmt.Errorf("ChainPorter shutting down") } diff --git a/tapfreighter/parcel.go b/tapfreighter/parcel.go index be8a29520..40058f644 100644 --- a/tapfreighter/parcel.go +++ b/tapfreighter/parcel.go @@ -107,6 +107,9 @@ type Parcel interface { // kit returns the parcel kit used for delivery. kit() *parcelKit + + // Validate validates the parcel. + Validate() error } // parcelKit is a struct that contains the channels that are used to deliver @@ -160,6 +163,28 @@ func (p *AddressParcel) kit() *parcelKit { return p.parcelKit } +// Validate validates the parcel. +func (p *AddressParcel) Validate() error { + // We need at least one address to send to in an address parcel. + if len(p.destAddrs) < 1 { + return fmt.Errorf("at least one Tap address must be " + + "specified in address parcel") + } + + for idx := range p.destAddrs { + tapAddr := p.destAddrs[idx] + + // Validate proof courier addresses. + _, err := proof.ParseCourierAddrUrl(tapAddr.ProofCourierAddr) + if err != nil { + return fmt.Errorf("invalid proof courier address: %w", + err) + } + } + + return nil +} + // PendingParcel is a parcel that has not yet completed delivery. type PendingParcel struct { *parcelKit @@ -194,6 +219,12 @@ func (p *PendingParcel) kit() *parcelKit { return p.parcelKit } +// Validate validates the parcel. +func (p *PendingParcel) Validate() error { + // A pending parcel should have already been validated. + return nil +} + // PreSignedParcel is a request to issue an asset transfer of a pre-signed // parcel. This packages a virtual transaction, the input commitment, and also // the response context. @@ -246,6 +277,12 @@ func (p *PreSignedParcel) kit() *parcelKit { return p.parcelKit } +// Validate validates the parcel. +func (p *PreSignedParcel) Validate() error { + // TODO(ffranr): Add validation where appropriate. + return nil +} + // sendPackage houses the information we need to complete a package transfer. type sendPackage struct { // SendState is the current send state of this parcel.