How I “hacked” the OnePlus reservation system.


DISCLAIMER : The purpose of this article is not to allow you to hack the queue. If it was I’d have just posted the script. I have tweeted at OnePlus (https://twitter.com/RealJakeCooper/status/628296501991596032) and they have not yet replied. If they do and would like me to remove this, I will do so at their own request.

EDIT: I mistakenly stated that the characters on the end of URL was a hash. It is not, it is a cache buster.

EDIT2: Part 2 is now up (https://medium.com/@JakeCooper/so-nice-i-did-it-twice-hacking-the-oneplus-reservation-system-again-2e8226c45f9a). I have also decided to open source to script, as it has become defunct. Hopefully people can learn from it :). https://github.com/JakeCooper/OnePlusTwoBot

I, like many others, scrambled to get a OnePlus One invite as soon as they came out. I was a loyal fan : I commented on the forums, I shared all the tabloid garbage with my friends, I even participated in their giveaways.

I ended up just buying an invite from some random dude on XDA for $20. Needless to say, I’ve been pretty against the OnePlus invite system for a long time now.

When the OnePlus Two rolled around, I made sure to be on the ball and put my email in early and secured position ~9000. However, with the invites for the OnePlus Two, OnePlus opted to allow users to jump the queue by referring their friends to the invite waitlist. Last night I checked my invite status and I was position > 70,000.

You wanna dance OnePlus? Let’s dance.

I went to OnePlus’ invite page and I started manually sending links to disposable emails, hosted by mailinator.com. Surprisingly, they worked. I did this about 10 and saw my queue number jump down to < 50,000. Better, but not where I was before.

Enter Python.

I started out by extracting the request URL from the invite page. I did this by using the Network tab in the chrome debugger and looking at the request URL.

https://invites.oneplus.net/index.php?r=share/signup&success_jsonpCallback=success_jsonpCallback&email=test%40mailinator.com&_=1438634544515

The above response is the result of sending a request to test@mailinator.com. Notice the numbers at the end: It’s a cache buster. A cache buster stops the browsers from caching links, and also helps verify if a link is “stale”. But, since we’re going to be doing all of our requests through python Requests, you can request an email to any email in the form of :

https://invites.oneplus.net/index.php?r=share/signup&success_jsonpCallback=success_jsonpCallback&email={{name}}%40mailinator.com&_=1438634544515

where {{name}} is the name of the mailinator inbox you want to use.

A couple lines of python, and boom. I generate a 32 digit random string and use it as my new mailbox. I used the Requests library (http://docs.python-requests.org/en/latest/) for anyone wondering.

So now we can send confirmation emails to any email we want using OnePlus’ system. That’s cool, but how can we retrieve the contents of the emails?

I signed up for https://mailinator.com/ and grabbed my API token from my settings page. From here, I simply used the API as directed on the API page (https://mailinator.com/apidocs.jsp).

Initially, we must request the entire mailbox to retrieve the emailID of the confirmation email.

Let me explain why I added the sleep timer. To do this, let’s look at the response.

{‘messages’: [{‘to’: ‘test@mailinator.com’, ‘ip’: ‘198.2.132.96’, ‘fromfull’: ‘invites@oneplus.net’, ‘id’: ‘14385
98503–141602468-test’, ‘seconds_ago’: 2621, ‘subject’: ‘Confirm your email’, ‘time’: 1438598503781, ‘from’: ‘OneP
lus’, ‘been_read’: False}, {‘to’: ‘test@mailinator.com’, ‘ip’: ‘198.2.132.96’, ‘fromfull’: ‘invites@oneplus.net’, ‘id’: ‘1438598522–141603512-test’, ‘seconds_ago’: 2602, ‘subject’: ‘Successful sign-up for the reservation list’
, ‘time’: 1438598522985, ‘from’: ‘OnePlus’, ‘been_read’: False}]}

Initially, the value for the messages key was coming back as null. After some quick debugging, I ruled that the mailinator API must only create the inbox after a message has been received. Adding a sleep timer of 1 resolves the problem, but I ended up DOSing the OnePlus invite queue (I shit you not) and ramped it down to 1 req/5s.

To access an emails body, you need the email ID. Some simple json drilling and we can easily extract it.

Dat string comparison

Using the emailID, just request the email and drill through that to get to the body of the email.

Here’s the result of print(content)

Sprinkle a bit of Regex in there, and voila : The confirmation URL extracted.

https://xkcd.com/208/

Put it all together and what do you get?

I actually overshot my goal by a couple thousand slots. I went to get more tea, left it running, and when I came back it had eaten through almost 50,000 slots.

PART 2 is now up! https://medium.com/@JakeCooper/so-nice-i-did-it-twice-hacking-the-oneplus-reservation-system-again-2e8226c45f9a

Show your support

Clapping shows how much you appreciated Jake Cooper’s story.