Coinbase Exchange API с PowerShell

Мне кажется, что я очень близок к тому, чтобы использовать Coinbase Exchange API с PowerShell, но у меня возникают проблемы с созданием действительной подписи. Запросы, не требующие подписи, например / time и / products, работают отлично.

Вот что у меня есть на данный момент.

$api = @{
    "endpoint" = 'https://api.gdax.com'
    "url" = '/account'
    "method" = 'GET'
    "body" = ''
    "key" = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    "secret" = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    "passphrase" = 'xxxxxxxx'
}

# Base64 encoding/decoding functions derived from
# http://vstepic.blogspot.com/2013/02/how-to-convert-string-to-base64-and.html 
function Base64-Encode($string) {
    $conversion = [System.Text.Encoding]::ASCII.GetBytes($string)
    return [System.Convert]::ToBase64String($conversion)
}

function Base64-Decode($string) {
    $conversion = [System.Convert]::FromBase64String($string)
    return [System.Text.Encoding]::ASCII.GetString($conversion)
}

# HMAC SHA256 code derived from
# http://www.jokecamp.com/blog/examples-of-creating-base64-hashes-using-hmac-sha256-in-different-languages/
function hmac($message, $secret) {
    $hmacsha = New-Object System.Security.Cryptography.HMACSHA256
    $hmacsha.key = [Text.Encoding]::ASCII.GetBytes($secret)
    $signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($message))
    $signature = [Convert]::ToBase64String($signature)
    return $signature
}

function Submit-Request($request) {
    $unixEpochStart = Get-Date -Date "01/01/1970"
    $now = Get-Date
    $timestamp = (New-TimeSpan -Start $unixEpochStart -End $now.ToUniversalTime()).TotalSeconds.ToString()
    # create the prehash string by concatenating required parts
    $prehash = $timestamp + $request.method.ToUpper() + $request.url + $request.body
    $signature_b64 = hmac -message $prehash -secret (Base64-Decode $request.secret)
    $header = @{
        "CB-ACCESS-KEY" = $request.key
        "CB-ACCESS-SIGN" = $signature_b64
        "CB-ACCESS-TIMESTAMP" = $timestamp
        "CB-ACCESS-PASSPHRASE" = $request.passphrase
        "Content-Type" = 'application/json'
    }
    $uri = $request.endpoint + $request.url
    if ($request.method.ToUpper() -eq 'POST') {
        $response = Invoke-RestMethod -Method $request.method -Uri $uri -Headers $header -Body $request.body
    } else {
        $response = Invoke-RestMethod -Method $request.method -Uri $uri -Headers $header
    }
    return $response
}

$api.method = 'GET'
$api.url = '/account'
$response = Submit-Request $api
Write-Output $response

person Will Ballance    schedule 01.03.2015    source источник


Ответы (1)


Изучив некоторый код C # в сообществе Coinbase, Я смог пересмотреть свой код и заставить его работать. Для декодирования секретного ключа не нужно было переходить в строковый формат, что и происходило, когда я вызывал Base64-Decode перед передачей секрета функции HMAC. Я последовал примеру C # и декодировал его прямо в функции HMAC, не создавая из него строку. Еще одно изменение, которое я сделал, заключалось в том, что метка времени соответствовала формату, полученному из / time, с использованием 3 десятичных знаков вместо 5.

Вот мой исправленный код. Я надеюсь, что это поможет другим.

$api = @{
    "endpoint" = 'https://api.gdax.com'
    "url" = '/account'
    "method" = 'GET'
    "body" = ''
    "key" = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    "secret" = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    "passphrase" = 'xxxxxxxx'
}

# Base64 encoding/decoding functions derived from
# http://vstepic.blogspot.com/2013/02/how-to-convert-string-to-base64-and.html 
function Base64-Encode($string) {
    $conversion = [System.Text.Encoding]::ASCII.GetBytes($string)
    return [System.Convert]::ToBase64String($conversion)
}

function Base64-Decode($string) {
    $conversion = [System.Convert]::FromBase64String($string)
    return [System.Text.Encoding]::ASCII.GetString($conversion)
}

# HMAC SHA256 code derived from
# http://www.jokecamp.com/blog/examples-of-creating-base64-hashes-using-hmac-sha256-in-different-languages/
function hmac($message, $secret) {
    $hmacsha = New-Object System.Security.Cryptography.HMACSHA256
    $hmacsha.key = [Convert]::FromBase64String($secret)
    $signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($message))
    $signature = [Convert]::ToBase64String($signature)
    return $signature
}

function Submit-Request($request) {
    $unixEpochStart = Get-Date -Date "01/01/1970"
    $now = Get-Date
    $timestamp = (New-TimeSpan -Start $unixEpochStart -End $now.ToUniversalTime()).TotalSeconds
    # round timestamp to 3 decimal places and convert to string
    $timestamp = ([math]::Round($timestamp, 3)).ToString()
    # create the prehash string by concatenating required parts
    $prehash = $timestamp + $request.method.ToUpper() + $request.url + $request.body
    $signature_b64 = hmac -message $prehash -secret $request.secret
    $header = @{
        "CB-ACCESS-KEY" = $request.key
        "CB-ACCESS-SIGN" = $signature_b64
        "CB-ACCESS-TIMESTAMP" = $timestamp
        "CB-ACCESS-PASSPHRASE" = $request.passphrase
        "Content-Type" = 'application/json'
    }
    $uri = $request.endpoint + $request.url
    if ($request.method.ToUpper() -eq 'POST') {
        $response = Invoke-RestMethod -Method $request.method -Uri $uri -Headers $header -Body $request.body
    } else {
        $response = Invoke-RestMethod -Method $request.method -Uri $uri -Headers $header
    }
    return $response
}

$api.method = 'GET'
$api.url = '/accounts'
$response = Submit-Request $api
Write-Output $response
person Will Ballance    schedule 04.03.2015