mdbitcoin (OP)
Newbie
Offline
Activity: 29
Merit: 0
|
|
July 25, 2011, 07:46:12 AM |
|
I signed in to help jimbobway on another thread but due to new user restrictions I can't answer him there. http://forum.bitcoin.org/index.php?topic=29843.0However, this is msg will probably help other C# coders trying to break through the learning curve since the new service can be a pain to authenticate to unless it's absolutely right. I lost the better half of the day to it but others have helped me in the past, so hope it helps... Keep in mind, you'll have to supply your own Json Parser to the return string of Post protected string Post( string moreargs = null ) { // Verify client was instantiated with apikey and apisecret if( string.IsNullOrEmpty( this.apiKey ) || string.IsNullOrEmpty( this.apiSecret ) ) throw new ArgumentException( "Cannot call private api's without api key and secret" );
// Create web request to mtgox
var parameters = "nonce=" + DateTime.Now.Ticks.ToString(); if( !string.IsNullOrEmpty( moreargs ) ) parameters += "&" + moreargs; HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create( Url );
webRequest.ContentType = "application/x-www-form-urlencoded"; webRequest.Method = "POST"; webRequest.UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)"; // you should probably key this with your client so they can help diagnose issues for you in their logs!!! webRequest.Accept = "application/json"; // Required to authenticate on MtGox
webRequest.Headers["Rest-Key"] = this.apiKey; webRequest.Headers["Rest-Sign"] = EncodeParamsToSecret( parameters );
byte[] byteArray = Encoding.UTF8.GetBytes( parameters ); webRequest.ContentLength = byteArray.Length;
using( Stream dataStream = webRequest.GetRequestStream() ) { dataStream.Write( byteArray, 0, byteArray.Length ); }
using( WebResponse webResponse = webRequest.GetResponse() ) { using( Stream str = webResponse.GetResponseStream() ) { using( StreamReader sr = new StreamReader( str ) ) { return sr.ReadToEnd(); } } } }
|
|
|
|
mdbitcoin (OP)
Newbie
Offline
Activity: 29
Merit: 0
|
|
July 25, 2011, 08:28:52 AM |
|
Be aware, that general misleading error: "{"error":"Must be logged in"}" will apply in every failed case except authorization for rights.
|
|
|
|
jimbobway
Legendary
Offline
Activity: 1304
Merit: 1015
|
|
July 25, 2011, 01:36:16 PM |
|
Thanks for that! I'll have to take a look at it tonight after work. I noticed there was a method in there "EncodeParamsToSecret( parameters );" that was not in the code you posted. You don't mind posting that method do you (without the key and secret of course.)
|
|
|
|
mdbitcoin (OP)
Newbie
Offline
Activity: 29
Merit: 0
|
|
July 25, 2011, 08:40:19 PM |
|
Sorry about that. That's what I get for posting in the wee hours of the morning. That part is pretty much the same as yours. protected string EncodeParamsToSecret( string parameters ) { var hmacsha512 = new HMACSHA512( Convert.FromBase64String( this.apiSecret ) ); var byteArray = hmacsha512.ComputeHash( Encoding.UTF8.GetBytes( parameters ) ); return Convert.ToBase64String( byteArray ); }
I'll give you more of the code so you can see how the api you're calling would work... I'm using Newtonsoft Json for my json parser. protected JObject JsonPost( string moreargs = null ) { return JsonConvert.DeserializeObject<JObject>( Post( moreargs ) ); }
public const string PRIVATE_URL = "https://mtgox.com/api/0/";
public JObject SendBTC( string walletaddress, double amt ) { Url = new Uri( PRIVATE_URL + "withdraw.php" ); return jObj = JsonPost( string.Format( "group1=BTC&btca={0}&amount={1:f6}", walletaddress, amt ) ); }
Let me know if there's any other pieces I've left out. Obviously you'll have to wrap the function in a class, and set member strings apiKey and apiSecret as you require as well. Good luck. Maybe when I get my revised service back online, you'll blog about it.
|
|
|
|
mdbitcoin (OP)
Newbie
Offline
Activity: 29
Merit: 0
|
|
July 25, 2011, 08:44:25 PM |
|
Oh and the great part if I accidentally posted the apiKey and apiSecret is I could go to MtGox and delete the old and create a new without ever worrying.
|
|
|
|
jimbobway
Legendary
Offline
Activity: 1304
Merit: 1015
|
|
July 26, 2011, 12:58:59 AM |
|
Thank you. I got it working without the username and password. Awesome. PM me about your service.
|
|
|
|
mdbitcoin (OP)
Newbie
Offline
Activity: 29
Merit: 0
|
|
July 26, 2011, 01:25:30 AM |
|
Could you link your other post to this post so others may benefit? I still can't reply on that thread. I wish a moderator would set me up.
|
|
|
|
hex
Newbie
Offline
Activity: 45
Merit: 0
|
|
September 21, 2011, 02:42:00 PM |
|
Here is mine vb.net class. You just supply it credentials and it returns parsed json ' bitcointalk.org - hex, GPL Public Class MtGoxAPI Public Property ApiKey As String Public Property ApiSecretKey As String Public Property UserName As String Public Property Password As String
Public Enum Urls GetTicker GetDepth GetTrades GetFunds BuyBTC SellBTC GetOrders Info '... End Enum
Private Function GetUrl(url As Urls) As String Select Case url Case Urls.GetTicker Return "http://mtgox.com/api/0/data/ticker.php" Case Urls.GetDepth Return "http://mtgox.com/api/0/data/getDepth.php" Case Urls.GetTrades Return "http://mtgox.com/api/0/data/getTrades.php" Case Urls.GetFunds Return "https://mtgox.com/api/0/getFunds.php" Case Urls.BuyBTC Return "https://mtgox.com/api/0/buyBTC.php" Case Urls.SellBTC Return "https://mtgox.com/api/0/sellBTC.php" Case Urls.GetOrders Return "https://mtgox.com/api/0/getOrders.php" Case Urls.Info Return "https://mtgox.com/api/0/info.php" Case Else Throw New NotImplementedException() End Select End Function
Public Shared Function UrlEncode(url As String) As String Dim r = url.Replace("!", "%21") r = r.Replace("*", "%2A") r = r.Replace("'", "%27") r = r.Replace("(", "%28") r = r.Replace(")", "%29") r = r.Replace(";", "%3B") r = r.Replace(":", "%3A") r = r.Replace("@", "%40") r = r.Replace("&", "%26") r = r.Replace("=", "%3D") r = r.Replace("+", "%2B") r = r.Replace("$", "%24") r = r.Replace(",", "%2C") r = r.Replace("/", "%2F") r = r.Replace("?", "%3F") r = r.Replace("#", "%23") r = r.Replace("[", "%5B") r = r.Replace("]", "%5D") Return r End Function
Public Function Request(url As Urls, params As List(Of Tuple(Of String, String))) As Newtonsoft.Json.Linq.JObject
Dim strUrl = GetUrl(url) If params Is Nothing Then params = New List(Of Tuple(Of String, String))
Dim req As Net.HttpWebRequest = System.Net.HttpWebRequest.Create(strUrl) req.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:8.0) Gecko/20110920 Firefox/8.0"
Dim authRequired = Not (url = Urls.GetTicker Or url = Urls.GetDepth Or url = Urls.GetTrades)
If authRequired Then If String.IsNullOrEmpty(ApiKey) Or String.IsNullOrEmpty(ApiSecretKey) Or _ String.IsNullOrEmpty(UserName) Or String.IsNullOrEmpty(Password) Then Throw New ArgumentNullException("auth properties not set")
req.Headers.Add("Rest-Key", ApiKey) params.Add(Tuple.Create("nonce", DateTime.Now.Ticks.ToString())) params.Add(Tuple.Create("name", UserName)) params.Add(Tuple.Create("pass", Password)) End If
If params.Count Then ' we need to POST req.AllowWriteStreamBuffering = True req.Method = "POST" req.ContentType = "application/x-www-form-urlencoded" Dim postSB As New System.Text.StringBuilder() For Each param In params If postSB.Length Then postSB.Append("&") postSB.Append(UrlEncode(param.Item1)) postSB.Append("=") postSB.Append(UrlEncode(param.Item2)) Next Dim postBin = System.Text.Encoding.ASCII.GetBytes(postSB.ToString())
If authRequired Then Dim hmac = System.Security.Cryptography.HMACSHA512.Create() hmac.Key = Convert.FromBase64String(ApiSecretKey) Dim hash = hmac.ComputeHash(postBin) req.Headers.Add("Rest-Sign", Convert.ToBase64String(hash)) End If
req.GetRequestStream.Write(postBin, 0, postBin.Length) End If
Dim response = req.GetResponse.GetResponseStream() Dim reader As IO.StreamReader = New IO.StreamReader(response) 'Return reader.ReadToEnd()
Return Newtonsoft.Json.Linq.JObject.Parse(reader.ReadToEnd())
End Function
End Class
|
|
|
|
mdbitcoin (OP)
Newbie
Offline
Activity: 29
Merit: 0
|
|
September 21, 2011, 09:51:03 PM |
|
hex, I am confused by your implementation. I see you include in your request username and password. Does your model allow for either username/password or key/secret to be passed?
|
|
|
|
hex
Newbie
Offline
Activity: 45
Merit: 0
|
|
September 21, 2011, 10:02:21 PM |
|
No it requires BOTH. Just like it says in documentation: https://en.bitcoin.it/wiki/MtGox/API"In addition to the "nonce" value, your POST data must also include your username and password values, named "name" and "pass" respectively." I tried removing them but it does not works.
|
|
|
|
mdbitcoin (OP)
Newbie
Offline
Activity: 29
Merit: 0
|
|
September 21, 2011, 11:41:36 PM |
|
The implementation I gave works and doesn't require username or password.
The whole point of an api key/secret implementation is to give user control of their account so they can revoke rights to an application. If they give up their username and password to applications, they can't guarantee that the application owner won't hijack the account. User should NEVER give out user name and passwords. That's the whole point.
Anyway, I'll let them know over at MtGox that someone has compromised the wiki. Or maybe something changed recently that I don't know about.
|
|
|
|
hex
Newbie
Offline
Activity: 45
Merit: 0
|
|
September 22, 2011, 12:04:12 AM |
|
Please do check with them and inform me.
|
|
|
|
mdbitcoin (OP)
Newbie
Offline
Activity: 29
Merit: 0
|
|
September 22, 2011, 12:48:16 AM |
|
I notified mark and I've updated the wiki's api for discussion. There is nothing fundamentally wrong with using the username and password strategy, but it does compromise the security of the user's private account and defeats the ENTIRE purpose of the api key/secret rights. I mean, if its a personal application, it doesn't hurt anything, but if it's an application like www.automtgox.com, a service; there's a piece of mind I want to provide my customers. I shouldn't have their passwords on other services. I know why this happened too. It is because the old password implementation is still functional and coders are having a lot of trouble getting the key/secret model working and there are a hundred articles still out there describing how to use the old api with username and password. But to prove I'm not crazy, this is the information on MtGox about key/secret. The wiki used to reflect the same information, and now it doesn't... Note that it does not mention user name or password. https://mtgox.com/support/tradeAPI
|
|
|
|
hex
Newbie
Offline
Activity: 45
Merit: 0
|
|
September 22, 2011, 10:03:37 AM |
|
I understand you compleatly.
I will chenge api as soon as un and pw are no longer required.
|
|
|
|
mdbitcoin (OP)
Newbie
Offline
Activity: 29
Merit: 0
|
|
September 23, 2011, 12:36:33 AM |
|
I thought I'd hear something back by now but I haven't. In any case, the only thing I can suggest is remove the Api Key and Secret from the header and see if your application still works. If it does, it means that your key/secret isn't actually being used and the un&pw is getting precedence. I looked at your code, it looks good to me. So the only next thing I can think that is requiring un/pw is you haven't gone to your mtgox api page and set the necessary rights for that key. Check all to on. If you don't know what I mean, you can check out the videos on www.automtgox.com. There's a part in the 2nd video that shows how to set api keys. Anyway, once the rights are assigned, you shouldn't need to pass the un/pw.
|
|
|
|
hex
Newbie
Offline
Activity: 45
Merit: 0
|
|
September 23, 2011, 01:30:57 PM |
|
nope, it does not work without key and signature. I gave granted get_info and trade rights to my key.
|
|
|
|
SupremePlus
Newbie
Offline
Activity: 3
Merit: 0
|
|
May 12, 2012, 02:32:53 PM |
|
been a while since anyone posted on here.. Hex i was just wandering if your vb code still works, as i tried it the other day with valid credentials and got this error message: "You cannot login to the API with just a login and password", and yes i used my api key/secret key.
|
|
|
|
hex
Newbie
Offline
Activity: 45
Merit: 0
|
|
May 16, 2012, 11:35:11 AM |
|
Try removing username and password from code ?
|
|
|
|
SupremePlus
Newbie
Offline
Activity: 3
Merit: 0
|
|
May 16, 2012, 02:44:23 PM |
|
I have tried removing them but it just throws the must be logged in error
|
|
|
|
hex
Newbie
Offline
Activity: 45
Merit: 0
|
|
May 16, 2012, 11:00:15 PM |
|
I don't know then :/
|
|
|
|
|