Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion byoc/job_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,12 +444,22 @@ func getJobSender(ctx context.Context, node *core.LivepeerNode) (*JobSender, err
addr := ethcommon.BytesToAddress(orchReq.Address)
jobSender := &JobSender{
Addr: addr.Hex(),
Sig: "0x" + hex.EncodeToString(orchReq.Sig),
Sig: encodeJobSig(orchReq.Sig),
}

return jobSender, nil
}

// encodeJobSig hex-encodes a signature with the "0x" prefix. Returns an empty
// string for empty signatures, which can occur in offchain mode when the
// broadcaster has no Eth keystore (see core.broadcaster.Sign).
func encodeJobSig(sig []byte) string {
if len(sig) == 0 {
return ""
}
return "0x" + hex.EncodeToString(sig)
}

func genOrchestratorReq(b common.Broadcaster) (*net.OrchestratorRequest, error) {
sig, err := b.Sign([]byte(fmt.Sprintf("%v", b.Address().Hex())))
if err != nil {
Expand Down
12 changes: 12 additions & 0 deletions byoc/job_gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,3 +426,15 @@ func TestSetupGatewayJob(t *testing.T) {
assert.Error(t, err)
assert.Nil(t, gatewayJob)
}

func TestEncodeJobSig(t *testing.T) {
// Empty signatures occur in offchain mode (broadcaster has no Eth keystore).
// The encoded form must be empty so the orchestrator's hex.DecodeString
// succeeds and VerifySig short-circuits to true.
assert.Equal(t, "", encodeJobSig(nil))
assert.Equal(t, "", encodeJobSig([]byte{}))

// Non-empty signatures get the "0x" prefix.
sig := []byte{0xde, 0xad, 0xbe, 0xef}
assert.Equal(t, "0xdeadbeef", encodeJobSig(sig))
}
10 changes: 5 additions & 5 deletions byoc/job_orchestrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -594,13 +594,13 @@ func (bso *BYOCOrchestratorServer) verifyTokenCreds(ctx context.Context, tokenCr
return nil, err
}

sigHex := jobSender.Sig
if len(jobSender.Sig) > 130 {
sigHex = jobSender.Sig[2:]
}
// Strip the "0x" prefix if present. Empty Sig is valid: the gateway sends
// it in offchain mode (broadcaster has no Eth keystore); VerifySig
// short-circuits to true in that mode.
sigHex := strings.TrimPrefix(jobSender.Sig, "0x")
sigByte, err := hex.DecodeString(sigHex)
if err != nil {
clog.Errorf(ctx, "Unable to hex-decode signature", err)
clog.Errorf(ctx, "Unable to hex-decode signature err=%v", err)
return nil, errSegSig
}

Expand Down
52 changes: 52 additions & 0 deletions byoc/job_orchestrator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -969,3 +969,55 @@ func createMockJobToken(hostUrl string) *JobToken {
AvailableCapacity: 1,
}
}

func TestVerifyTokenCreds_OffchainEmptySig(t *testing.T) {
// In offchain mode the gateway sends an empty Sig (no keystore to sign
// with). The orchestrator's VerifySig short-circuits to true offchain,
// so the empty Sig must round-trip through hex.DecodeString without
// erroring.
mockJobOrch := newMockJobOrchestrator()
mockJobOrch.verifySignature = func(addr ethcommon.Address, msg string, sig []byte) bool {
return true
}
bso := &BYOCOrchestratorServer{
node: mockJobLivepeerNode(),
orch: mockJobOrch,
}

js := &JobSender{
Addr: "0x0000000000000000000000000000000000000000",
Sig: "",
}
jsBytes, _ := json.Marshal(js)
creds := base64.StdEncoding.EncodeToString(jsBytes)

got, err := bso.verifyTokenCreds(context.Background(), creds)
assert.NoError(t, err)
assert.NotNil(t, got)
assert.Equal(t, "", got.Sig)
}

func TestVerifyTokenCreds_StripsHexPrefix(t *testing.T) {
// "0x"-prefixed signatures must be accepted regardless of length.
// (Pre-fix code only stripped the prefix when len > 130, breaking
// short or empty sigs.)
mockJobOrch := newMockJobOrchestrator()
mockJobOrch.verifySignature = func(addr ethcommon.Address, msg string, sig []byte) bool {
return true
}
bso := &BYOCOrchestratorServer{
node: mockJobLivepeerNode(),
orch: mockJobOrch,
}

js := &JobSender{
Addr: "0x0000000000000000000000000000000000000000",
Sig: "0xdeadbeef",
}
jsBytes, _ := json.Marshal(js)
creds := base64.StdEncoding.EncodeToString(jsBytes)

got, err := bso.verifyTokenCreds(context.Background(), creds)
assert.NoError(t, err)
assert.NotNil(t, got)
}
Loading