I sell Android apps in Google Play and all orders go through Google Wallet as usual. Google Wallet doesn't allow grouping and filtering the order list, so I wanted to create a small utility (C#, WinForms) to show that order list in a more convenient way. I managed to find the following URL allows downloading a CSV file with the order information and this file fully meets my requirements "https://wallet.google.com/merchant/pages/u/0/bcid-XXX/oid-YYY/cid-ZZZ/purchaseorderdownload?startTime=...&endTime=...". However, I'm unable to authorize to Google and I cannot use this URL without being redirected to the login page. Since I'm going to create a WinForms tool, I cannot use this login page. So, the question is, how to authorize to Google in a sort of automatic mode, so that I can use this URL and download CSV files for further processing in my tool?
-
You need to use Google Authenticator. There is a question that talks about how to use it in .Net here: http://stackoverflow.com/questions/6421950/is-there-a-tutorial-on-how-to-implement-google-authenticator-in-net-apps – ChargerIIC Oct 01 '14 at 15:10
-
@Ted8119 - You are so lucky. I recently asked this question and even posted an open bounty for it. Unfortunately, there doesn't seem to be a way to do this. So, I went ahead and created a program to programmically do what you are trying to do. I am at work right now, so I can't access my computer, but I when I get home tonight, I will post the code for doing this. I wrote it in C# as a console app, but you should be able to easily port it to WinForms if that's what you need. – Icemanind Oct 01 '14 at 15:20
-
@icemanind - That would be just perfect. Can't wait to see your implementation. – Ted8119 Oct 01 '14 at 15:30
1 Answers
Ted, here is my code:
private const string LoginUrl = "https://accounts.google.com/ServiceLoginAuth";
private const string WalletUrl = "https://wallet.google.com/merchant/pages";
private readonly DateTime _unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
private const string Username = "YourUserName@gmail.com";
private const string Password = "YourPassword";
private readonly DateTime _startDate = new DateTime(2014, 9, 1);
private readonly DateTime _endDate = new DateTime(2014, 9, 30);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string orders = GetLoginHtml();
}
private string GetLoginHtml()
{
var request = (HttpWebRequest)WebRequest.Create(LoginUrl);
var cookieJar = new CookieContainer();
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.CookieContainer = cookieJar;
using (var requestStream = request.GetRequestStream())
{
string content = "Email=" + Username + "&Passwd=" + Password;
requestStream.Write(Encoding.UTF8.GetBytes(content), 0, Encoding.UTF8.GetBytes(content).Length);
using (var sr = new StreamReader(request.GetResponse().GetResponseStream()))
{
string html = sr.ReadToEnd();
string galxValue = ParseOutValue(html, "GALX");
return GetLoginHtml2(galxValue, cookieJar);
}
}
}
private string GetLoginHtml2(string galx, CookieContainer cookieJar)
{
var request = (HttpWebRequest)WebRequest.Create(LoginUrl);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.CookieContainer = cookieJar;
using (var requestStream = request.GetRequestStream())
{
string content = "Email=" + Username + "&Passwd=" + Password + "&GALX=" + galx;
requestStream.Write(Encoding.UTF8.GetBytes(content), 0, Encoding.UTF8.GetBytes(content).Length);
using (var sr = new StreamReader(request.GetResponse().GetResponseStream()))
{
string html = sr.ReadToEnd();
return GetLoginHtml3(galx, cookieJar);
}
}
}
private string GetLoginHtml3(string galx, CookieContainer cookieJar)
{
var request = (HttpWebRequest)WebRequest.Create(WalletUrl);
request.Method = "GET";
request.ContentType = "text/xml";
request.CookieContainer = cookieJar;
using (var sr = new StreamReader(request.GetResponse().GetResponseStream()))
{
string html = sr.ReadToEnd();
string bcid = ParseOutBcid(html);
string oid = ParseOutOid(html);
string cid = ParseOutCid(html);
string orders = GetOrders(cookieJar, bcid, oid, cid, _startDate, _endDate);
return orders;
}
}
private string GetOrders(CookieContainer cookieJar, string bcid, string oid, string cid, DateTime startDate, DateTime endDate)
{
var st = (long)(startDate.ToUniversalTime() - _unixEpoch).TotalMilliseconds;
var et = (long)(endDate.ToUniversalTime() - _unixEpoch).TotalMilliseconds;
var request = (HttpWebRequest)WebRequest.Create(WalletUrl + "/u/0/bcid-" + bcid + "/oid-" + oid + "/cid-" + cid + "/purchaseorderdownload?startTime=" + st + "&endTime=" + et);
request.Method = "GET";
request.ContentType = "text/xml";
request.CookieContainer = cookieJar;
using (var sr = new StreamReader(request.GetResponse().GetResponseStream()))
{
string html = sr.ReadToEnd();
return html;
}
}
private string ParseOutValue(string html, string value)
{
int ndx1 = html.IndexOf("<input name=\"" + value + "\"", StringComparison.Ordinal);
int ndx2 = html.IndexOf("value=", ndx1, StringComparison.Ordinal);
return html.Substring(ndx2 + 7, html.IndexOf("\"", ndx2 + 7, StringComparison.Ordinal) - ndx2 - 7);
}
private string ParseOutBcid(string html)
{
int ndx1 = html.IndexOf("bcid-", StringComparison.Ordinal);
int ndx2 = html.IndexOf("/oid", ndx1, StringComparison.Ordinal);
return html.Substring(ndx1 + 5, ndx2 - ndx1 - 5);
}
private string ParseOutOid(string html)
{
int ndx1 = html.IndexOf("/oid-", StringComparison.Ordinal);
int ndx2 = html.IndexOf("/cid", ndx1, StringComparison.Ordinal);
return html.Substring(ndx1 + 5, ndx2 - ndx1 - 5);
}
private string ParseOutCid(string html)
{
int ndx1 = html.IndexOf("/cid-", StringComparison.Ordinal);
string retval = "";
ndx1 = ndx1 + 5;
while (char.IsNumber(html[ndx1]))
{
retval = retval + html[ndx1];
ndx1++;
}
return retval;
}
A couple of things. First, you need to change the Username to whatever your gmail username is and change the Password to whatever your password is. Also, set the _startDate and _endDate to whatever time frame you are trying to pull. You shouldn't have to change anything else. Just call the "GetLoginHtml()" function and it will return your Wallet orders!
Keep in mind, I haven't had a chance to optimize the code yet. Its very raw and there might still be bugs. Also, one other thing, if you get an indexing error while running it, its because you have to open Internet Explorer and log into your Google Account for the first time. Once you log in, you can close Internet Explorer and the program should work after that. I need to figure out a way around that, which I didn't yet.
Let me know what you think!

- 47,519
- 50
- 171
- 296
-
Thank you very much for this code. It is very interesting approach to auth to Google via application/x-www-form-urlencoded and it works! I had to struggle a bit with my password, but after I figured out that non-alphanumeric chars must be encoded with %HH everything works like a charm. – Ted8119 Oct 02 '14 at 08:10
-
@Ted8119 - Yea, the way I should be doing this is using oAuth. That'll be version 2! Glad its working for you! – Icemanind Oct 02 '14 at 15:14