diff --git a/.travis.yml b/.travis.yml index cd14def..3350e94 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: go go: -- 1.10.2 +- 1.11.2 before_install: - sudo pip install codecov install: diff --git a/README.md b/README.md index ebe8957..7b3787f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ go-iap ====== -![](https://img.shields.io/badge/golang-1.10-blue.svg?style=flat) +![](https://img.shields.io/badge/golang-1.11-blue.svg?style=flat) [![Build Status](https://travis-ci.org/awa/go-iap.svg?branch=master)](https://travis-ci.org/awa/go-iap) [![codecov.io](https://codecov.io/github/awa/go-iap/coverage.svg?branch=master)](https://codecov.io/github/awa/go-iap?branch=master) diff --git a/appstore/model_test.go b/appstore/model_test.go index 8b0fb5e..9dec6d2 100644 --- a/appstore/model_test.go +++ b/appstore/model_test.go @@ -33,7 +33,7 @@ func TestNumericString_UnmarshalJSON(t *testing.T) { { name: "object case", in: []byte("{\"ID\":{\"Num\": 8080}}"), - err: errors.New("json: cannot unmarshal object into Go struct field foo.ID of type json.Number"), + err: errors.New("json: cannot unmarshal object into Go value of type json.Number"), out: foo{}, }, } diff --git a/playstore/validator_test.go b/playstore/validator_test.go index 2460f50..1f50452 100644 --- a/playstore/validator_test.go +++ b/playstore/validator_test.go @@ -33,8 +33,9 @@ func init() { func TestNew(t *testing.T) { t.Parallel() + // Exception scenario - expected := "oauth2: cannot fetch token: 401 Unauthorized\nResponse: {\n \"error\" : \"invalid_client\",\n \"error_description\" : \"The OAuth client was invalid.\"\n}" + expected := "oauth2: cannot fetch token: 400 Bad Request\nResponse: {\n \"error\": \"invalid_grant\",\n \"error_description\": \"Invalid issuer: Not a service account.\"\n}" actual, _ := New(dummyKey) val := actual.httpCli.Transport.(*oauth2.Transport) @@ -196,54 +197,83 @@ func TestRevokeSubscription(t *testing.T) { func TestVerifySignature(t *testing.T) { t.Parallel() - receipt := `{"orderId":"GPA.xxxx-xxxx-xxxx-xxxxx","packageName":"my.package","productId":"myproduct","purchaseTime":1437564796303,"purchaseState":0,"developerPayload":"user001","purchaseToken":"some-token"}` + receipt := []byte(`{"orderId":"GPA.xxxx-xxxx-xxxx-xxxxx","packageName":"my.package","productId":"myproduct","purchaseTime":1437564796303,"purchaseState":0,"developerPayload":"user001","purchaseToken":"some-token"}`) - // when public key format is invalid base64 - pubkey := "dummy_public_key" - sig := "gj0N8LANKXOw4OhWkS1UZmDVUxM1UIP28F6bDzEp7BCqcVAe0DuDxmAY5wXdEgMRx/VM1Nl2crjogeV60OqCsbIaWqS/ZJwdP127aKR0jk8sbX36ssyYZ0DdZdBdCr1tBZ/eSW1GlGuD/CgVaxns0JaWecXakgoV7j+RF2AFbS4=" - expectedStr := "failed to decode public key" - _, err := VerifySignature(pubkey, []byte(receipt), sig) - if err.Error() != expectedStr { - t.Errorf("got %v\nwant %v", err, expectedStr) + type in struct { + pubkey string + receipt []byte + sig string } - // when pub key is not rsa public key - pubkey = "JTbngOdvBE0rfdOs3GeuBnPB+YEP1w/peM4VJbnVz+hN9Td25vPjAznX9YKTGQN4iDohZ07wtl+zYygIcpSCc2ozNZUs9pV0s5itayQo22aT5myJrQmkp94ZSGI2npDP4+FE6ZiF+7khl3qoE0rVZq4G2mfk5LIIyTPTSA4UvyQ=" - sig = "gj0N8LANKXOw4OhWkS1UZmDVUxM1UIP28F6bDzEp7BCqcVAe0DuDxmAY5wXdEgMRx/VM1Nl2crjogeV60OqCsbIaWqS/ZJwdP127aKR0jk8sbX36ssyYZ0DdZdBdCr1tBZ/eSW1GlGuD/CgVaxns0JaWecXakgoV7j+RF2AFbS4=" - expectedStr = "failed to parse public key" - _, err = VerifySignature(pubkey, []byte(receipt), sig) - if err.Error() != expectedStr { - t.Errorf("got %v\nwant %v", err, expectedStr) + tests := []struct { + name string + in in + err error + valid bool + }{ + { + name: "public key is invalid base64 format", + in: in{ + pubkey: "dummy_public_key", + receipt: receipt, + sig: "gj0N8LANKXOw4OhWkS1UZmDVUxM1UIP28F6bDzEp7BCqcVAe0DuDxmAY5wXdEgMRx/VM1Nl2crjogeV60OqCsbIaWqS/ZJwdP127aKR0jk8sbX36ssyYZ0DdZdBdCr1tBZ/eSW1GlGuD/CgVaxns0JaWecXakgoV7j+RF2AFbS4=", + }, + err: errors.New("failed to decode public key"), + valid: false, + }, + { + name: "public key is not rsa public key", + in: in{ + pubkey: "JTbngOdvBE0rfdOs3GeuBnPB+YEP1w/peM4VJbnVz+hN9Td25vPjAznX9YKTGQN4iDohZ07wtl+zYygIcpSCc2ozNZUs9pV0s5itayQo22aT5myJrQmkp94ZSGI2npDP4+FE6ZiF+7khl3qoE0rVZq4G2mfk5LIIyTPTSA4UvyQ=", + receipt: receipt, + sig: "gj0N8LANKXOw4OhWkS1UZmDVUxM1UIP28F6bDzEp7BCqcVAe0DuDxmAY5wXdEgMRx/VM1Nl2crjogeV60OqCsbIaWqS/ZJwdP127aKR0jk8sbX36ssyYZ0DdZdBdCr1tBZ/eSW1GlGuD/CgVaxns0JaWecXakgoV7j+RF2AFbS4=", + }, + err: errors.New("failed to parse public key"), + valid: false, + }, + { + name: "signature is invalid base64 format", + in: in{ + pubkey: "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGvModvVUrqJ9C5fy8J77ZQ7JDC6+tf5iK8C74/3mjmcvwo4nmprCgzR/BQIEuZWJi8KX+jiJUXKXF90JPsXHkKAPq6A1SCga7kWvs/M8srMpjNS9zJdwZF+eDOR0+lJEihO04zlpAV9ybPJ3Q621y1HUeVpwdxDNLQpJTuIflnwIDAQAB", + receipt: receipt, + sig: "invalid_signature", + }, + err: errors.New("failed to decode signature"), + valid: false, + }, + { + name: "signature is invalid", + in: in{ + pubkey: "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGvModvVUrqJ9C5fy8J77ZQ7JDC6+tf5iK8C74/3mjmcvwo4nmprCgzR/BQIEuZWJi8KX+jiJUXKXF90JPsXHkKAPq6A1SCga7kWvs/M8srMpjNS9zJdwZF+eDOR0+lJEihO04zlpAV9ybPJ3Q621y1HUeVpwdxDNLQpJTuIflnwIDAQAB", + receipt: receipt, + sig: "JTbngOdvBE0rfdOs3GeuBnPB+YEP1w/peM4VJbnVz+hN9Td25vPjAznX9YKTGQN4iDohZ07wtl+zYygIcpSCc2ozNZUs9pV0s5itayQo22aT5myJrQmkp94ZSGI2npDP4+FE6ZiF+7khl3qoE0rVZq4G2mfk5LIIyTPTSA4UvyQ=", + }, + err: nil, + valid: false, + }, + { + name: "normal", + in: in{ + pubkey: "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGvModvVUrqJ9C5fy8J77ZQ7JDC6+tf5iK8C74/3mjmcvwo4nmprCgzR/BQIEuZWJi8KX+jiJUXKXF90JPsXHkKAPq6A1SCga7kWvs/M8srMpjNS9zJdwZF+eDOR0+lJEihO04zlpAV9ybPJ3Q621y1HUeVpwdxDNLQpJTuIflnwIDAQAB", + receipt: receipt, + sig: "gj0N8LANKXOw4OhWkS1UZmDVUxM1UIP28F6bDzEp7BCqcVAe0DuDxmAY5wXdEgMRx/VM1Nl2crjogeV60OqCsbIaWqS/ZJwdP127aKR0jk8sbX36ssyYZ0DdZdBdCr1tBZ/eSW1GlGuD/CgVaxns0JaWecXakgoV7j+RF2AFbS4=", + }, + err: nil, + valid: true, + }, } - // when signature is invalid base64 format - pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGvModvVUrqJ9C5fy8J77ZQ7JDC6+tf5iK8C74/3mjmcvwo4nmprCgzR/BQIEuZWJi8KX+jiJUXKXF90JPsXHkKAPq6A1SCga7kWvs/M8srMpjNS9zJdwZF+eDOR0+lJEihO04zlpAV9ybPJ3Q621y1HUeVpwdxDNLQpJTuIflnwIDAQAB" - sig = "invalid_signature" - expectedStr = "failed to decode signature" - _, err = VerifySignature(pubkey, []byte(receipt), sig) - if err.Error() != expectedStr { - t.Errorf("got %v\nwant %v", err, expectedStr) - } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + valid, err := VerifySignature(tt.in.pubkey, tt.in.receipt, tt.in.sig) - // when signature is invalid - pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGvModvVUrqJ9C5fy8J77ZQ7JDC6+tf5iK8C74/3mjmcvwo4nmprCgzR/BQIEuZWJi8KX+jiJUXKXF90JPsXHkKAPq6A1SCga7kWvs/M8srMpjNS9zJdwZF+eDOR0+lJEihO04zlpAV9ybPJ3Q621y1HUeVpwdxDNLQpJTuIflnwIDAQAB" - sig = "JTbngOdvBE0rfdOs3GeuBnPB+YEP1w/peM4VJbnVz+hN9Td25vPjAznX9YKTGQN4iDohZ07wtl+zYygIcpSCc2ozNZUs9pV0s5itayQo22aT5myJrQmkp94ZSGI2npDP4+FE6ZiF+7khl3qoE0rVZq4G2mfk5LIIyTPTSA4UvyQ=" - isValid, err := VerifySignature(pubkey, []byte(receipt), sig) - if err != nil { - t.Errorf("got %v\n", err) - } - if isValid { - t.Errorf("got %v\nwant %v", isValid, false) - } + if valid != tt.valid { + t.Errorf("input: %v\nget: %t\nwant: %t\n", tt.in, valid, tt.valid) + } - // when all arguments are valid - pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGvModvVUrqJ9C5fy8J77ZQ7JDC6+tf5iK8C74/3mjmcvwo4nmprCgzR/BQIEuZWJi8KX+jiJUXKXF90JPsXHkKAPq6A1SCga7kWvs/M8srMpjNS9zJdwZF+eDOR0+lJEihO04zlpAV9ybPJ3Q621y1HUeVpwdxDNLQpJTuIflnwIDAQAB" - sig = "gj0N8LANKXOw4OhWkS1UZmDVUxM1UIP28F6bDzEp7BCqcVAe0DuDxmAY5wXdEgMRx/VM1Nl2crjogeV60OqCsbIaWqS/ZJwdP127aKR0jk8sbX36ssyYZ0DdZdBdCr1tBZ/eSW1GlGuD/CgVaxns0JaWecXakgoV7j+RF2AFbS4=" - isValid, err = VerifySignature(pubkey, []byte(receipt), sig) - if err != nil { - t.Errorf("got %v\n", err) - } - if !isValid { - t.Errorf("got %v\nwant %v", isValid, true) + if !reflect.DeepEqual(err, tt.err) { + t.Errorf("input: %v\nget: %s\nwant: %s\n", tt.in, err, tt.err) + } + }) } }