diff options
| author | Teddy Wing | 2015-06-06 19:25:17 -0400 |
|---|---|---|
| committer | Teddy Wing | 2015-06-06 19:25:17 -0400 |
| commit | 1135764727f3dc525d0f674c784edbc81cc786f3 (patch) | |
| tree | 5c402c88d3a07a3cde84237ead5829bda28f3e25 /vendor/_nuts/github.com/fabioberger/coinbase-go | |
| download | New-House-on-the-Block-1135764727f3dc525d0f674c784edbc81cc786f3.tar.bz2 | |
Initial commit. Install coinbase-go.
* Use nut for vendored dependencies
* Install coinbase-go to interact with the Coinbase API
Diffstat (limited to 'vendor/_nuts/github.com/fabioberger/coinbase-go')
38 files changed, 3418 insertions, 0 deletions
diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/Authenticator.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/Authenticator.go new file mode 100644 index 0000000..f5b68ea --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/Authenticator.go @@ -0,0 +1,13 @@ +package coinbase + +import ( + "net/http" +) + +// Authenticator is an interface that objects can implement in order to act as the +// authentication mechanism for RPC requests to Coinbase +type authenticator interface { + getBaseUrl() string + getClient() *http.Client + authenticate(req *http.Request, endpoint string, params []byte) error +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/README.md b/vendor/_nuts/github.com/fabioberger/coinbase-go/README.md new file mode 100644 index 0000000..e301cf0 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/README.md @@ -0,0 +1,527 @@ +[](https://godoc.org/github.com/fabioberger/coinbase-go) + +# Coinbase Go Client Library + +An easy way to buy, send, and accept [bitcoin](http://en.wikipedia.org/wiki/Bitcoin) through the [Coinbase API](https://coinbase.com/docs/api/overview). + +This library supports both the [API key authentication method](https://coinbase.com/docs/api/overview) and OAuth. The below examples use an API key - for instructions on how to use OAuth, see [OAuth Authentication](#oauth-authentication). + +A detailed step-by-step tutorial on how to use this library can be found at [this blog](http://fabioberger.com/blog/2014/11/06/building-a-coinbase-app-in-go/). + +## Installation + +Make sure you have set the environment variable $GOPATH + +```bash +export GOPATH="path/to/your/go/folder" +``` + +Obtain the latest version of the Coinbase Go library with: + +```bash +go get github.com/fabioberger/coinbase-go +``` + +Then, add the following to your Go project: + +```go +import ( + "github.com/fabioberger/coinbase-go" +) +``` + +## Usage + +Start by [enabling an API Key on your account](https://coinbase.com/settings/api). + +Next, create an instance of the client using the `ApiKeyClient` method: + +```go +c := coinbase.ApiKeyClient(os.Getenv("COINBASE_KEY"), os.Getenv("COINBASE_SECRET")) +``` + +Notice here that we did not hard code the API key into our codebase, but set it in an environment variable instead. This is just one example, but keeping your credentials separate from your code base is a good [security practice](https://coinbase.com/docs/api/overview#security). Here is a [step-by-step guide](http://fabioberger.com/blog/2014/11/06/building-a-coinbase-app-in-go/#env) on how to add these environment variables to your shell config file. + +Now you can call methods on `c` similar to the ones described in the [API reference](https://coinbase.com/api/doc). For example: + +```go +balance, err := c.GetBalance() +if err != nil { + log.Fatal(err) +} +fmt.Printf("Balance is %f BTC", balance) +``` + +A working API key example is available in example/ApiKeyExample.go. To run it, execute: + +`go run ./example/ApiKeyExample.go` + +## Error Handling + +All errors generated at runtime will be returned to the calling client method. Any API request for which Coinbase returns an error encoded in a JSON response will be parsed and returned by the client method as a Golang error struct. Lastly, it is important to note that for HTTP requests, if the response code returned is not '200 OK', an error will be returned to the client method detailing the response code that was received. + +## Examples + +### Get user information + +```go +user, err := c.GetUser() +if err != nil { + log.Fatal(err) +} +fmt.Println(user.Name) +// 'User One' +fmt.Println(user.Email) +// 'user1@example.com' +``` + +### Check your balance + +```go +amount, err := c.GetBalance() +if err != nil { + log.Fatal(err) +} +fmt.Printf("Balance is %f BTC", amount) +// 'Balance is 24.229801 BTC' +``` + +### Send bitcoin + +`func (c Client) SendMoney(params *TransactionParams) (*transactionConfirmation, error) ` + +```go +params := &coinbase.TransactionParams{ + To: "1HHNtsSVWuJXzTZrAmq71busSKLHzgm4Wb", + Amount: "0.0026", + Notes: "Thanks for the coffee!", + } +confirmation, err := c.SendMoney(params) +if err != nil { + log.Fatal(err) +} +fmt.Println(confirmation.Transaction.Status) +// 'pending' +fmt.Println(confirmation.Transaction.Id) +// '518d8567ed3ddcd4fd000034' +``` + +The "To" parameter can also be a bitcoin address and the "Notes" parameter can be a note or description of the transaction. Descriptions are only visible on Coinbase (not on the general bitcoin network). + +You can also send money in a number of currencies (see `GetCurrencies()`). The amount will be automatically converted to the correct BTC amount using the current exchange rate. + +All possible transaction parameters are detailed below: + +```go +type TransactionParams struct { + To string + From string + Amount string + AmountString string + AmountCurrencyIso string + Notes string + UserFee string + ReferrerId string + Idem string + InstantBuy bool + OrderId string +} +``` +Note that parameters are equivalent to those of the coinbase API except in camelcase rather then with underscores between words (Golang standard). This can also be assumed for accessing return values. For detailed information on each parameter, check out the ['send_money' documentation](https://www.coinbase.com/api/doc/1.0/transactions/send_money.html) + +### Request bitcoin + +This will send an email to the recipient, requesting payment, and give them an easy way to pay. + +```go +params := &coinbase.TransactionParams{ + From: "client@example.com", //Who are you requesting Bitcoins from + Amount: "2.5", + Notes: "contractor hours in January (website redesign for 50 BTC)", +} +confirmation, err := c.RequestMoney(params) +if err != nil { + log.Fatal(err) +} +fmt.Println(confirmation.Transaction.Request) +// 'true' +fmt.Println(confirmation.Transaction.Id) +// '518d8567ed3ddcd4fd000034' + + +success, err := c.ResendRequest("501a3554f8182b2754000003") +if err != nil { + log.Fatal(err) +} +fmt.Println(success) +// 'true' + + +success, err := c.CancelRequest("501a3554f8182b2754000003") +if err != nil { + log.Fatal(err) +} +fmt.Println(success) +// 'true' + + +// From the other account: +success, err := c.CompleteRequest("501a3554f8182b2754000003") +if err != nil { + log.Fatal(err) +} +fmt.Println(success) +// 'true' +``` + +### List your current transactions + +Sorted in descending order by timestamp, 30 per page. You can pass an integer as the first param to page through results, for example `c.GetTransactions(2)` would grab the second page. + +```go +response, err := c.GetTransactions(1) +if err != nil { + log.Fatal(err) +} +fmt.Println(response.CurrentPage) +// '1' +fmt.Println(response.NumPages) +// '2' +fmt.Println(response.Transactions[0].Id) +// '5018f833f8182b129c00002f' +``` + +Transactions will always have an `id` attribute which is the primary way to identity them through the Coinbase api. They will also have a `hsh` (bitcoin hash) attribute once they've been broadcast to the network (usually within a few seconds). + +### Check bitcoin prices + +Check the buy or sell price by passing a `quantity` of bitcoin that you'd like to buy or sell. The price can be given with or without the Coinbase's fee of 1% and the bank transfer fee of $0.15. + +```go +price, err := c.GetBuyPrice(1) +if err != nil { + log.Fatal(err) +} +fmt.Println(price.Subtotal.Amount) // Subtotal does not include fees +// '303.00' +fmt.Println(price.Total.Amount) // Total includes coinbase & bank fee +// '306.18' + +price, err = c.GetSellPrice(1) +if err != nil { + log.Fatal(err) +} +fmt.Println(price.Subtotal.Amount) // Subtotal is current market price +// '9.90' +fmt.Println(price.Total.Amount) // Total is amount you will receive (after fees) +// '9.65' +``` + +### Buy or sell bitcoin + +Buying and selling bitcoin requires you to [link and verify a bank account](https://coinbase.com/payment_methods) through the web interface first. + +Then you can call `buy` or `sell` and pass a `quantity` of bitcoin you want to buy. + +On a buy, coinbase will debit your bank account and the bitcoin will arrive in your Coinbase account four business days later (this is shown as the `payoutDate` below). This is how long it takes for the bank transfer to complete and verify, although they are working on shortening this window. In some cases, they may not be able to guarantee a price, and buy requests will fail. In that case, set the second parameter (`agreeBtcAmountVaries`) to true in order to purchase bitcoin at the future market price when your money arrives. + +On a sell they will credit your bank account in a similar way and it will arrive within two business days. + + func (c Client) Buy(amount float64, agreeBtcAmountVaries bool) (*transfer, error) + +```go +transfer, err := c.Buy(1.0, true) +if err != nil { + log.Fatal(err) +} +fmt.Println(transfer.Code) +// '6H7GYLXZ' +fmt.Println(transfer.Btc.Amount) +// '1.00000000' +fmt.Println(transfer.Total.Amount) +// '$361.55' +fmt.Println(transfer.PayoutDate) +// '2013-02-01T18:00:00-08:00' (ISO 8601 format - can be parsed with time.Parse(transfer.PayoutDate, "2013-06-05T14:10:43.678Z")) +``` + +```go +transfer, err := c.Sell(1.0, true) +if err != nil { + log.Fatal(err) +} +fmt.Println(transfer.Code) +// '6H7GYLXZ' +fmt.Println(transfer.Btc.Amount) +// '1.00000000' +fmt.Println(transfer.Total.Amount) +// '$361.55' +fmt.Println(transfer.PayoutDate) +// '2013-02-01T18:00:00-08:00' (ISO 8601 format - can be parsed with time.Parse(transfer.PayoutDate, "2013-06-05T14:10:43.678Z")) +``` + +### Create a payment button + +This will create the code for a payment button (and modal window) that you can use to accept bitcoin on your website. You can read [more about payment buttons here and try a demo](https://coinbase.com/docs/merchant_tools/payment_buttons). + +The allowed ButtonParams are: + +```go +type Button struct { + Name string + PriceString string + PriceCurrencyIso string + Type string + Subscription bool + Repeat string + Style string + Text string + Description string + Custom string + CustomSecure bool + CallbackUrl string + SuccessUrl string + CancelUrl string + InfoUrl string + AutoRedirect bool + AutoRedirectSuccess bool + AutoRedirectCancel bool + VariablePrice bool + ChoosePrice bool + IncludeAddress bool + IncludeEmail bool + Price1 string + Price2 string + Price3 string + Price4 string + Price5 string +} +``` +The `custom` param will get passed through in [callbacks](https://coinbase.com/docs/merchant_tools/callbacks) to your site. The list of valid `options` [are described here](https://coinbase.com/api/doc/1.0/buttons/create.html). + +For detailed information on each parameter, check out the ['buttons' documentation](https://www.coinbase.com/api/doc/1.0/buttons/create.html) + +```go +params := &coinbase.Button{ + Name: "test", + Type: "buy_now", + Subscription: false, + PriceString: "1.23", + PriceCurrencyIso: "USD", + Custom: "Order123", + CallbackUrl: "http://www.example.com/my_custom_button_callback", + Description: "Sample Description", + Style: "custom_large", + IncludeEmail: true, + } +button, err := c.CreateButton(params) +if err != nil { + log.Fatal(err) +} +fmt.Println(button.Code) +// '93865b9cae83706ae59220c013bc0afd' +fmt.Println(button.EmbedHtml) +// '<div class=\"coinbase-button\" data-code=\"93865b9cae83706ae59220c013bc0afd\"></div><script src=\"https://coinbase.com/assets/button.js\" type=\"text/javascript\"></script>' +``` + +### Exchange rates and currency utilities + +You can fetch a list of all supported currencies and ISO codes with the `GetCurrencies()` method. + +```go +currencies, err := c.GetCurrencies() +if err != nil { + log.Fatal() +} +fmt.Println(currencies[0].Name) +// 'Afghan Afghani (AFN)' +``` + +`GetExchangeRates()` will return a list of exchange rates. + +```go +exchanges, err := c.GetExchangeRates() +if err != nil { + log.Fatal(err) +} +fmt.Println(exchanges["btc_to_cad"]) +// '117.13892' +``` + +`GetExchangeRate(from string, to string)` will return a single exchange rate + +```go +exchange, err := c.GetExchangeRate("btc", "usd") +if err != nil { + log.Fatal(err) +} +fmt.Println(exchange) +// 117.13892 +``` + +### Create a new user + +```go +user, err := c.CreateUser("test@email.com", "password") +if err != nil { + log.Fatal(err) +} +fmt.Println(user.Email) +// 'newuser@example.com' +fmt.Println(user.ReceiveAddress) +// 'mpJKwdmJKYjiyfNo26eRp4j6qGwuUUnw9x' +``` + +A receive address is returned also in case you need to send the new user a payment right away. + +### Get autocomplete contacts + +This will return a list of contacts the user has previously sent to or received from. Useful for auto completion. By default, 30 contacts are returned at a time; use the `$page` and `$limit` parameters to adjust how pagination works. + +The allowed ContactsParams are: + +```go +type ContactsParams struct { + Page int + Limit int + Query string +} +``` + +```go +params := &coinbase.ContactsParams{ + Page: 1, + Limit: 5, + Query: "user", +} +contacts, err := c.GetContacts(params) +if err != nil { + log.Fatal(err) +} +fmt.Println(strings.Join(contacts.Emails, ",")) +// 'user1@example.com, user2@example.com' +``` + +## Adding new methods + +You can see a [list of method calls here](https://github.com/fabioberger/coinbase-go/blob/master/coinbase.go) and how they are implemented. They are all wrappers around the [Coinbase JSON API](https://coinbase.com/api/doc). + +If there are any methods listed in the [API Reference](https://coinbase.com/api/doc) that don't have an explicit function name in the library, you can also call `Get`, `Post`, `Put`, or `Delete` with a `path`, `params` and holder struct for a quick implementation. Holder should be a pointer to some data structure that correctly reflects the structure of the returned JSON response. The library will attempt to unmarshal the response from the server into holder. For example: + +```go +balance := map[string]string{} // Holder struct depends on JSON format returned from API +if err := c.Get("account/balance", nil, &balance); err != nil { + log.Fatal(err) +} +fmt.Println(balance) +// map[amount:36.62800000 currency:BTC] +``` + +Or feel free to add a new wrapper method and submit a pull request. + +# OAuth Authentication + +For an indepth tutorial on how to implement OAuth Authentication, visit this [step-by-step tutorial](http://fabioberger.com/blog/2014/11/06/building-a-coinbase-app-in-go/#oauth). + +## Higher Level Overview + +To authenticate with OAuth, first create an OAuth application at [https://coinbase.com/oauth/applications](https://coinbase.com/oauth/applications). +When a user wishes to connect their Coinbase account, redirect them to a URL created with `func (o OAuth) CreateAuthorizeUrl(scope []string) string`: + +```go +o, err := coinbase.OAuthService(YOUR_CLIENT_ID, YOUR_CLIENT_SECRET, YOUR_REDIRECT_URL) +if err != nil { + log.Fatal(err) +} +scope := []string{"all",} +header("Location: " . o.CreateAuthorizeUrl(scope)); +``` + +After the user has authorized your application, they will be redirected back to the redirect URL specified above. A `code` parameter will be included - pass this into `GetTokens` to receive a set of tokens: + +```go +query := req.URL.Query() +code := query.Get("code") +tokens, err := o.GetTokens(code, "authorization_code") +if err != nil { + log.Fatal(err) +} +``` + +Store these tokens safely, and use them to make Coinbase API requests in the future. For example: + +```go +c := coinbase.OAuthClient(tokens) +amount, err := c.GetBalance() +if err != nil { + log.Fatal(err) +} +``` + +A full example implementation is available in the `example` directory. In order to run this example implementation, you will need to install the following dependency: + +```bash +go get github.com/go-martini/martini +``` + +You will also need to set your coinbase application client_id and client_secret as environment variables by adding these environment variables to your bash config file (i.e ~/.bashrc, ~/.bash_profile, etc...) and reload them: + +```bash +export COINBASE_CLIENT_ID="YOUR_CLIENT_ID" +``` +```bash +export COINBASE_CLIENT_SECRET="YOUR_CLIENT_SECRET" +``` + +```bash +source ~/.bash_profile +``` + +The last step we need to take is to generate a cert and key pair in order to run our OAuth server over SSL. To do this, run the following command from within the example directory: + +```bash +go run $(go env GOROOT)/src/pkg/crypto/tls/generate_cert.go --host="localhost" +``` + +Once you have done this, run the example: + +```bash +go run OAuthExample.go +``` + + +## Security notes + +If someone gains access to your API Key they will have complete control of your Coinbase account. This includes the abillity to send all of your bitcoins elsewhere. + +For this reason, API access is disabled on all Coinbase accounts by default. If you decide to enable API key access you should take precautions to store your API key securely in your application. How to do this is application specific, but it's something you should [research](http://programmers.stackexchange.com/questions/65601/is-it-smart-to-store-application-keys-ids-etc-directly-inside-an-application) if you have never done this before. + +## Testing + +In order to run the tests for this library, you will first need to install the Testify/Assert dependency with the following command: + + ```bash + go get github.com/stretchr/testify/assert + ``` + +Then run all tests by executing the following in your command line: + + go test . -v + + +For environment specific test use : + +Endpoint(Live) : + + go test . -v -test.run=TestEndpoint + +Sandbox : + + go test . -v -test.run=TestSandbox + +Mock : + + go test . -v -test.run=TestMock + + + + diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/api_key_authentication.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/api_key_authentication.go new file mode 100644 index 0000000..534e2dd --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/api_key_authentication.go @@ -0,0 +1,74 @@ +package coinbase + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "net/http" + "strconv" + "time" +) + +// ApiKeyAuthentication Struct implements the Authentication interface and takes +// care of authenticating RPC requests for clients with a Key & Secret pair +type apiKeyAuthentication struct { + Key string + Secret string + BaseUrl string + Client http.Client +} + +// ApiKeyAuthWithEnv instantiates ApiKeyAuthentication with the API key & secret & environment (Live or Sandbox) +func apiKeyAuthWithEnv(key string, secret string, sandbox bool) *apiKeyAuthentication { + baseUrl := "https://api.coinbase.com/v1/" // Live Url + + // Check if should use sandbox + if sandbox { + baseUrl = "https://api.sandbox.coinbase.com/v1/" // Sandbox Url + } + a := apiKeyAuthentication{ + Key: key, + Secret: secret, + BaseUrl: baseUrl, + Client: http.Client{ + Transport: &http.Transport{ + Dial: dialTimeout, + }, + }, + } + return &a +} + +// ApiKeyAuth instantiates ApiKeyAuthentication with the API key & secret +// TODO: Maybe remove this (not sure if it would break backwards compatability) +func apiKeyAuth(key string, secret string) *apiKeyAuthentication { + return apiKeyAuthWithEnv(key, secret, false) +} + +// API Key + Secret authentication requires a request header of the HMAC SHA-256 +// signature of the "message" as well as an incrementing nonce and the API key +func (a apiKeyAuthentication) authenticate(req *http.Request, endpoint string, params []byte) error { + + nonce := strconv.FormatInt(time.Now().UTC().UnixNano(), 10) + message := nonce + endpoint + string(params) //As per Coinbase Documentation + + req.Header.Set("ACCESS_KEY", a.Key) + + h := hmac.New(sha256.New, []byte(a.Secret)) + h.Write([]byte(message)) + + signature := hex.EncodeToString(h.Sum(nil)) + + req.Header.Set("ACCESS_SIGNATURE", signature) + req.Header.Set("ACCESS_NONCE", nonce) + + return nil +} + +func (a apiKeyAuthentication) getBaseUrl() string { + return a.BaseUrl +} + +func (a apiKeyAuthentication) getClient() *http.Client { + return &a.Client +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/ca-coinbase.crt b/vendor/_nuts/github.com/fabioberger/coinbase-go/ca-coinbase.crt new file mode 100644 index 0000000..6a117f4 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/ca-coinbase.crt @@ -0,0 +1,629 @@ +## DigiCert High Assurance EV Root CA +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- + +## DigiCert Assured ID Root CA +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +## DigiCert Global Root CA +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +## DigiCert Assured ID Root G2 +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- + +## DigiCert Assured ID Root G3 +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE----- + +## DigiCert Global Root G2 +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + +## DigiCert Global Root G3 +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE----- + +## DigiCert Trusted Root G4 +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg +RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y +ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If +xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV +ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO +DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ +jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ +CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi +EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM +fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY +uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK +chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t +9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 +SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd ++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc +fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa +sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N +cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N +0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie +4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI +r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 +/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm +gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE----- + +## VeriSign Class 3 Public Primary CA - G2 +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh +c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy +MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp +emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X +DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw +FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg +UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo +YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 +MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4 +pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0 +13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID +AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk +U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i +F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY +oJ2daZH9 +-----END CERTIFICATE----- + +## VeriSign Class 3 Public Primary CA +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz +cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 +MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV +BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt +YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN +ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE +BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is +I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G +CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i +2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ +2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ +-----END CERTIFICATE----- + +## VeriSign Class 3 Primary CA - G5 +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 +nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex +t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz +SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG +BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ +rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ +NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E +BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH +BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv +MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE +p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y +5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK +WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ +4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N +hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- + +## VeriSign Class 3 Public Primary CA - G3 +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu +LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT +aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu +IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b +N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t +KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu +kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm +CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ +Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu +imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te +2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe +DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC +/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p +F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt +TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== +-----END CERTIFICATE----- + +## VeriSign Class 3 Public Primary CA - G4 +-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp +U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg +SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln +biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm +GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve +fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ +aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj +aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW +kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC +4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga +FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----END CERTIFICATE----- + +## VeriSign Class 2 Public Primary CA - G3 +-----BEGIN CERTIFICATE----- +MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy +aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s +IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp +Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV +BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp +Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu +Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g +Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt +IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU +J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO +JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY +wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o +koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN +qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E +Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe +xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u +7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU +sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI +sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP +cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q +-----END CERTIFICATE----- + +## VeriSign Class 2 Public Primary CA - G2 +-----BEGIN CERTIFICATE----- +MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns +YXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH +MjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y +aXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAe +Fw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGlj +IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx +KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjM +HiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjw +DqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cC +AwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9ji +nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX +rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn +jBJ7xUS0rg== +-----END CERTIFICATE----- + +## VeriSign Class 1 Public Primary CA +-----BEGIN CERTIFICATE----- +MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh +c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05 +NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD +VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp +bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOB +jQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO+jglr0aIguVzqKCbJF0N +H8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR +4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATAN +BgkqhkiG9w0BAQIFAAOBgQBMP7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZo +EWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5 +FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89Fx +lA== +-----END CERTIFICATE----- + +## VeriSign Class 1 Public Primary CA - G3 +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu +LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT +aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu +IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4 +nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO +8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV +ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb +PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2 +6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr +n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a +qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4 +wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3 +ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs +pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4 +E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g== +-----END CERTIFICATE----- + +## VeriSign Universal Root CA +-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB +vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W +ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 +IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y +IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh +bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF +9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH +H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H +LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN +/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT +rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw +WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs +exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 +sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ +seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz +4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ +BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR +lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 +7M2CYfE45k+XmCpajQ== +-----END CERTIFICATE----- + +## VeriSign Class 4 Public Primary CA - G3 +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu +LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT +aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu +IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1 +GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ ++mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd +U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm +NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY +ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ +ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1 +CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq +g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm +fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c +2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/ +bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== +-----END CERTIFICATE----- + +## GeoTrust Global CA +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg +R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 +9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq +fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv +iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU +1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ +bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW +MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA +ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l +uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn +Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS +tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF +PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un +hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV +5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== +-----END CERTIFICATE----- + +## GeoTrust Primary Certification Authority +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY +MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo +R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx +MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 +AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA +ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 +7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W +kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI +mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ +KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 +6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl +4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K +oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj +UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU +AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- + +## GeoTrust Primary Certification Authority – G2 +-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL +MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj +KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 +MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw +NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV +BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH +MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL +So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal +tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG +CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT +qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz +rD6ogRLQy7rQkgu2npaqBA+K +-----END CERTIFICATE----- + +## GeoTrust Primary Certification Authority – G3 +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB +mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT +MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ +BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 +BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz ++uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm +hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn +5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W +JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL +DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC +huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB +AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB +zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN +kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH +SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G +spki4cErx5z481+oghLrGREt +-----END CERTIFICATE----- + +## GeoTrust Universal CA +-----BEGIN CERTIFICATE----- +MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy +c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE +BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0 +IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV +VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8 +cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT +QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh +F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v +c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w +mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd +VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX +teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ +f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe +Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+ +nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB +/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY +MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG +9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc +aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX +IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn +ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z +uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN +Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja +QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW +koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9 +ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt +DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm +bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw= +-----END CERTIFICATE----- + +## GeoTrust Global CA2 +-----BEGIN CERTIFICATE----- +MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs +IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg +R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A +PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8 +Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL +TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL +5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7 +S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe +2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap +EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td +EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv +/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN +A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0 +abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF +I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz +4iIprn2DQKi6bA== +-----END CERTIFICATE----- + +## GeoTrust Universal CA2 +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy +c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD +VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1 +c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81 +WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG +FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq +XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL +se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb +KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd +IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73 +y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt +hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc +QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4 +Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV +HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ +KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z +dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ +L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr +Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo +ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY +T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz +GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m +1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV +OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH +6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX +QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS +-----END CERTIFICATE----- diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/client_oauth_authentication.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/client_oauth_authentication.go new file mode 100644 index 0000000..b8f924c --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/client_oauth_authentication.go @@ -0,0 +1,60 @@ +package coinbase + +import ( + "errors" + "net/http" + "time" +) + +// ClientOAuthAuthentication Struct implements the Authentication interface +// and takes care of authenticating OAuth RPC requests on behalf of a client +// (i.e GetBalance()) +type clientOAuthAuthentication struct { + Tokens *oauthTokens + BaseUrl string + Client http.Client +} + +// ClientOAuth instantiates ClientOAuthAuthentication with the client OAuth tokens +func clientOAuth(tokens *oauthTokens) *clientOAuthAuthentication { + return clientOAuthWithEnv(tokens, false) +} + +// ClientOAuthWithEnv instantiates ClientOAuthAuthentication with the client OAuth tokens and the specified environment +func clientOAuthWithEnv(tokens *oauthTokens, sandbox bool) *clientOAuthAuthentication { + baseUrl := "https://api.coinbase.com/v1/" // Live Url + + // Check if should use sandbox + if sandbox { + baseUrl = "https://api.sandbox.coinbase.com/v1/" // Sandbox Url + } + a := clientOAuthAuthentication{ + Tokens: tokens, + BaseUrl: baseUrl, + Client: http.Client{ + Transport: &http.Transport{ + Dial: dialTimeout, + }, + }, + } + return &a +} + +// Client OAuth authentication requires us to attach an unexpired OAuth token to +// the request header +func (a clientOAuthAuthentication) authenticate(req *http.Request, endpoint string, params []byte) error { + // Ensure tokens havent expired + if time.Now().UTC().Unix() > a.Tokens.ExpireTime { + return errors.New("The OAuth tokens are expired. Use refreshTokens to refresh them") + } + req.Header.Set("Authorization", "Bearer "+a.Tokens.AccessToken) + return nil +} + +func (a clientOAuthAuthentication) getBaseUrl() string { + return a.BaseUrl +} + +func (a clientOAuthAuthentication) getClient() *http.Client { + return &a.Client +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/coinbase.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/coinbase.go new file mode 100644 index 0000000..2f5fdb9 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/coinbase.go @@ -0,0 +1,460 @@ +// Coinbase-go is a convenient Go wrapper for the Coinbase API +package coinbase + +import ( + "errors" + "strconv" + "strings" +) + +// Client is the struct from which all API requests are made +type Client struct { + rpc rpc +} + +// ApiKeyClient instantiates the client with ApiKey Authentication +func ApiKeyClient(key string, secret string) Client { + c := Client{ + rpc: rpc{ + auth: apiKeyAuthWithEnv(key, secret, false), + mock: false, + }, + } + return c +} + +// ApiKeyClientSandbox instantiates the client with ApiKey Authentication for Coinbase Sandbox +func ApiKeyClientSandbox(key string, secret string) Client { + c := Client{ + rpc: rpc{ + auth: apiKeyAuthWithEnv(key, secret, true), + mock: false, + }, + } + return c +} + +// OAuthClient instantiates the client with OAuth Authentication +func OAuthClient(tokens *oauthTokens) Client { + c := Client{ + rpc: rpc{ + auth: clientOAuthWithEnv(tokens, false), + mock: false, + }, + } + return c +} + +// OAuthClientSandbox instantiates the client with OAuth Authentication for Coinbase Sandbox +func OAuthClientSandbox(tokens *oauthTokens) Client { + c := Client{ + rpc: rpc{ + auth: clientOAuthWithEnv(tokens, true), + mock: false, + }, + } + return c +} + +// ApiKeyClientTest instantiates Testing ApiKeyClient. All client methods execute +// normally except responses are returned from a test_data/ file instead of the coinbase API +func apiKeyClientTest(key string, secret string) Client { + c := ApiKeyClient(key, secret) + c.rpc.mock = true + return c +} + +// Get sends a GET request and marshals response data into holder +func (c Client) Get(path string, params interface{}, holder interface{}) error { + return c.rpc.Request("GET", path, params, &holder) +} + +// Post sends a POST request and marshals response data into holder +func (c Client) Post(path string, params interface{}, holder interface{}) error { + return c.rpc.Request("POST", path, params, &holder) +} + +// Delete sends a DELETE request and marshals response data into holder +func (c Client) Delete(path string, params interface{}, holder interface{}) error { + return c.rpc.Request("DELETE", path, params, &holder) +} + +// Put sends a PUT request and marshals response data into holder +func (c Client) Put(path string, params interface{}, holder interface{}) error { + return c.rpc.Request("PUT", path, params, &holder) +} + +// GetBalance returns current balance in BTC +func (c Client) GetBalance() (float64, error) { + balance := map[string]string{} + if err := c.Get("account/balance", nil, &balance); err != nil { + return 0.0, err + } + balanceFloat, err := strconv.ParseFloat(balance["amount"], 64) + if err != nil { + return 0, err + } + return balanceFloat, nil +} + +// GetReceiveAddress returns clients current bitcoin receive address +func (c Client) GetReceiveAddress() (string, error) { + holder := map[string]interface{}{} + if err := c.Get("account/receive_address", nil, &holder); err != nil { + return "", err + } + return holder["address"].(string), nil +} + +// GetAllAddresses returns bitcoin addresses associated with client account +func (c Client) GetAllAddresses(params *AddressesParams) (*addresses, error) { + holder := addressesHolder{} + if err := c.Get("addresses", params, &holder); err != nil { + return nil, err + } + addresses := addresses{ + paginationStats: holder.paginationStats, + } + // Remove one layer of nesting + for _, addr := range holder.Addresses { + addresses.Addresses = append(addresses.Addresses, addr.Address) + } + return &addresses, nil +} + +// GenerateReceiveAddress generates and returns a new bitcoin receive address +func (c Client) GenerateReceiveAddress(params *AddressParams) (string, error) { + holder := map[string]interface{}{} + if err := c.Post("account/generate_receive_address", params, &holder); err != nil { + return "", err + } + return holder["address"].(string), nil +} + +// SendMoney to either a bitcoin or email address +func (c Client) SendMoney(params *TransactionParams) (*transactionConfirmation, error) { + return c.transactionRequest("POST", "send_money", params) +} + +// RequestMoney from either a bitcoin or email address +func (c Client) RequestMoney(params *TransactionParams) (*transactionConfirmation, error) { + return c.transactionRequest("POST", "request_money", params) +} + +func (c Client) transactionRequest(method string, kind string, params *TransactionParams) (*transactionConfirmation, error) { + finalParams := &struct { + Transaction *TransactionParams `json:"transaction"` + }{ + Transaction: params, + } + holder := transactionHolder{} + var err error + if method == "POST" { + err = c.Post("transactions/"+kind, finalParams, &holder) + } else if method == "PUT" { + err = c.Put("transactions/"+kind, finalParams, &holder) + } + if err != nil { + return nil, err + } + if err := checkApiErrors(holder.response, kind); err != nil { + return nil, err + } + confirmation := transactionConfirmation{ + Transaction: holder.Transaction, + Transfer: holder.Transfer, + } + return &confirmation, nil +} + +// ResendRequest resends a transaction request referenced by id +func (c Client) ResendRequest(id string) (bool, error) { + holder := map[string]interface{}{} + if err := c.Put("transactions/"+id+"/resend_request", nil, &holder); err != nil { + return false, err + } + if holder["success"].(bool) { + return true, nil + } + return false, nil +} + +// CancelRequest cancels a transaction request referenced by id +func (c Client) CancelRequest(id string) (bool, error) { + holder := map[string]interface{}{} + if err := c.Delete("transactions/"+id+"/cancel_request", nil, &holder); err != nil { + return false, err + } + if holder["success"].(bool) { + return true, nil + } + return false, nil +} + +// CompleteRequest completes a money request referenced by id +func (c Client) CompleteRequest(id string) (*transactionConfirmation, error) { + return c.transactionRequest("PUT", id+"/complete_request", nil) +} + +// CreateButton gets a new payment button including EmbedHtml as a field on button struct +func (c Client) CreateButton(params *Button) (*Button, error) { + finalParams := &struct { + Button *Button `json:"button"` + }{ + Button: params, + } + holder := buttonHolder{} + if err := c.Post("buttons", finalParams, &holder); err != nil { + return nil, err + } + if err := checkApiErrors(holder.response, "CreateButton"); err != nil { + return nil, err + } + button := holder.Button + button.EmbedHtml = "<div class=\"coinbase-button\" data-code=\"" + button.Code + "\"></div><script src=\"https://coinbase.com/assets/button.js\" type=\"text/javascript\"></script>" + return &button, nil +} + +// CreateOrderFromButtonCode creates an order for a given button code +func (c Client) CreateOrderFromButtonCode(buttonCode string) (*order, error) { + holder := orderHolder{} + if err := c.Post("buttons/"+buttonCode+"/create_order", nil, &holder); err != nil { + return nil, err + } + if err := checkApiErrors(holder.response, "CreateOrderFromButtonCode"); err != nil { + return nil, err + } + return &holder.Order, nil +} + +// CreateUser creates a new user given an email and password +func (c Client) CreateUser(email string, password string) (*user, error) { + params := map[string]interface{}{ + "user[email]": email, + "user[password]": password, + } + holder := userHolder{} + if err := c.Post("users", params, &holder); err != nil { + return nil, err + } + if err := checkApiErrors(holder.response, "CreateUser"); err != nil { + return nil, err + } + return &holder.User, nil +} + +// Buy an amount of BTC and bypass rate limits by setting agreeBtcAmountVaries to true +func (c Client) Buy(amount float64, agreeBtcAmountVaries bool) (*transfer, error) { + params := map[string]interface{}{ + "qty": amount, + "agree_btc_amount_varies": agreeBtcAmountVaries, + } + holder := transferHolder{} + if err := c.Post("buys", params, &holder); err != nil { + return nil, err + } + if err := checkApiErrors(holder.response, "Buy"); err != nil { + return nil, err + } + return &holder.Transfer, nil +} + +// Sell an amount of BTC +func (c Client) Sell(amount float64) (*transfer, error) { + params := map[string]interface{}{ + "qty": amount, + } + holder := transferHolder{} + if err := c.Post("sells", params, &holder); err != nil { + return nil, err + } + if err := checkApiErrors(holder.response, "Sell"); err != nil { + return nil, err + } + return &holder.Transfer, nil +} + +// GetContacts gets a users contacts +func (c Client) GetContacts(params *ContactsParams) (*contactsHolder, error) { + holder := contactsHolder{} + if err := c.Get("contacts", params, &holder); err != nil { + return nil, err + } + for _, contact := range holder.Contacts { + if contact.Contact.Email != "" { + holder.Emails = append(holder.Emails, contact.Contact.Email) + } + } + return &holder, nil +} + +// GetCurrencies gets all currency names and ISO's +func (c Client) GetCurrencies() ([]currency, error) { + holder := [][]string{} + if err := c.Get("currencies", nil, &holder); err != nil { + return nil, err + } + finalData := []currency{} + for _, curr := range holder { + class := currency{ + Name: curr[0], + Iso: curr[1], + } + finalData = append(finalData, class) + } + return finalData, nil +} + +// GetExchangeRates gets the current exchange rates +func (c Client) GetExchangeRates() (map[string]string, error) { + holder := map[string]string{} + if err := c.Get("currencies/exchange_rates", nil, &holder); err != nil { + return nil, err + } + return holder, nil +} + +// GetExchangeRate gets the exchange rate between two specified currencies +func (c Client) GetExchangeRate(from string, to string) (float64, error) { + exchanges, err := c.GetExchangeRates() + if err != nil { + return 0.0, err + } + key := from + "_to_" + to + if exchanges[key] == "" { + return 0.0, errors.New("The exchange rate does not exist for this currency pair") + } + exchangeFloat, err := strconv.ParseFloat(exchanges[key], 64) + if err != nil { + return 0.0, err + } + return exchangeFloat, nil +} + +// GetTransactions gets transactions associated with an account +func (c Client) GetTransactions(page int) (*transactions, error) { + params := map[string]int{ + "page": page, + } + holder := transactionsHolder{} + if err := c.Get("transactions", params, &holder); err != nil { + return nil, err + } + transactions := transactions{ + paginationStats: holder.paginationStats, + } + // Remove one layer of nesting + for _, tx := range holder.Transactions { + transactions.Transactions = append(transactions.Transactions, tx.Transaction) + } + return &transactions, nil +} + +// GetOrders gets orders associated with an account +func (c Client) GetOrders(page int) (*orders, error) { + holder := ordersHolder{} + params := map[string]int{ + "page": page, + } + if err := c.Get("orders", params, &holder); err != nil { + return nil, err + } + orders := orders{ + paginationStats: holder.paginationStats, + } + // Remove one layer of nesting + for _, o := range holder.Orders { + orders.Orders = append(orders.Orders, o.Order) + } + return &orders, nil +} + +// GetTransfers get transfers associated with an account +func (c Client) GetTransfers(page int) (*transfers, error) { + params := map[string]int{ + "page": page, + } + holder := transfersHolder{} + if err := c.Get("transfers", params, &holder); err != nil { + return nil, err + } + transfers := transfers{ + paginationStats: holder.paginationStats, + } + // Remove one layer of nesting + for _, t := range holder.Transfers { + transfers.Transfers = append(transfers.Transfers, t.Transfer) + } + return &transfers, nil +} + +// GetBuyPrice gets the current BTC buy price +func (c Client) GetBuyPrice(qty int) (*pricesHolder, error) { + return c.getPrice("buy", qty) +} + +// GetSellPrice gets the current BTC sell price +func (c Client) GetSellPrice(qty int) (*pricesHolder, error) { + return c.getPrice("sell", qty) +} + +func (c Client) getPrice(kind string, qty int) (*pricesHolder, error) { + params := map[string]int{ + "qty": qty, + } + holder := pricesHolder{} + if err := c.Get("prices/"+kind, params, &holder); err != nil { + return nil, err + } + return &holder, nil +} + +// GetTransaction gets a particular transaction referenced by id +func (c Client) GetTransaction(id string) (*transaction, error) { + holder := transactionHolder{} + if err := c.Get("transactions/"+id, nil, &holder); err != nil { + return nil, err + } + if err := checkApiErrors(holder.response, "GetTransaction"); err != nil { + return nil, err + } + return &holder.Transaction, nil +} + +// GetOrder gets a particular order referenced by id +func (c Client) GetOrder(id string) (*order, error) { + holder := orderHolder{} + if err := c.Get("orders/"+id, nil, &holder); err != nil { + return nil, err + } + if err := checkApiErrors(holder.response, "GetOrder"); err != nil { + return nil, err + } + return &holder.Order, nil +} + +// GetUser gets the user associated with the authentication +func (c Client) GetUser() (*user, error) { + holder := usersHolder{} + if err := c.Get("users", nil, &holder); err != nil { + return nil, err + } + return &holder.Users[0].User, nil +} + +// checkApiErrors checks for errors returned by coinbase API JSON response +// i.e { "success": false, "errors": ["Button with code code123456 does not exist"], ...} +func checkApiErrors(resp response, method string) error { + if resp.Success == false { // Return errors received from API here + err := " in " + method + "()" + if resp.Errors != nil { + err = strings.Join(resp.Errors, ",") + err + return errors.New(err) + } + if resp.Error != "" { // Return errors received from API here + err = resp.Error + err + return errors.New(err) + } + } + return nil +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/endpoint_api_test.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/endpoint_api_test.go new file mode 100644 index 0000000..ce0e1b6 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/endpoint_api_test.go @@ -0,0 +1,151 @@ +package coinbase + +import ( + "fmt" + "log" + "os" + "testing" + + "com.teddywing/new-house-on-the-block/vendor/_nuts/github.com/stretchr/testify/assert" +) + +// Initialize the client without mock mode enabled on rpc. +// All calls hit the coinbase API and tests focus on checking +// format of the response and validity of sent requests +func initClient() Client { + return ApiKeyClient(os.Getenv("COINBASE_KEY"), os.Getenv("COINBASE_SECRET")) +} + +// About Endpoint Tests: +//All Endpoint Tests actually call the Coinbase API and check the return values +// with type assertions. This was done because of the varying specific values +// returned depending on the API Key and Secret pair used when running the tests. +// Endpoint tests do not include tests that could be run an arbitrary amount of times +// i.e buy, sell, etc... + +func TestEndpointGetBalance(t *testing.T) { + c := initClient() + amount, err := c.GetBalance() + if err != nil { + log.Fatal(err) + } + assert.IsType(t, 1.1, amount) +} + +func TestEndpointGetReceiveAddress(t *testing.T) { + t.Skip("Skipping GetReceiveAddressEndpoint in order not to create excessive amounts of receive addresses during testing.") + c := initClient() + params := &AddressParams{ + CallbackUrl: "http://www.wealthlift.com", + Label: "My Test Address", + } + address, err := c.GenerateReceiveAddress(params) + if err != nil { + log.Fatal(err) + } + assert.IsType(t, "string", address) +} + +func TestEndpointGetAllAddresses(t *testing.T) { + c := initClient() + params := &AddressesParams{ + Page: 1, + Limit: 5, + } + addresses, err := c.GetAllAddresses(params) + if err != nil { + log.Fatal(err) + } + assert.IsType(t, "string", addresses.Addresses[0].CreatedAt) + assert.IsType(t, "string", addresses.Addresses[0].Address) +} + +func TestEndpointCreateButton(t *testing.T) { + c := initClient() + params := &Button{ + Name: "test", + Type: "buy_now", + Subscription: false, + PriceString: "1.23", + PriceCurrencyIso: "USD", + Custom: "Order123", + CallbackUrl: "http://www.example.com/my_custom_button_callback", + Description: "Sample Description", + Style: "custom_large", + IncludeEmail: true, + } + data, err := c.CreateButton(params) + if err != nil { + if fmt.Sprint(err) != "You have not filled out your merchant profile. Please enter your information in the Profile section. in CreateButton()" { + log.Fatal(err) + } + t.Skip("Skip this test since user hasn't filled out their merchant profile yet.") + } + assert.IsType(t, "string", data.EmbedHtml) + assert.IsType(t, "string", data.Type) +} + +func TestEndpointGetCurrencies(t *testing.T) { + c := initClient() + data, err := c.GetCurrencies() + if err != nil { + log.Fatal() + } + assert.IsType(t, "string", data[0].Name) +} + +func TestEndpointGetExchangeRates(t *testing.T) { + c := initClient() + data, err := c.GetExchangeRates() + if err != nil { + log.Fatal(err) + } + assert.IsType(t, "string", data["btc_to_usd"]) +} + +func TestEndpointGetExchangeRate(t *testing.T) { + c := initClient() + data, err := c.GetExchangeRate("btc", "usd") + if err != nil { + log.Fatal(err) + } + assert.IsType(t, 0.0, data) +} + +func TestEndpointGetTransactions(t *testing.T) { + c := initClient() + data, err := c.GetTransactions(1) + if err != nil { + log.Fatal(err) + } + assert.IsType(t, int64(1), data.TotalCount) + assert.IsType(t, "string", data.Transactions[0].Hsh) +} + +func TestEndpointGetBuyPrice(t *testing.T) { + c := initClient() + data, err := c.GetBuyPrice(1) + if err != nil { + log.Fatal(err) + } + assert.IsType(t, "string", data.Subtotal.Currency) + assert.IsType(t, "string", data.Total.Amount) +} + +func TestEndpointGetSellPrice(t *testing.T) { + c := initClient() + data, err := c.GetSellPrice(1) + if err != nil { + log.Fatal(err) + } + assert.IsType(t, "string", data.Subtotal.Currency) + assert.IsType(t, "string", data.Total.Amount) +} + +func TestEndpointGetTransaction(t *testing.T) { + c := initClient() + _, err := c.GetTransaction("5446968682a19ab940000004") + if err != nil { + assert.IsType(t, "string", err.Error()) + } +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/example/ApiKeyExample.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/example/ApiKeyExample.go new file mode 100644 index 0000000..5830b73 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/example/ApiKeyExample.go @@ -0,0 +1,21 @@ +package main + +import ( + "fmt" + "log" + "os" + + "com.teddywing/new-house-on-the-block/vendor/_nuts/github.com/fabioberger/coinbase-go" +) + +func main() { + // Instantiate a ApiKeyClient with key and secret set at environment variables + c := coinbase.ApiKeyClient(os.Getenv("COINBASE_KEY"), os.Getenv("COINBASE_SECRET")) + + balance, err := c.GetBalance() + if err != nil { + log.Fatal(err) + } + fmt.Printf("Balance is %f BTC", balance) + +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/example/OAuthExample.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/example/OAuthExample.go new file mode 100644 index 0000000..c8697f2 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/example/OAuthExample.go @@ -0,0 +1,72 @@ +package main + +import ( + "log" + "net/http" + "os" + "strconv" + + "com.teddywing/new-house-on-the-block/vendor/_nuts/github.com/fabioberger/coinbase-go" + "com.teddywing/new-house-on-the-block/vendor/_nuts/github.com/go-martini/martini" +) + +var o *coinbase.OAuth + +func main() { + m := martini.New() + m.Use(martini.Logger()) + m.Use(martini.Recovery()) + m.Use(martini.Static("public")) + r := martini.NewRouter() + m.MapTo(r, (*martini.Routes)(nil)) + m.Action(r.Handle) + + // Instantiate OAuthService with the OAuth App Client Id & Secret from the Environment Variables + o, err := coinbase.OAuthService(os.Getenv("COINBASE_CLIENT_ID"), os.Getenv("COINBASE_CLIENT_SECRET"), "https://localhost:8443/tokens") + if err != nil { + panic(err) + return + } + + // At https://localhost:8443/ we will display an "authorize" link + r.Get("/", func() string { + authorizeUrl := o.CreateAuthorizeUrl([]string{ + "user", + "balance", + }) + link := "<a href='" + authorizeUrl + "'>authorize</a>" + return link + }) + + // AuthorizeUrl redirects to https://localhost:8443/tokens with 'code' in its + // query params. If you dont have SSL enabled, replace 'https' with 'http' + // and reload the page. If successful, the user's balance will show + r.Get("/tokens", func(res http.ResponseWriter, req *http.Request) string { + // Get the tokens given the 'code' query param + tokens, err := o.NewTokensFromRequest(req) // Will use 'code' query param from req + if err != nil { + return err.Error() + } + // instantiate the OAuthClient + c := coinbase.OAuthClient(tokens) + amount, err := c.GetBalance() + if err != nil { + return err.Error() + } + return strconv.FormatFloat(amount, 'f', 6, 64) + }) + + // HTTP + go func() { + if err := http.ListenAndServe(":8080", m); err != nil { + log.Fatal(err) + } + }() + + // HTTPS + // To generate a development cert and key, run the following from your *nix terminal: + // go run $(go env GOROOT)/src/pkg/crypto/tls/generate_cert.go --host="localhost" + if err := http.ListenAndServeTLS(":8443", "cert.pem", "key.pem", m); err != nil { + log.Fatal(err) + } +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/example/cert.pem b/vendor/_nuts/github.com/fabioberger/coinbase-go/example/cert.pem new file mode 100644 index 0000000..3bb7c24 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/example/cert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC9TCCAd+gAwIBAgIQAa1gzEkBj0oAqnmjI0uchzALBgkqhkiG9w0BAQswEjEQ +MA4GA1UEChMHQWNtZSBDbzAeFw0xNDExMDcyMTU2NThaFw0xNTExMDcyMTU2NTha +MBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCvCNMPOGV5/OCekfp7I6BOhWdnHedXE9CqiopA3yjv4Gpu2WOS0m/2Irr4 +qGTiFvh9JOZw1XrfcpPlTM5XzoP6MtV+XZP57xgt9hPhwnoAb9X0iN+j9AIkoLXi +alPhZK2poo9QVfQdoDtIUwZPrX0WmlARaf31/uLDvzKxC3uwWbvi/mebg2XnEFhA +K1uPHBXveTbN0PwCXXoOI4F7rnBsXbORNnm5sBS8c3Va0ZetG65gFRjWx/hsvGsA +9dJWyjvaPEzz0bSvVnfQxf0Yybe/sXPn+l9rXMZ+P+LmeUjmPo2KFO135PPYHSCd +BkTGNtMImDk8NdgrsvqMgSjb+sxHAgMBAAGjSzBJMA4GA1UdDwEB/wQEAwIAoDAT +BgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuCCWxv +Y2FsaG9zdDALBgkqhkiG9w0BAQsDggEBAKBf63MpQY+wmo6oH4dIHvziNwjrsOuZ +SK1d7TB0v67BcTAdKG2fX4eOfUVSVocKoki/OYqbjO7CmVDY972UQnQkN2QaEg/c +8LMX/Z3kC51xBD5y2vztpXgdPSAo6vAPWJCtNVqlRIRDuExDZwEeQ7icZo2jguD4 +GAkpbXJ4OKBXPG+iy+dMFbnEIAaKedSnFU92blrPqa1cMBb0scFli7Klxuu1eHsD +cixGtpI+cBw9X1phl2M09eAdCG618qDXqO/2d5rjcbQ+BFfQjv11HUrKbZKjd6HV +cAOvXdl6Xa8jyr/RMlk2wx1SZlsjw3NqK698VuRLBLPK7rDukxs7V1s= +-----END CERTIFICATE----- diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/example/key.pem b/vendor/_nuts/github.com/fabioberger/coinbase-go/example/key.pem new file mode 100644 index 0000000..36de1cd --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/example/key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEArwjTDzhlefzgnpH6eyOgToVnZx3nVxPQqoqKQN8o7+Bqbtlj +ktJv9iK6+Khk4hb4fSTmcNV633KT5UzOV86D+jLVfl2T+e8YLfYT4cJ6AG/V9Ijf +o/QCJKC14mpT4WStqaKPUFX0HaA7SFMGT619FppQEWn99f7iw78ysQt7sFm74v5n +m4Nl5xBYQCtbjxwV73k2zdD8Al16DiOBe65wbF2zkTZ5ubAUvHN1WtGXrRuuYBUY +1sf4bLxrAPXSVso72jxM89G0r1Z30MX9GMm3v7Fz5/pfa1zGfj/i5nlI5j6NihTt +d+Tz2B0gnQZExjbTCJg5PDXYK7L6jIEo2/rMRwIDAQABAoIBABRCrzuZyZU/QjjY +qOfMDehI5Nk4yuh3cLXs52fu7OwnS+qc2zvJhBA3oPDbfSH2irjhppL1Aw4OUzQ9 +mbzsOLajX7cK2fAaTvAzBcYiHsEiMN/nYAu4WO8ocyVMLX1vi/KQ0In6CRHM1E/g +3GAosswE/LOnUzBAWrtRzGpV6/FToK6VoSwx0MPW/9v99NIo74u35CuiPZAKyEuw +rIqH1BhTez1Mrfy88Knpxm0+bIRzvIDYyno9ZaBcTqFNI1iN53SatwM4AcU4XVzO +TJtZ2kT9pvyMqXOSA16J2hCh3GNQEBjmI28NFCZ3j6LVTZNsq5cWc55p4gaFvxgV +YsLQPwECgYEA3esqFBptLBXam739CPsh31yMKcPSMP1fkC12S5vZNeEa1kFOCGG2 +A4y6n+vq0tTU1yXvYTVWYnkdqodTE3ASsAvbfeDNzlxinupK1jaOBs8MSBJ4ELJv +OOW/cOC5v6GWlAspuc1sRhho90anTJSg+8FRN4op2k5CVJkGZY/ZE4cCgYEAyepj +SLYaT354xE3hWniEHF1bEV/mUf7WnxRpK4He2+n3wn29AGFk/u9AakmvKbeIv7hQ +ql4FzelLxRPulfGKhzMSU+b5vg6T65+xTQdn+q5etaW8azJMR/34OYPCeLFfK3m2 +v6xYCgbZ0aan2Q4TaSNv82ziMuaPKvwrf3XgMUECgYAuRnV1z7ToNn5pb4quLr/3 +dbL8morgEFW3GOPMDGmU5KXV+7Qr50QvJU9dPbKv2BWx74UlPhwPWLYo8yMNsJcV +AsP4UcJYv8cI4E5OsP2YyeADv2YuBSdQNAhhn1rcbPObV2CSEBX93+UzexYzz+Jp +3Pv0mujzTtJiFa7Rytc3TQKBgFfwdGNTpGvg2jos7SwY9vjfk+0iRk6J3fGU0yU2 +v9gps1WKq8lBodoCW5yvENHrdGyDmuZIYuDGbdCcmLnHZBz0GlRecYDcGoJxn6e7 +xQaB8Q/N6h0J3/0u2HA8OXOVVKy7quMZ7ZIYX7+WhN3c6olM/NIZJv8iOVJwV4WA +0i7BAoGBAImvMo7AWoPP2ht5F/jloaktDOAw9zqyzIpGcHAN1irGluBdthf1VkD4 +C3snqtzBs4tJukNXBVpUQwwwSRFWmOIxuDxFJmW2DmIIE+GdU3WHNGuK+/1RrK/i +H3O8n5w+fP83vevr5HOR6+esodUS+padDZYCglAkpnruBI/i63Df +-----END RSA PRIVATE KEY----- diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/holders.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/holders.go new file mode 100644 index 0000000..42979cc --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/holders.go @@ -0,0 +1,112 @@ +package coinbase + +// Holders includes all the structs used for marshaling JSON responses from the coinbase API + +// The holder used to marshal the JSON request returned in GetTokens +type tokensHolder struct { + AccessToken string `json:"access_token,omitempty"` + TokenType string `json:"token_type,omitempty"` + ExpiresIn int64 `json:"expires_in,omitempty"` + RefreshToken string `json:"refresh_token,omitempty"` + Scope string `json:"scope,omitempty"` +} + +// addressesHolder used to marshal the JSON request returned in GetAllAddresses +type addressesHolder struct { + paginationStats + Addresses []struct { + Address address `json:"address,omitempty"` + } `json:"addresses,omitempty"` +} + +// orderHolder used to marshal the JSON request returned in CreateOrderFromButtonCode and GetOrder +type orderHolder struct { + response + Order order `json:"order,omitempty"` +} + +// orderHolders used to marshal the JSON request returned in GetOrders +type ordersHolder struct { + paginationStats + Orders []struct { + Order order `json:"order,omitempty"` + } `json:"orders,omitempty"` +} + +// buttonHolder used to marshal the JSON request returned in CreateButton +type buttonHolder struct { + response + Button Button `json:"button,omitempty"` +} + +// transfersHolder used to marshal the JSON request returned in GetTransfers +type transfersHolder struct { + paginationStats + Transfers []struct { + Transfer transfer `json:"transfer,omitempty"` + } `json:"transfers,omitempty"` +} + +// transferHolder used to marshal the JSON request returned in Buy & Sell +type transferHolder struct { + response + Transfer transfer `json:"transfer,omitempty"` +} + +// pricesHolder used to marshal the JSON request returned in GetBuyPrice & GetSellPrice +type pricesHolder struct { + Subtotal amount `json:"subtotal,omitempty"` + Fees []struct { + Coinbase amount `json:"coinbase,omitempty"` + Bank amount `json:"bank,omitempty"` + } `json:"fees,omitempty"` + Total amount `json:"total,omitempty"` +} + +// usersHolder used to marshal the JSON request returned in GetUser +type usersHolder struct { + response + Users []struct { + User user `json:"user,omitempty"` + } `json:"users,omitempty"` +} + +// userHolder used to marshal the JSON request returned in CreateUser +type userHolder struct { + response + User user `json:"user,omitempty"` + Oauth oauth `json:"oauth,omitempty"` +} + +// The sub-structure of a response denominating its success and/or errors +type response struct { + Success bool `json:"success"` + Errors []string `json:"errors"` + Error string `json:"error"` +} + +// contactsHolder used to marshal the JSON request returned in GetContacts +type contactsHolder struct { + paginationStats + Contacts []contact `json:"contacts,omitempty"` + Emails []string `json:"emails,omitempty"` // Add for convenience +} + +// transactionHolder used to marshal the JSON request returned in SendMoney, RequestMoney, +// GetTransaction +type transactionHolder struct { + response + Transaction transaction `json:"transaction"` + Transfer transfer `json:"transfer"` +} + +// transactionsHolder used to marshal the JSON request returned in GetTransactions +type transactionsHolder struct { + paginationStats + CurrentUser user `json:"current_user,omitempty"` + Balance amount `json:"balance,omitempty"` + NativeBalance amount `json:"native_balance,omitempty"` + Transactions []struct { + Transaction transaction `json:"transaction,omitempty"` + } `json:"transactions,omitempty"` +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/mock_api_test.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/mock_api_test.go new file mode 100644 index 0000000..30f190f --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/mock_api_test.go @@ -0,0 +1,255 @@ +package coinbase + +import ( + "log" + "os" + "testing" +) + +// Initialize the client with mock mode enabled on rpc +// All calls return the corresponding json response from the test_data files +func initTestClient() Client { + return apiKeyClientTest(os.Getenv("COINBASE_KEY"), os.Getenv("COINBASE_SECRET")) +} + +// About Mock Tests: +// All Mock Tests simulate requests to the coinbase API by returning the expected +// return values from a file under the test_data folder. The values received from +// the file are compared with the expected value given the marshaling of the JSON +// executed correctly. + +func TestMockGetBalanceParse(t *testing.T) { + c := initTestClient() + amount, err := c.GetBalance() + if err != nil { + log.Fatal(err) + } + compareFloat(t, "GetBalanceParse", 36.62800000, amount) +} + +func TestMockGetReceiveAddressParse(t *testing.T) { + c := initTestClient() + params := &AddressParams{} + address, err := c.GenerateReceiveAddress(params) + if err != nil { + log.Fatal(err) + } + compareString(t, "GetReceiveAddressParse", "muVu2JZo8PbewBHRp6bpqFvVD87qvqEHWA", address) +} + +func TestMockGetAllAddressesParse(t *testing.T) { + c := initTestClient() + params := &AddressesParams{} + addresses, err := c.GetAllAddresses(params) + if err != nil { + log.Fatal(err) + } + compareString(t, "GetAllAddressesParse", "2013-05-09T23:07:08-07:00", addresses.Addresses[0].CreatedAt) + compareString(t, "GetAllAddressesParse", "mwigfecvyG4MZjb6R5jMbmNcs7TkzhUaCj", addresses.Addresses[1].Address) + compareInt(t, "GetAllAddressesParse", 1, int64(addresses.NumPages)) +} + +func TestMockCreateButtonParse(t *testing.T) { + c := initTestClient() + params := &Button{} + data, err := c.CreateButton(params) + if err != nil { + log.Fatal(err) + } + compareString(t, "CreateButtonParse", "93865b9cae83706ae59220c013bc0afd", data.Code) + compareString(t, "CreateButtonParse", "Sample description", data.Description) +} + +func TestMockSendMoneyParse(t *testing.T) { + c := initTestClient() + params := &TransactionParams{} + data, err := c.SendMoney(params) + if err != nil { + log.Fatal(err) + } + compareString(t, "SendMoneyParse", "-1.23400000", data.Transaction.Amount.Amount) + compareString(t, "SendMoneyParse", "37muSN5ZrukVTvyVh3mT5Zc5ew9L9CBare", data.Transaction.RecipientAddress) +} + +func TestMockRequestMoneyParse(t *testing.T) { + c := initTestClient() + params := &TransactionParams{} + data, err := c.RequestMoney(params) + if err != nil { + log.Fatal(err) + } + compareString(t, "RequestMoneyParse", "1.23400000", data.Transaction.Amount.Amount) + compareString(t, "RequestMoneyParse", "5011f33df8182b142400000e", data.Transaction.Recipient.Id) +} + +func TestMockResendRequestParse(t *testing.T) { + c := initTestClient() + data, err := c.ResendRequest("ID") + if err != nil { + log.Fatal(err) + } + compareBool(t, "ResendRequestParse", true, data) +} + +func TestMockCancelRequestParse(t *testing.T) { + c := initTestClient() + data, err := c.CancelRequest("ID") + if err != nil { + log.Fatal(err) + } + compareBool(t, "CancelRequestParse", false, data) +} + +func TestMockCompleteRequestParse(t *testing.T) { + c := initTestClient() + data, err := c.CompleteRequest("ID") + if err != nil { + log.Fatal(err) + } + compareString(t, "CancelRequestParse", "503c46a3f8182b106500009b", data.Transaction.Id) +} + +func TestMockCreateOrderFromButtonCodeParse(t *testing.T) { + c := initTestClient() + data, err := c.CreateOrderFromButtonCode("ID") + if err != nil { + log.Fatal(err) + } + compareString(t, "CreateOrderFromButtonCodeParse", "7RTTRDVP", data.Id) + compareString(t, "CreateOrderFromButtonCodeParse", "new", data.Status) +} + +func TestMockCreateUserParse(t *testing.T) { + c := initTestClient() + data, err := c.CreateUser("test@email.com", "password") + if err != nil { + log.Fatal(err) + } + compareString(t, "CreateUser", "newuser@example.com", data.Email) + compareString(t, "CreateUser", "501a3d22f8182b2754000011", data.Id) +} + +func TestMockBuyParse(t *testing.T) { + c := initTestClient() + data, err := c.Buy(1000.0, true) + if err != nil { + log.Fatal(err) + } + compareString(t, "Buys", "2013-01-28T16:08:58-08:00", data.CreatedAt) + compareString(t, "Buys", "USD", data.Fees.Bank.CurrencyIso) + compareString(t, "Buys", "13.55", data.Subtotal.Amount) +} + +func TestMockSellParse(t *testing.T) { + c := initTestClient() + data, err := c.Sell(1000.0) + if err != nil { + log.Fatal(err) + } + compareString(t, "Sells", "2013-01-28T16:32:35-08:00", data.CreatedAt) + compareString(t, "Sells", "USD", data.Fees.Bank.CurrencyIso) + compareString(t, "Sells", "13.50", data.Subtotal.Amount) +} + +func TestMockGetContactsParse(t *testing.T) { + c := initTestClient() + params := &ContactsParams{ + Page: 1, + Limit: 5, + } + data, err := c.GetContacts(params) + if err != nil { + log.Fatal(err) + } + compareString(t, "GetContacts", "user1@example.com", data.Emails[0]) +} + +func TestMockGetTransactionsParse(t *testing.T) { + c := initTestClient() + data, err := c.GetTransactions(1) + if err != nil { + log.Fatal(err) + } + compareInt(t, "GetTransactions", 2, data.TotalCount) + compareString(t, "GetTransactions", "5018f833f8182b129c00002f", data.Transactions[0].Id) + compareString(t, "GetTransactions", "-1.00000000", data.Transactions[1].Amount.Amount) +} + +func TestMockGetOrdersParse(t *testing.T) { + c := initTestClient() + data, err := c.GetOrders(1) + if err != nil { + log.Fatal(err) + } + compareString(t, "GetOrders", "buy_now", data.Orders[0].Button.Type) + compareInt(t, "GetOrders", int64(0), int64(data.Orders[0].Transaction.Confirmations)) +} + +func TestMockGetTransfersParse(t *testing.T) { + c := initTestClient() + data, err := c.GetTransfers(1) + if err != nil { + log.Fatal(err) + } + compareString(t, "GetTransfers", "BTC", data.Transfers[0].Btc.Currency) + compareInt(t, "GetTransfers", int64(1), int64(data.NumPages)) +} + +func TestMockGetTransaction(t *testing.T) { + c := initTestClient() + data, err := c.GetTransaction("ID") + if err != nil { + log.Fatal(err) + } + compareString(t, "GetTransaction", "5018f833f8182b129c00002f", data.Id) + compareString(t, "GetTransaction", "BTC", data.Amount.Currency) + compareString(t, "GetTransaction", "User One", data.Recipient.Name) +} + +func TestMockGetOrder(t *testing.T) { + c := initTestClient() + data, err := c.GetOrder("ID") + if err != nil { + log.Fatal(err) + } + compareString(t, "GetTransaction", "A7C52JQT", data.Id) + compareString(t, "GetTransaction", "BTC", data.TotalBtc.CurrencyIso) + compareString(t, "GetTransaction", "test", data.Button.Name) +} + +func TestMockGetUser(t *testing.T) { + c := initTestClient() + data, err := c.GetUser() + if err != nil { + log.Fatal(err) + } + compareString(t, "GetTransaction", "512db383f8182bd24d000001", data.Id) + compareString(t, "GetTransaction", "49.76000000", data.Balance.Amount) + compareString(t, "GetTransaction", "Company Name, Inc.", data.Merchant.CompanyName) +} + +func compareFloat(t *testing.T, prefix string, expected float64, got float64) { + if expected != got { + t.Errorf(`%s + Expected %0.32f + but got %0.32f`, prefix, expected, got) + } +} + +func compareInt(t *testing.T, prefix string, expected int64, got int64) { + if expected != got { + t.Errorf("%s Expected %d but got %d", prefix, expected, got) + } +} + +func compareString(t *testing.T, prefix string, expected string, got string) { + if expected != got { + t.Errorf("%s Expected '%s' but got '%s'", prefix, expected, got) + } +} + +func compareBool(t *testing.T, prefix string, expected bool, got bool) { + if expected != got { + t.Errorf("%s Expected '%t' but got '%t'", prefix, expected, got) + } +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/oauth.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/oauth.go new file mode 100644 index 0000000..92bda03 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/oauth.go @@ -0,0 +1,101 @@ +package coinbase + +import ( + "net/http" + "net/url" + "strings" + "time" +) + +// OAuth handles all service oauth related functionality (i.e GetTokens(), RefreshTokens() +type OAuth struct { + ClientId string + ClientSecret string + RedirectUri string + Rpc rpc +} + +// OAuthService Instantiates OAuth Struct in order to send service related OAuth requests +func OAuthService(clientId string, clientSecret string, redirectUri string) (*OAuth, error) { + certFilePath := basePath + "/ca-coinbase.crt" + serviceAuth, err := serviceOAuth(certFilePath) + if err != nil { + return nil, err + } + o := OAuth{ + ClientId: clientId, + ClientSecret: clientSecret, + RedirectUri: redirectUri, + Rpc: rpc{ + auth: serviceAuth, + mock: false, + }, + } + return &o, nil +} + +// CreateAuthorizeUrl create the Authorize Url used to redirect users for +// coinbase app authorization. The scope parameter includes the specific +// permissions one wants to ask from the user +func (o OAuth) CreateAuthorizeUrl(scope []string) string { + Url, _ := url.Parse("https://coinbase.com") + Url.Path += "/oauth/authorize" + + parameters := url.Values{} + parameters.Add("response_type", "code") + parameters.Add("client_id", o.ClientId) + parameters.Add("redirect_uri", o.RedirectUri) + parameters.Add("scope", strings.Join(scope, " ")) + Url.RawQuery = parameters.Encode() + + return Url.String() +} + +// RefreshTokens refreshes a users existing OAuth tokens +func (o OAuth) RefreshTokens(oldTokens map[string]interface{}) (*oauthTokens, error) { + refresh_token := oldTokens["refresh_token"].(string) + return o.GetTokens(refresh_token, "refresh_token") +} + +// NewTokens generates new tokens for an OAuth user +func (o OAuth) NewTokens(code string) (*oauthTokens, error) { + return o.GetTokens(code, "authorization_code") +} + +// NewTokensRequest generates new tokens for OAuth user given an http request +// containing the query parameter 'code' +func (o OAuth) NewTokensFromRequest(req *http.Request) (*oauthTokens, error) { + query := req.URL.Query() + code := query.Get("code") + return o.GetTokens(code, "authorization_code") +} + +// GetTokens gets tokens for an OAuth user specifying a grantType (i.e authorization_code) +func (o OAuth) GetTokens(code string, grantType string) (*oauthTokens, error) { + + postVars := map[string]string{ + "grant_type": grantType, + "redirect_uri": o.RedirectUri, + "client_id": o.ClientId, + "client_secret": o.ClientSecret, + } + + if grantType == "refresh_token" { + postVars["refresh_token"] = code + } else { + postVars["code"] = code + } + holder := tokensHolder{} + err := o.Rpc.Request("POST", "oauth/token", postVars, &holder) + if err != nil { + return nil, err + } + + tokens := oauthTokens{ + AccessToken: holder.AccessToken, + RefreshToken: holder.RefreshToken, + ExpireTime: time.Now().UTC().Unix() + holder.ExpiresIn, + } + + return &tokens, nil +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/params.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/params.go new file mode 100644 index 0000000..3d2db60 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/params.go @@ -0,0 +1,253 @@ +package coinbase + +// Params includes all the struct parameters that are required for specific API requests +// By defining a specific param struct, a developer can know which parameters are allowed +// for a given request. Also included here are the return object structs returned by +// specific API calls + +// Parameter Struct for GET /api/v1/addresses Requests +type AddressesParams struct { + Page int64 `json:"page,omitempty"` + Limit int64 `json:"limit,omitempty"` + AccountId string `json:"account_id,omitempty"` + Query string `json:"query,omitempty"` +} + +// Parameter Struct for POST /api/v1/account/generate_receive_address Requests +type AddressParams struct { + Label string `json:"label,omitempty"` + CallbackUrl string `json:"callback_url,omitempty"` +} + +// Parameter Struct for POST /api/v1/transactions/(request_money,send_money) Requests +type TransactionParams struct { + To string `json:"to,omitempty"` + From string `json:"from,omitempty"` + Amount string `json:"amount,omitempty"` + AmountString string `json:"amount_string,omitempty"` + AmountCurrencyIso string `json:"amount_currency_iso,omitempty"` + Notes string `json:"notes,omitempty"` + UserFee string `json:"user_fee,omitempty"` + ReferrerId string `json:"refferer_id,omitempty"` + Idem string `json:"idem,omitempty"` + InstantBuy bool `json:"instant_buy,omitempty"` + OrderId string `json:"order_id,omitempty"` +} + +// Parameter Struct for GET /api/v1/contacts Requests +type ContactsParams struct { + Page int64 `json:"page,omitempty"` + Limit int64 `json:"limit,omitempty"` + Query string `json:"query,omitempty"` +} + +// The OAuth Tokens Struct returned from OAuth Authentication +type oauthTokens struct { + AccessToken string + RefreshToken string + ExpireTime int64 +} + +// The return response from SendMoney, RequestMoney, CompleteRequest +type transactionConfirmation struct { + Transaction transaction + Transfer transfer +} + +// The return response from GetAllAddresses +type addresses struct { + paginationStats + Addresses []address +} + +// The structure for one returned address from GetAllAddresses +type address struct { + Address string `json:"address,omitempty"` + CallbackUrl string `json:"callback_url,omitempty"` + Label string `json:"label,omitempty"` + CreatedAt string `json:"created_at,omitempty"` +} + +// The sub-structure of a response denominating a currency +type currency struct { + Name string `json:"name,omitempty"` + Iso string `json:"iso,omitempty"` +} + +// The sub-structure of a response denominating a contact +type contact struct { + Contact struct { + Email string `json:"email,omitempty"` + } `json:"contact,omitempty"` +} + +// The return response from CreateButton +type Button struct { + Name string `json:"name,omitempty"` + PriceString string `json:"price_string,omitempty"` + PriceCurrencyIso string `json:"price_currency_iso,omitempty"` + Type string `json:"type,omitempty"` + Subscription bool `json:"subscription,omitempty"` + Repeat string `json:"repeat,omitempty"` + Style string `json:"style,omitempty"` + Text string `json:"text,omitempty"` + Description string `json:"description,omitempty"` + Custom string `json:"custom,omitempty"` + CustomSecure bool `json:"custom_secure,omitempty"` + CallbackUrl string `json:"callback_url,omitempty"` + SuccessUrl string `json:"success_url,omitempty"` + CancelUrl string `json:"cancel_url,omitempty"` + InfoUrl string `json:"info_url,omitempty"` + AutoRedirect bool `json:"auto_redirect,omitempty"` + AutoRedirectSuccess bool `json:"auto_redirect_success,omitempty"` + AutoRedirectCancel bool `json:"auto_redirect_cancel,omitempty"` + VariablePrice bool `json:"variable_price,omitempty"` + ChoosePrice bool `json:"choose_price,omitempty"` + IncludeAddress bool `json:"include_address,omitempty"` + IncludeEmail bool `json:"include_email,omitempty"` + Price1 string `json:"price1,omitempty"` + Price2 string `json:"price2,omitempty"` + Price3 string `json:"price3,omitempty"` + Price4 string `json:"price4,omitempty"` + Price5 string `json:"price5,omitempty"` + Code string `json:"code,omitempty"` + Price fee `json:"price,omitempty"` + Id string `json:"id,omitempty"` + EmbedHtml string `json:"embed_html"` //Added embed_html for convenience +} + +// The return response from GetUser and CreateUser +type user struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Email string `json:"email,omitempty"` + ReceiveAddress string `json:"receive_address,omitempty"` + TimeZone string `json:"timezone,omitempty"` + NativeCurrency string `json:"native_currency,omitempty"` + Balance amount `json:"balance,omitempty"` + Merchant merchant `json:"merchant,omitempty"` + BuyLevel int64 `json:"buy_level,omitempty"` + SellLevel int64 `json:"sell_level,omitempty"` + BuyLimit amount `json:"buy_limit,omitempty"` + SellLimit amount `json:"sell_limit,omitempty"` +} + +// The sub-structure of a response denominating a merchant +type merchant struct { + CompanyName string `json:"company_name,omitempty"` + Logo struct { + Small string `json:"small,omitempty"` + Medium string `json:"medium,omitempty"` + Url string `json:"url,omitempty"` + } `json:"logo,omitempty"` +} + +// The sub-structure of a response denominating the oauth data +type oauth struct { + AccessToken string `json:"access_token,omitempty"` + TokenType string `json:"token_type,omitempty"` + ExpiresIn int64 `json:"expires_in,omitempty"` + RefreshToken string `json:"refresh_token,omitempty"` + Scope string `json:"scope,omitempty"` +} + +// The sub-structure of a response denominating pagination stats +type paginationStats struct { + TotalCount int64 `json:"total_count,omitempty"` + NumPages int64 `json:"num_pages,omitempty"` + CurrentPage int64 `json:"current_page,omitempty"` +} + +// The return response from GetTransfers +type transfers struct { + paginationStats + Transfers []transfer +} + +// The sub-structure of a response denominating a transfer +type transfer struct { + Id string `json:"id,omitempty"` + Type string `json:"type,omitempty"` + Code string `json:"code,omitempty"` + CreatedAt string `json:"created_at,omitempty"` + Fees fees `json:"fees,omitempty"` + Status string `json:"status,omitempty"` + PayoutDate string `json:"payout_date,omitempty"` + Btc amount `json:"btc,omitempty"` + Subtotal amount `json:"subtotal,omitempty"` + Total amount `json:"total,omitempty"` + Description string `json:"description,omitempty"` + TransactionId string `json:"transaction_id,omitempty"` +} + +// The sub-structure of a response denominating an amount +type amount struct { + Amount string `json:"amount,omitempty"` + Currency string `json:"currency,omitempty"` +} + +// The sub-structure of a response denominating a fee +type fee struct { + Cents float64 `json:"cents,omitempty"` + CurrencyIso string `json:"currency_iso,omitempty"` +} + +// The sub-structure of a response denominating fees +type fees struct { + Coinbase fee `json:"coinbase,omitempty"` + Bank fee `json:"bank,omitempty"` +} + +// The sub-structure of a response denominating a transaction actor +type transactionActor struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Email string `json:"email,omitempty"` +} + +// The return response from GetTransactions +type transactions struct { + paginationStats + Transactions []transaction +} + +// The sub-structure of a response denominating a transaction +type transaction struct { + Id string `json:"id,omitempty"` + CreateAt string `json:"create_at,omitempty"` + Hsh string `json:"hsh,omitempty"` + Notes string `json:"notes,omitempty"` + Idem string `json:"idem,omitempty"` + Amount amount `json:"amount,omitempty"` + Request bool `json:"request,omitempty"` + Status string `json:"status,omitempty"` + Sender transactionActor `json:"sender,omitempty"` + Recipient transactionActor `json:"recipient,omitempty"` + RecipientAddress string `json:"recipient_address,omitempty"` + Type string `json:"type,omitempty"` + Signed bool `json:"signed,omitempty"` + SignaturesRequired int64 `json:"signature_required,omitempty"` + SignaturesPresent int64 `json:"signatures_present,omitempty"` + SignaturesNeeded int64 `json:"signatures_needed,omitempty"` + Hash string `json:"hash,omitempty"` + Confirmations int64 `json:"confirmations,omitempty"` +} + +// The return response from GetOrders +type orders struct { + paginationStats + Orders []order +} + +// The sub-structure of a response denominating an order +type order struct { + Id string `json:"id,omitempty"` + CreatedAt string `json:"created_at,omitempty"` + Status string `json:"status,omitempty"` + TotalBtc fee `json:"total_btc,omitempty"` + TotalNative fee `json:"total_native,omitempty"` + Custom string `json:"custom,omitempty"` + ReceiveAddress string `json:"receive_address,omitempty"` + Button Button `json:"button,omitempty"` + Transaction transaction `json:"transaction,omitempty"` +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/rpc.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/rpc.go new file mode 100644 index 0000000..2fc25e1 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/rpc.go @@ -0,0 +1,107 @@ +package coinbase + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "strings" +) + +// basePath needed for reading mock JSON files in simulateRequest and for +// referencing ca-coinbase.crt in OAuthService. Must be fixed path because +// relative path changes depending on where library called +var basePath string = os.Getenv("GOPATH") + "/src/github.com/fabioberger/coinbase-go" + +// Rpc handles the remote procedure call requests +type rpc struct { + auth authenticator + mock bool +} + +// Request sends a request with params marshaled into a JSON payload in the body +// The response value is marshaled from JSON into the specified holder struct +func (r rpc) Request(method string, endpoint string, params interface{}, holder interface{}) error { + + jsonParams, err := json.Marshal(params) + if err != nil { + return err + } + + request, err := r.createRequest(method, endpoint, jsonParams) + if err != nil { + return err + } + + var data []byte + if r.mock == true { // Mock mode: Replace actual request with expected JSON from file + data, err = r.simulateRequest(endpoint, method) + } else { + data, err = r.executeRequest(request) + } + if err != nil { + return err + } + if err := json.Unmarshal(data, &holder); err != nil { + return err + } + + return nil +} + +// CreateRequest formats a request with all the necessary headers +func (r rpc) createRequest(method string, endpoint string, params []byte) (*http.Request, error) { + + endpoint = r.auth.getBaseUrl() + endpoint //BaseUrl depends on Auth type used + + req, err := http.NewRequest(method, endpoint, bytes.NewBuffer(params)) + if err != nil { + return nil, err + } + + // Authenticate the request + r.auth.authenticate(req, endpoint, params) + + req.Header.Set("User-Agent", "CoinbaseGo/v1") + req.Header.Set("Content-Type", "application/json") + + return req, nil +} + +// executeRequest takes a prepared http.Request and returns the body of the response +// If the response is not of HTTP Code 200, an error is returned +func (r rpc) executeRequest(req *http.Request) ([]byte, error) { + resp, err := r.auth.getClient().Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + buf := new(bytes.Buffer) + buf.ReadFrom(resp.Body) + bytes := buf.Bytes() + if resp.StatusCode != 200 { + if len(bytes) == 0 { // Log response body for debugging purposes + log.Printf("Response body was empty") + } else { + log.Printf("Response body:\n\t%s\n", bytes) + } + return nil, fmt.Errorf("%s %s failed. Response code was %s", req.Method, req.URL, resp.Status) + } + return bytes, nil +} + +// simulateRequest simulates a request by returning a sample JSON from file +func (r rpc) simulateRequest(endpoint string, method string) ([]byte, error) { + // Test files conform to replacing '/' in endpoint with '_' + fileName := strings.Replace(endpoint, "/", "_", -1) + // file names also have method type prepended to ensure uniqueness + filePath := basePath + "/test_data/" + method + "_" + fileName + ".json" + data, err := ioutil.ReadFile(filePath) + if err != nil { + return nil, err + } + return data, nil +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/service_oauth_authentication.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/service_oauth_authentication.go new file mode 100644 index 0000000..a02faea --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/service_oauth_authentication.go @@ -0,0 +1,54 @@ +package coinbase + +import ( + "crypto/tls" + "crypto/x509" + "io/ioutil" + "net/http" +) + +// ServiceOAuthAuthentication Struct implements the Authentication interface +// and takes care of authenticating OAuth RPC requests on behalf of the service +// (i.e GetTokens()) +type serviceOAuthAuthentication struct { + BaseUrl string + Client http.Client +} + +// ServiceOAuth instantiates ServiceOAuthAuthentication with the coinbase certificate file +func serviceOAuth(certFilePath string) (*serviceOAuthAuthentication, error) { + // First we read the cert + certs := x509.NewCertPool() + pemData, err := ioutil.ReadFile(certFilePath) + if err != nil { + return nil, err + } + certs.AppendCertsFromPEM(pemData) + mTLSConfig := &tls.Config{ + RootCAs: certs, //Add the cert as a TLS config + } + a := serviceOAuthAuthentication{ + BaseUrl: "https://coinbase.com/", + Client: http.Client{ + Transport: &http.Transport{ + Dial: dialTimeout, + TLSClientConfig: mTLSConfig, + }, + }, + } + return &a, nil +} + +// Service OAuth authentication requires no additional headers to be sent. The +// Coinbase Public Certificate is set as a TLS config in the http.Client +func (a serviceOAuthAuthentication) authenticate(req *http.Request, endpoint string, params []byte) error { + return nil // No additional headers needed for service OAuth requests +} + +func (a serviceOAuthAuthentication) getBaseUrl() string { + return a.BaseUrl +} + +func (a serviceOAuthAuthentication) getClient() *http.Client { + return &a.Client +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/DELETE_transactions_ID_cancel_request.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/DELETE_transactions_ID_cancel_request.json new file mode 100644 index 0000000..f11b832 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/DELETE_transactions_ID_cancel_request.json @@ -0,0 +1,3 @@ +{ + "success": false +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_account_balance.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_account_balance.json new file mode 100644 index 0000000..9cc74fa --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_account_balance.json @@ -0,0 +1,4 @@ +{ + "amount": "36.62800000", + "currency": "BTC" +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_addresses.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_addresses.json new file mode 100644 index 0000000..2f5f4c5 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_addresses.json @@ -0,0 +1,33 @@ +{ + "addresses": [ + { + "address": { + "address": "moLxGrqWNcnGq4A8Caq8EGP4n9GUGWanj4", + "callback_url": null, + "label": "My Label", + "created_at": "2013-05-09T23:07:08-07:00" + } + }, + { + "address": { + "address": "mwigfecvyG4MZjb6R5jMbmNcs7TkzhUaCj", + "callback_url": null, + "label": null, + "created_at": "2013-05-09T17:50:37-07:00" + } + }, + { + "address": { + "address": "2N139JFn7dwX1ySkdWYDXCV51oyBCuV8zYw", + "callback_url": null, + "label": null, + "created_at": "2013-05-09T17:50:37-07:00", + "type": "p2sh", + "redeem_script": "524104c6e3f151b7d0ca7a63c6090c1eb86fd2cbfce43c367b5b36553ba28ade342b9dd8590f48abd48aa0160babcabfdccc6529609d2f295b3165e724de2f15adca9d410434cca255243e36de58f628b0f462518168b9c97b408f92ea9e01e168c70c003398bbf9b4c5cb9344f00c7cebf40322405f9b063eb4d2da25e710759aa51301eb4104624c024547a858b898bfe0b89c4281d743303da6d9ad5fc2f82228255586a9093011a540acae4bdf77ce427c0cb9b482918093e677238800fc0f6fae14f6712853ae" + } + } + ], + "total_count": 3, + "num_pages": 1, + "current_page": 1 +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_contacts.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_contacts.json new file mode 100644 index 0000000..5b3a520 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_contacts.json @@ -0,0 +1,17 @@ +{ + "contacts": [ + { + "contact": { + "email": "user1@example.com" + } + }, + { + "contact": { + "email": "user2@example.com" + } + } + ], + "total_count": 2, + "num_pages": 1, + "current_page": 1 +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_orders.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_orders.json new file mode 100644 index 0000000..024afca --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_orders.json @@ -0,0 +1,35 @@ +{ + "orders": [ + { + "order": { + "id": "A7C52JQT", + "created_at": "2013-03-11T22:04:37-07:00", + "status": "completed", + "total_btc": { + "cents": 100000000, + "currency_iso": "BTC" + }, + "total_native": { + "cents": 3000, + "currency_iso": "USD" + }, + "custom": "", + "receive_address": "mgrmKftH5CeuFBU3THLWuTNKaZoCGJU5jQ", + "button": { + "type": "buy_now", + "name": "Order #1234", + "description": "order description", + "id": "eec6d08e9e215195a471eae432a49fc7" + }, + "transaction": { + "id": "513eb768f12a9cf27400000b", + "hash": "4cc5eec20cd692f3cdb7fc264a0e1d78b9a7e3d7b862dec1e39cf7e37ababc14", + "confirmations": 0 + } + } + } + ], + "total_count": 1, + "num_pages": 1, + "current_page": 1 +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_orders_ID.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_orders_ID.json new file mode 100644 index 0000000..bc31d53 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_orders_ID.json @@ -0,0 +1,28 @@ +{ + "order": { + "id": "A7C52JQT", + "created_at": "2013-03-11T22:04:37-07:00", + "status": "completed", + "total_btc": { + "cents": 10000000, + "currency_iso": "BTC" + }, + "total_native": { + "cents": 10000000, + "currency_iso": "BTC" + }, + "custom": "custom123", + "receive_address": "mgrmKftH5CeuFBU3THLWuTNKaZoCGJU5jQ", + "button": { + "type": "buy_now", + "name": "test", + "description": "", + "id": "eec6d08e9e215195a471eae432a49fc7" + }, + "transaction": { + "id": "513eb768f12a9cf27400000b", + "hash": "4cc5eec20cd692f3cdb7fc264a0e1d78b9a7e3d7b862dec1e39cf7e37ababc14", + "confirmations": 0 + } + } +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_transactions.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_transactions.json new file mode 100644 index 0000000..89e99af --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_transactions.json @@ -0,0 +1,61 @@ +{ + "current_user": { + "id": "5011f33df8182b142400000e", + "email": "user2@example.com", + "name": "User Two" + }, + "balance": { + "amount": "50.00000000", + "currency": "BTC" + }, + "native_balance": { + "amount": "500.00", + "currency": "USD" + }, + "total_count": 2, + "num_pages": 1, + "current_page": 1, + "transactions": [ + { + "transaction": { + "id": "5018f833f8182b129c00002f", + "created_at": "2012-08-01T02:34:43-07:00", + "amount": { + "amount": "-1.10000000", + "currency": "BTC" + }, + "request": true, + "status": "pending", + "sender": { + "id": "5011f33df8182b142400000e", + "name": "User Two", + "email": "user2@example.com" + }, + "recipient": { + "id": "5011f33df8182b142400000a", + "name": "User One", + "email": "user1@example.com" + } + } + }, + { + "transaction": { + "id": "5018f833f8182b129c00002e", + "created_at": "2012-08-01T02:36:43-07:00", + "hsh": "9d6a7d1112c3db9de5315b421a5153d71413f5f752aff75bf504b77df4e646a3", + "amount": { + "amount": "-1.00000000", + "currency": "BTC" + }, + "request": false, + "status": "complete", + "sender": { + "id": "5011f33df8182b142400000e", + "name": "User Two", + "email": "user2@example.com" + }, + "recipient_address": "37muSN5ZrukVTvyVh3mT5Zc5ew9L9CBare" + } + } + ] +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_transactions_ID.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_transactions_ID.json new file mode 100644 index 0000000..ee0aac7 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_transactions_ID.json @@ -0,0 +1,22 @@ +{ + "transaction": { + "id": "5018f833f8182b129c00002f", + "created_at": "2012-08-01T02:34:43-07:00", + "amount": { + "amount": "-1.10000000", + "currency": "BTC" + }, + "request": true, + "status": "pending", + "sender": { + "id": "5011f33df8182b142400000e", + "name": "User Two", + "email": "user2@example.com" + }, + "recipient": { + "id": "5011f33df8182b142400000a", + "name": "User One", + "email": "user1@example.com" + } + } +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_transfers.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_transfers.json new file mode 100644 index 0000000..83c9e27 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_transfers.json @@ -0,0 +1,40 @@ +{ + "transfers": [ + { + "transfer": { + "type": "Buy", + "code": "QPCUCZHR", + "created_at": "2013-02-27T23:28:18-08:00", + "fees": { + "coinbase": { + "cents": 14, + "currency_iso": "USD" + }, + "bank": { + "cents": 15, + "currency_iso": "USD" + } + }, + "payout_date": "2013-03-05T18:00:00-08:00", + "transaction_id": "5011f33df8182b142400000e", + "status": "Pending", + "btc": { + "amount": "1.00000000", + "currency": "BTC" + }, + "subtotal": { + "amount": "13.55", + "currency": "USD" + }, + "total": { + "amount": "13.84", + "currency": "USD" + }, + "description": "Paid for with $13.84 from Test xxxxx3111." + } + } + ], + "total_count": 1, + "num_pages": 1, + "current_page": 1 +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_users.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_users.json new file mode 100644 index 0000000..a6e9c74 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_users.json @@ -0,0 +1,35 @@ +{ + "users": [ + { + "user": { + "id": "512db383f8182bd24d000001", + "name": "User One", + "email": "user1@example.com", + "time_zone": "Pacific Time (US & Canada)", + "native_currency": "USD", + "balance": { + "amount": "49.76000000", + "currency": "BTC" + }, + "merchant": { + "company_name": "Company Name, Inc.", + "logo": { + "small": "http://smalllogo.example", + "medium": "http://mediumlogo.example", + "url": "http://logo.example" + } + }, + "buy_level": 1, + "sell_level": 1, + "buy_limit": { + "amount": "10.00000000", + "currency": "BTC" + }, + "sell_limit": { + "amount": "100.00000000", + "currency": "BTC" + } + } + } + ] +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_account_generate_receive_address.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_account_generate_receive_address.json new file mode 100644 index 0000000..d7b739b --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_account_generate_receive_address.json @@ -0,0 +1,6 @@ +{ + "success": true, + "address": "muVu2JZo8PbewBHRp6bpqFvVD87qvqEHWA", + "callback_url": null, + "label": null +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_buttons.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_buttons.json new file mode 100644 index 0000000..ff4bb44 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_buttons.json @@ -0,0 +1,18 @@ +{ + "success": true, + "button": { + "code": "93865b9cae83706ae59220c013bc0afd", + "type": "buy_now", + "subscription": false, + "style": "custom_large", + "text": "Pay With Bitcoin", + "name": "test", + "description": "Sample description", + "custom": "Order123", + "callback_url": "http://www.example.com/my_custom_button_callback", + "price": { + "cents": 123, + "currency_iso": "USD" + } + } +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_buttons_ID_create_order.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_buttons_ID_create_order.json new file mode 100644 index 0000000..ebcd00b --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_buttons_ID_create_order.json @@ -0,0 +1,25 @@ +{ + "success": true, + "order": { + "id": "7RTTRDVP", + "created_at": "2013-11-09T22:47:10-08:00", + "status": "new", + "total_btc": { + "cents": 100000000, + "currency_iso": "BTC" + }, + "total_native": { + "cents": 100000000, + "currency_iso": "BTC" + }, + "custom": "Order123", + "receive_address": "mgrmKftH5CeuFBU3THLWuTNKaZoCGJU5jQ", + "button": { + "type": "buy_now", + "name": "test", + "description": "Sample description", + "id": "93865b9cae83706ae59220c013bc0afd" + }, + "transaction": null + } +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_buys.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_buys.json new file mode 100644 index 0000000..49718a4 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_buys.json @@ -0,0 +1,32 @@ +{ + "success": true, + "transfer": { + "type": "Buy", + "code": "6H7GYLXZ", + "created_at": "2013-01-28T16:08:58-08:00", + "fees": { + "coinbase": { + "cents": 14, + "currency_iso": "USD" + }, + "bank": { + "cents": 15, + "currency_iso": "USD" + } + }, + "status": "created", + "payout_date": "2013-02-01T18:00:00-08:00", + "btc": { + "amount": "1.00000000", + "currency": "BTC" + }, + "subtotal": { + "amount": "13.55", + "currency": "USD" + }, + "total": { + "amount": "13.84", + "currency": "USD" + } + } +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_sells.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_sells.json new file mode 100644 index 0000000..a2bf661 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_sells.json @@ -0,0 +1,32 @@ +{ + "success": true, + "transfer": { + "type": "Sell", + "code": "RD2OC8AL", + "created_at": "2013-01-28T16:32:35-08:00", + "fees": { + "coinbase": { + "cents": 14, + "currency_iso": "USD" + }, + "bank": { + "cents": 15, + "currency_iso": "USD" + } + }, + "status": "created", + "payout_date": "2013-02-01T18:00:00-08:00", + "btc": { + "amount": "1.00000000", + "currency": "BTC" + }, + "subtotal": { + "amount": "13.50", + "currency": "USD" + }, + "total": { + "amount": "13.21", + "currency": "USD" + } + } +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_transactions_request_money.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_transactions_request_money.json new file mode 100644 index 0000000..5b72fb8 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_transactions_request_money.json @@ -0,0 +1,25 @@ +{ + "success": true, + "transaction": { + "id": "501a3554f8182b2754000003", + "created_at": "2012-08-02T01:07:48-07:00", + "hsh": null, + "notes": "Sample request for you!", + "amount": { + "amount": "1.23400000", + "currency": "BTC" + }, + "request": true, + "status": "pending", + "sender": { + "id": "5011f33df8182b142400000a", + "name": "User One", + "email": "user1@example.com" + }, + "recipient": { + "id": "5011f33df8182b142400000e", + "name": "User Two", + "email": "user2@example.com" + } + } +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_transactions_send_money.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_transactions_send_money.json new file mode 100644 index 0000000..68cd239 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_transactions_send_money.json @@ -0,0 +1,26 @@ +{ + "success": true, + "transaction": { + "id": "501a1791f8182b2071000087", + "created_at": "2012-08-01T23:00:49-07:00", + "hsh": "9d6a7d1112c3db9de5315b421a5153d71413f5f752aff75bf504b77df4e646a3", + "notes": "Sample transaction for you!", + "amount": { + "amount": "-1.23400000", + "currency": "BTC" + }, + "request": false, + "status": "pending", + "sender": { + "id": "5011f33df8182b142400000e", + "name": "User Two", + "email": "user2@example.com" + }, + "recipient": { + "id": "5011f33df8182b142400000a", + "name": "User One", + "email": "user1@example.com" + }, + "recipient_address": "37muSN5ZrukVTvyVh3mT5Zc5ew9L9CBare" + } + }
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_users.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_users.json new file mode 100644 index 0000000..b8e866f --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_users.json @@ -0,0 +1,9 @@ +{ + "success": true, + "user": { + "id": "501a3d22f8182b2754000011", + "name": "New User", + "email": "newuser@example.com", + "receive_address": "mpJKwdmJKYjiyfNo26eRp4j6qGwuUUnw9x" + } +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/PUT_transactions_ID_complete_request.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/PUT_transactions_ID_complete_request.json new file mode 100644 index 0000000..a8c2f4a --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/PUT_transactions_ID_complete_request.json @@ -0,0 +1,18 @@ +{ + "success": true, + "errors": [], + "transaction": { + "id": "503c46a3f8182b106500009b", + "created_at": null, + "hsh": null, + "notes": null, + "amount": { + "amount": "0.00000000", + "currency": "BTC" + }, + "request": false, + "status": "pending", + "recipient": null, + "sender": null + } +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/PUT_transactions_ID_resend_request.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/PUT_transactions_ID_resend_request.json new file mode 100644 index 0000000..28e7be1 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/PUT_transactions_ID_resend_request.json @@ -0,0 +1,3 @@ +{ + "success": true +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/utils.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/utils.go new file mode 100644 index 0000000..329e59c --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/utils.go @@ -0,0 +1,12 @@ +package coinbase + +import ( + "net" + "time" +) + +// dialTimeout is used to enforce a timeout for all http requests. +func dialTimeout(network, addr string) (net.Conn, error) { + var timeout = time.Duration(2 * time.Second) //how long to wait when trying to connect to the coinbase + return net.DialTimeout(network, addr, timeout) +} |
