I'm struggling to access the Coinspot API from PowerShell. No matter what I do I always get the "no nonce" error back from the API:
$VerbosePreference = 'Continue'
$key = ''
$secret = ''
$epoc_start_date = ("01/01/1970" -as [DateTime])
[int]$nonce = ((New-TimeSpan -Start $epoc_start_date -End ([DateTime]::UtcNow)).TotalSeconds -as [string])
$baseUrl = 'www.coinspot.com.au/api'
$resourcePath = '/my/orders'
$url = 'https://{0}{1}&nonce={2}' -f $baseUrl, $resourcePath, $nonce
$encoded = New-Object System.Text.UTF8Encoding
$url_bytes = $encoded.GetBytes($url)
# create hash
$hmac = New-Object System.Security.Cryptography.HMACSHA512
$hmac.key = [Text.Encoding]::ASCII.GetBytes($secret)
$sha_result = $hmac.ComputeHash($url_bytes)
#remove dashes
$hmac_signed = [System.BitConverter]::ToString($sha_result) -replace "-";
$headers = #{
sign = $hmac_signed
key = $key
'content-type' = 'application/json'
}
$result = Invoke-RestMethod -Uri $url -Method Post -Headers $headers
$result
Alternatively I have already tested this:
$VerbosePreference = 'Continue'
$key = ''
$secret = ''
$epoc_start_date = ("01/01/1970" -as [DateTime])
[int]$nonce = ((New-TimeSpan -Start $epoc_start_date -End ([DateTime]::UtcNow)).TotalSeconds -as [string])
$baseUrl = 'www.coinspot.com.au/api'
$resourcePath = '/my/orders'
$url = 'https://{0}{1}' -f $baseUrl, $resourcePath
$body = #{
nonce = $nonce
}
$encoded = New-Object System.Text.UTF8Encoding
$body_bytes = $encoded.GetBytes($body)
# create hash
$hmac = New-Object System.Security.Cryptography.HMACSHA512
$hmac.key = [Text.Encoding]::ASCII.GetBytes($secret)
$sha_result = $hmac.ComputeHash($body_bytes)
#remove dashes
$hmac_signed = [System.BitConverter]::ToString($sha_result) -replace "-";
Invoke-RestMethod -Uri $url -Method Post -Headers #{sign = $hmac_signed ; key = $key ; 'content-type' = 'application/json' } -Body $($body | ConvertTo-Json)
The second gives me an invalid status error.
I have a feeling there's something wrong with my header.
Coinspot support responded:
Apologies for this.
Our current API system is way out of date and needs to be updated.
We know that we need to support the developers as best as we can but our current dev team are very busy with other things at the
moment.
They are aware of this and plan to update it as soon as possible, but right now there is no ETA for this.
Very sorry the inconvenience.
Related
I have been trying to pull out Azure Audit logs using Microsoft Graph. I am using Powershell to do this nut I can't get filtering to work.
For example, this URL returns lots of older data than then date specified in the filter.
https://graph.microsoft.com/v1.0/auditLogs/directoryAudits?\$filter=activityDateTime ge 2020-02-24T18:39:36Z
Here is my code
$ClientID = "yyyyyy"
$ClientSecret = "xxxxxxxxx"
$loginURL = "https://login.microsoftonline.com"
$tenantdomain = "xxx.onmicrosoft.com"
$resource = "https://graph.microsoft.com"
$Date = Get-Date
$UTC = $Date.ToUniversalTime();
$UTC
$Time = "{0:s}" -f $UTC.AddMinutes(-5) + "Z"
$Time
$body =
#{grant_type="client_credentials";resource=$resource;client_id=$ClientID;client_secret=$ClientSecret}
$oauth = Invoke-RestMethod -Method Post -Uri $loginURL/$tenantdomain/oauth2/token?api-
version=1.0 -Body $body
$headerParams = #{'Authorization'="$($oauth.token_type) $($oauth.access_token)"}
$url = 'https://graph.microsoft.com/v1.0/auditLogs/directoryAudits?\`$filter=activityDateTime ge ' +
$Time
$Data = Invoke-WebRequest -UseBasicParsing -Headers $headerParams -Uri $url
$DataFromJson = $Data.Content | ConvertFrom-Json
$ValueFromJason = $DataFromJson.value
$AllAuditData += $ValueFromJason
# Output
$Time
2020-02-24T18:39:36Z
$short = $AllAuditData | Sort-Object activityDateTime
$short[1].activityDateTime
2020-02-24T17:52:09.9673372Z # Old data as comparison to $Time
$short[-1].activityDateTime
2020-02-24T18:44:15.1283452Z
According to my test, we can use the following script
$ClientID = "yyyyyy"
$ClientSecret = "xxxxxxxxx"
$loginURL = "https://login.microsoftonline.com"
$tenantdomain = "xxx.onmicrosoft.com"
$resource = "https://graph.microsoft.com"
$body =
#{grant_type="client_credentials";resource=$resource;client_id=$ClientID;client_secret=$ClientSecret}
$oauth = Invoke-RestMethod -Method Post -Uri $loginURL/$tenantdomain/oauth2/token?api-
version=1.0 -Body $body
$Date = Get-Date
$UTC = $Date.ToUniversalTime();
$Time = "{0:s}" -f $UTC.AddMinutes(-5) + "Z"
$Time
$url= "https://graph.microsoft.com/beta/auditLogs/directoryAudits?`$filter=activityDateTime gt " + $Time
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "$($oauth.token_type) $($oauth.access_token)")
$AllAuditData=#()
$response = Invoke-RestMethod $url -Method 'GET' -Headers $headers
$AllAuditData += $response.value
$short = $AllAuditData | Sort-Object activityDateTime
$short[1].activityDateTime
$short[-1].activityDateTime
Update
According to my research, we can use the Azure AD PowerShell command Get-AzureADAuditDirectoryLogs to filter audit logs. For more details, please refer to https://learn.microsoft.com/en-us/azure/active-directory/reports-monitoring/reference-powershell-reporting.
For example
Install-module AzureADPreview
Connect-AzureAD
$result=Get-AzureADAuditDirectoryLogs -Filter "activityDisplayName eq 'Update user'"
$result | Select-Object ActivityDisplayName
I have a Powershell code that is work very fine in powershell version 3.
I need to run this code in powershell 2.0 too. But Invoke-WebRequest not supported in PS version 2.0.
Please help me!
$params = "metrics[]=failed:count"
$failed = (Invoke-WebRequest -Uri http://localhost:9000/stats -Method POST -Body $params -ContentType "application/json").Content
$x = $failed | ConvertFrom-Json
Untested, but I think this may help:
$params = "metrics[]=failed:count"
$result = #{}
try{
$request = [System.Net.WebRequest]::Create('http://localhost:9000/stats')
$request.Method = 'POST'
$request.ContentType = 'application/json'
$request.Accept = "application/json"
$body = [byte[]][char[]]$params
$upload = $request.GetRequestStream()
$upload.Write($body, 0, $body.Length)
$upload.Flush()
$upload.Close()
$response = $request.GetResponse()
$stream = $response.GetResponseStream()
$streamReader = [System.IO.StreamReader]($stream)
$result['StatusCode'] = $response.StatusCode
$result['StatusDescription'] = $response.StatusDescription
$result['Content'] = $streamReader.ReadToEnd()
$streamReader.Close()
$response.Close()
}
catch{
throw
}
# I suggest checking $result.StatusCode here first..
$x = $result.Content | ConvertFrom-Json
I haven't been successful in getting a response from the Bittrex API with the following powershell code:
Function Crypto($secret, $message)
{
$hmacsha = New-Object System.Security.Cryptography.HMACSHA512(,[System.Text.Encoding]::ASCII.GetBytes($secret))
$hashmessage = $hmacsha.ComputeHash([System.Text.Encoding]::ASCII.GetBytes($message))
$signature = [Convert]::ToBase64String($hashmessage)
return $signature
}
$apiKey = "key"
$secretApiKey = "secret"
$nonce = [Math]::Round((([DateTime]::UtcNow - [DateTime]::new(1970, 1, 1, 0, 0, 0, 0, 'Utc')).TotalSeconds),0)
$uri = "https://bittrex.com/api/v1.1/account/getbalances?apikey=$apiKey&nonce=$nonce"
$signature = Crypto $secretApiKey $uri
Invoke-RestMethod -Uri $uri -Method Get -Headers #{"apisign"="$signature"}
The response is
success message result
------- ------- ------
False INVALID_SIGNATURE
Any ideas what's missing?
Funny enough I ran across this as I was working on the exact same thing. I have solved the problem -- after looking at enough material I figured out the resulting header needs to be the signed data in hex format without any dashes.
Code:
### Bittrex API Key Variables
$apikey = 'KEY-GOES-HERE'
$apisecret = 'SECRET-GOES-HERE'
$byte_key = [Text.Encoding]::ASCII.GetBytes($apikey)
$byte_secret = [Text.Encoding]::ASCII.GetBytes($apisecret)
### Build the URL String
$d1 = ("01/01/1970" -as [DateTime])
[int]$int_nonce = ((New-TimeSpan -Start $d1 -End ([DateTime]::UtcNow)).TotalSeconds -as [string])
[string]$nonce = ($int_nonce -as [string])
$url = "https://bittrex.com/api/v1.1/account/getbalances?apikey=$($apikey)&nonce=$($nonce)"
$utf8enc = New-Object System.Text.UTF8Encoding
$url_bytes = $utf8enc.GetBytes($url)
### SHA 512 HASH TO HEX
$sha512 = New-Object System.Security.Cryptography.HMACSHA512
$sha512.key = $byte_secret
$sha_data = $sha512.ComputeHash($url_bytes)
$sha_sig = [System.BitConverter]::ToString($sha_data) -replace "-";
### Add Headers
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("apisign",$sha_sig)
### Make the Request
$request = Invoke-WebRequest $url -Headers $headers | ConvertFrom-Json
I feel like I'm really close to being able to use the Coinbase Exchange API with PowerShell, but I'm having trouble creating a valid signature. Requests that don't require a signature, like /time and /products, work great.
Here's what I have so far.
$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
After reviewing some C# code in the Coinbase community, I was able to revise my code and get it working. Decoding of the secret key did not need to go to a string format, which is what was happening when I called Base64-Decode before passing the secret to the HMAC function. I followed the C# example and decoded it directly in the HMAC function without making a string out of it. Another change I made was to make the timestamp match the format retrieved from /time, using 3 decimal places instead of 5.
Here's my revised code. I hope it will be of help to others.
$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
I am developing a powershell script that should invoke a REST API using the HTTP POST method. The REST API is used to restore an application specific backup resource from external backup file. the KeyName for backup file in the form data must be "backupFile".
The content type is multipart/form-data. Here is what i am doing:
function invoke-rest {
param([string]$uri)
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
#$enc = [system.Text.Encoding]::UTF8
$request = [System.Net.HttpWebRequest]::Create($uri)
$request.Credentials = New-Object system.net.networkcredential("user","password")
$request.CookieContainer = New-Object System.Net.CookieContainer
$request.AllowWriteStreamBuffering = $true;
$boundary = "--------------"+(get-date -format yyyymmddhhmmss).ToString()
$header = "--"+$boundary
$body = $header + "`r`n" +"Content-Disposition: form-data; name='backupFile'; filename='somefile.sql.gz'"+"`r`n" + "Content-Type: multipart/form-data"+"`r`n`r`n"
$body = $body + [System.Text.Encoding]::UTF8.GetString($(Get-Content 'somefile.sql.gz' -Encoding byte)) + "`r`n"
$footer = $header+"--"
$body = $body + $footer
$bytes = [System.Text.Encoding]::UTF8.GetBytes($body)
$request.ContentType = "multipart/form-data; boundary="+$boundary
$request.Method = "Post"
$request.keepAlive = $true
$request.ContentLength = $bytes.Length
$requestStream = $request.GetRequestStream()
$requestStream.Write($bytes,0,$bytes.length);
$requestStream.Flush();
$requestStream.Close();
$response = $request.GetResponse()
$responseStream = $response.GetResponseStream()
$stream = new-object System.IO.StreamReader $responseStream
$xmlDump = $stream.ReadToEnd()
$output = [xml]$xmlDump
$response.close()
return $output
}
$uri = "http://localhost/rest/backups"
invoke-rest $uri
The error being thrown: REST request failed, A data form must exist with the name backupFile, returning: Bad Request (400)
What am i doing wrong here?
In this scenario, the 400 probably means something was incorrect in generating the
Is the file the only parameter you need to submit on the request? If so, you may be able to use the WebClient.UploadFile API and let it handle generating the bulk of the request.
$client = New-Object System.Net.WebClient
$client.Credentials = $creds
$client.UploadFile('http://localhost/rest/backups', 'c:\temp\somefile.sql.gz')
If you do need to submit multiple parameters in a mime multipart request, then you're looking at a world of pain. I've had to do this through powershell myself and it's not fun at all, particularly when you start involving binary data. After much frustration & headbanging, I ended up with the following to convert a hashtable of values and outputs a multipart. Sorry I can't spot exactly what's wrong with your code, but perhaps this can will either work outright for you, or lead you to identify what your issue is.
function ConvertTo-MimeMultiPartBody
{
param(
[Parameter(Mandatory=$true)]
[string]$Boundary,
[Parameter(Mandatory=$true)]
[hashtable]$Data
)
$body = '';
$Data.GetEnumerator() |% {
$name = $_.Key
$value = $_.Value
$body += "--$Boundary`r`n"
$body += "Content-Disposition: form-data; name=`"$name`""
if ($value -is [byte[]]) {
$fileName = $Data['FileName']
if(!$fileName) {
$fileName = $name
}
$body += "; filename=`"$fileName`"`r`n"
$body += 'Content-Type: application/octet-stream'
#ISO-8859-1 is only encoding where byte value == code point value
$value = [System.Text.Encoding]::GetEncoding("ISO-8859-1").GetString($value)
}
$body += "`r`n`r`n"
$body += $value
$body += "`r`n"
}
$body += "--$boundary--"
return $body
}