add new helper functions
This commit is contained in:
parent
860e50130e
commit
4d4f9c8ca0
@ -15,7 +15,7 @@ import (
|
|||||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||||
"github.com/decred/dcrd/dcrutil/v4"
|
"github.com/decred/dcrd/dcrutil/v4"
|
||||||
"github.com/decred/dcrd/wire"
|
"github.com/decred/dcrd/wire"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/decred/vspd/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func currentVoteVersion(params *chaincfg.Params) uint32 {
|
func currentVoteVersion(params *chaincfg.Params) uint32 {
|
||||||
@ -105,16 +105,22 @@ func validPolicyOption(policy string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateSignature(reqBytes []byte, commitmentAddress string, c *gin.Context) error {
|
func validateSignature(hash, commitmentAddress, signature, message string) error {
|
||||||
// Ensure a signature is provided.
|
firstErr := dcrutil.VerifyMessage(commitmentAddress, signature, message, cfg.NetParams)
|
||||||
signature := c.GetHeader("VSP-Client-Signature")
|
if firstErr != nil {
|
||||||
if signature == "" {
|
// Don't return an error straight away if sig validation fails -
|
||||||
return errors.New("no VSP-Client-Signature header")
|
// first check if we have an alternate sign address for this ticket.
|
||||||
}
|
altSigData, err := db.AltSignAddrData(hash)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("db.AltSignAddrData failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have no alternate sign address, or if validating with the
|
||||||
|
// alt sign addr fails, return an error to the client.
|
||||||
|
if altSigData == nil || dcrutil.VerifyMessage(altSigData.AltSignAddr, signature, message, cfg.NetParams) != nil {
|
||||||
|
return fmt.Errorf("bad signature")
|
||||||
|
}
|
||||||
|
|
||||||
err := dcrutil.VerifyMessage(commitmentAddress, signature, string(reqBytes), cfg.NetParams)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -141,3 +147,52 @@ func isValidTicket(tx *wire.MsgTx) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateTicketHash ensures the provided ticket hash is a valid ticket hash.
|
||||||
|
// A ticket hash should be 64 chars (MaxHashStringSize) and should parse into
|
||||||
|
// a chainhash.Hash without error.
|
||||||
|
func validateTicketHash(hash string) error {
|
||||||
|
if len(hash) != chainhash.MaxHashStringSize {
|
||||||
|
return fmt.Errorf("incorrect hash length: got %d, expected %d", len(hash), chainhash.MaxHashStringSize)
|
||||||
|
|
||||||
|
}
|
||||||
|
_, err := chainhash.NewHashFromStr(hash)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid hash: %v", err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCommitmentAddress gets the commitment address of the provided ticket hash
|
||||||
|
// from the chain.
|
||||||
|
func getCommitmentAddress(hash string, dcrdClient *rpc.DcrdRPC) (string, error) {
|
||||||
|
var commitmentAddress string
|
||||||
|
resp, err := dcrdClient.GetRawTransaction(hash)
|
||||||
|
if err != nil {
|
||||||
|
return commitmentAddress, fmt.Errorf("dcrd.GetRawTransaction for ticket failed: %v", err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
msgTx, err := decodeTransaction(resp.Hex)
|
||||||
|
if err != nil {
|
||||||
|
return commitmentAddress, fmt.Errorf("Failed to decode ticket hex: %v", err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
err = isValidTicket(msgTx)
|
||||||
|
if err != nil {
|
||||||
|
return commitmentAddress, fmt.Errorf("Invalid ticket: %w", errInvalidTicket)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := stake.AddrFromSStxPkScrCommitment(msgTx.TxOut[1].PkScript, cfg.NetParams)
|
||||||
|
if err != nil {
|
||||||
|
return commitmentAddress, fmt.Errorf("AddrFromSStxPkScrCommitment error: %v", err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
commitmentAddress = addr.String()
|
||||||
|
return commitmentAddress, nil
|
||||||
|
}
|
||||||
|
|||||||
@ -11,8 +11,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/decred/dcrd/blockchain/stake/v4"
|
|
||||||
"github.com/decred/dcrd/chaincfg/chainhash"
|
|
||||||
"github.com/decred/vspd/rpc"
|
"github.com/decred/vspd/rpc"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gin-gonic/gin/binding"
|
"github.com/gin-gonic/gin/binding"
|
||||||
@ -287,17 +285,9 @@ func vspAuth() gin.HandlerFunc {
|
|||||||
hash := request.TicketHash
|
hash := request.TicketHash
|
||||||
|
|
||||||
// Before hitting the db or any RPC, ensure this is a valid ticket hash.
|
// Before hitting the db or any RPC, ensure this is a valid ticket hash.
|
||||||
// A ticket hash should be 64 chars (MaxHashStringSize) and should parse
|
err = validateTicketHash(hash)
|
||||||
// into a chainhash.Hash without error.
|
|
||||||
if len(hash) != chainhash.MaxHashStringSize {
|
|
||||||
log.Errorf("%s: Incorrect hash length (clientIP=%s): got %d, expected %d",
|
|
||||||
funcName, c.ClientIP(), len(hash), chainhash.MaxHashStringSize)
|
|
||||||
sendErrorWithMsg("invalid ticket hash", errBadRequest, c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err = chainhash.NewHashFromStr(hash)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("%s: Invalid hash (clientIP=%s): %v", funcName, c.ClientIP(), err)
|
log.Errorf("%s: Bad request (clientIP=%s): %v", funcName, c.ClientIP(), err)
|
||||||
sendErrorWithMsg("invalid ticket hash", errBadRequest, c)
|
sendErrorWithMsg("invalid ticket hash", errBadRequest, c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -313,67 +303,44 @@ func vspAuth() gin.HandlerFunc {
|
|||||||
// If the ticket was found in the database, we already know its
|
// If the ticket was found in the database, we already know its
|
||||||
// commitment address. Otherwise we need to get it from the chain.
|
// commitment address. Otherwise we need to get it from the chain.
|
||||||
var commitmentAddress string
|
var commitmentAddress string
|
||||||
|
dcrdClient := c.MustGet(dcrdKey).(*rpc.DcrdRPC)
|
||||||
|
dcrdErr := c.MustGet(dcrdErrorKey)
|
||||||
|
if dcrdErr != nil {
|
||||||
|
log.Errorf("%s: could not get dcrd client: %v", funcName, dcrdErr.(error))
|
||||||
|
sendError(errInternalError, c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if ticketFound {
|
if ticketFound {
|
||||||
commitmentAddress = ticket.CommitmentAddress
|
commitmentAddress = ticket.CommitmentAddress
|
||||||
} else {
|
} else {
|
||||||
dcrdClient := c.MustGet(dcrdKey).(*rpc.DcrdRPC)
|
commitmentAddress, err = getCommitmentAddress(hash, dcrdClient)
|
||||||
dcrdErr := c.MustGet(dcrdErrorKey)
|
|
||||||
if dcrdErr != nil {
|
|
||||||
log.Errorf("%s: could not get dcrd client: %v", funcName, dcrdErr.(error))
|
|
||||||
sendError(errInternalError, c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := dcrdClient.GetRawTransaction(hash)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("%s: dcrd.GetRawTransaction for ticket failed (ticketHash=%s): %v", funcName, hash, err)
|
var apiErr *apiError
|
||||||
sendError(errInternalError, c)
|
if errors.Is(err, apiErr) {
|
||||||
|
sendError(errInvalidTicket, c)
|
||||||
|
} else {
|
||||||
|
sendError(errInternalError, c)
|
||||||
|
}
|
||||||
|
log.Errorf("%s: (clientIP: %s, ticketHash: %s): %v", funcName, c.ClientIP(), hash, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
msgTx, err := decodeTransaction(resp.Hex)
|
// Ensure a signature is provided.
|
||||||
if err != nil {
|
signature := c.GetHeader("VSP-Client-Signature")
|
||||||
log.Errorf("%s: Failed to decode ticket hex (ticketHash=%s): %v", funcName, ticket.Hash, err)
|
if signature == "" {
|
||||||
sendError(errInternalError, c)
|
log.Warnf("%s: Bad request (clientIP=%s): %v", funcName, c.ClientIP(), err)
|
||||||
return
|
sendErrorWithMsg("no VSP-Client-Signature header", errBadRequest, c)
|
||||||
}
|
return
|
||||||
|
|
||||||
err = isValidTicket(msgTx)
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("%s: Invalid ticket (clientIP=%s, ticketHash=%s): %v", funcName, c.ClientIP(), hash, err)
|
|
||||||
sendError(errInvalidTicket, c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
addr, err := stake.AddrFromSStxPkScrCommitment(msgTx.TxOut[1].PkScript, cfg.NetParams)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("%s: AddrFromSStxPkScrCommitment error (ticketHash=%s): %v", funcName, hash, err)
|
|
||||||
sendError(errInternalError, c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
commitmentAddress = addr.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate request signature to ensure ticket ownership.
|
// Validate request signature to ensure ticket ownership.
|
||||||
err = validateSignature(reqBytes, commitmentAddress, c)
|
err = validateSignature(hash, commitmentAddress, signature, string(reqBytes))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Don't return an error straight away if sig validation fails -
|
log.Errorf("%s: Bad signature (clientIP=%s, ticketHash=%s): %v", funcName, err)
|
||||||
// first check if we have an alternate sign address for this ticket.
|
sendError(errBadSignature, c)
|
||||||
altSigData, err := db.AltSignAddrData(hash)
|
return
|
||||||
if err != nil {
|
|
||||||
log.Errorf("%s: db.AltSignAddrData failed (ticketHash=%s): %v", funcName, hash, err)
|
|
||||||
sendError(errInternalError, c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have no alternate sign address, or if validating with the
|
|
||||||
// alt sign addr fails, return an error to the client.
|
|
||||||
if altSigData == nil || validateSignature(reqBytes, altSigData.AltSignAddr, c) != nil {
|
|
||||||
log.Warnf("%s: Bad signature (clientIP=%s, ticketHash=%s)", funcName, c.ClientIP(), hash)
|
|
||||||
sendError(errBadSignature, c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add ticket information to context so downstream handlers don't need
|
// Add ticket information to context so downstream handlers don't need
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user