Last active
August 29, 2015 14:00
-
-
Save wblakecaldwell/11203637 to your computer and use it in GitHub Desktop.
Google I/O secret invite code finder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# Google I/O 2014 secret invite code finder | |
# | |
# Blake Caldwell, 2014 | |
# | |
# Blog Post: http://blakecaldwell.net/blog/2014/4/23/solving-a-2014-google-io-secret-invite-puzzle.html | |
# | |
# Repeatedly hit https://developers.google.com looking two-colored "I/O" on the page, | |
# with a secret code in comments below it. Using the color codes of the "I" and "O", | |
# calculate the 6-character Google URL-shortened link code, and print the code out. | |
# | |
# I'm not sure if this is intentional or my mistake, but most of the URLs end up 404. | |
# Occasionally, one hits the console-based Google I/O ticket game. | |
# | |
# Here's what the HTML looks like: | |
# <span style="color: #386834">I</span>/<span style="color: #317368">O</span> | |
# <!-- Still need a hint? http://goo.gl/Eypmp --> | |
# </li><!-- 110101 110010 110001 110011 110100 110000 --> | |
# | |
import httplib2 | |
import re | |
# Given the input binary string (ex: '110011'), return | |
# the ASCII character for that value (33): '3' | |
def binary_to_ascii(binary_str): | |
result = 0 | |
while len(binary_str): | |
result *= 2 | |
if binary_str[:1] == "1": | |
result += 1 | |
binary_str = binary_str[1:] | |
return str(unichr(result)) | |
# Calculate our 6-character code shortener by breaking the "I" and "O" | |
# color codes into 6 pairings of 2 characters, converting each pairing | |
# from hex->int, then looking up that ASCII character. Once we have that | |
# code, rearrange it based on |secret_code|, which is a 6-chracter string | |
# of integers from 0-6. | |
# | |
# For example, given #386834 and #317368, along with 521340: | |
# 1. Break the color codes into 6 hex digits: | |
# 0x38, 0x68, 0x34, 0x31, 0x73, 0x68 | |
# 2. Convert each number to decimal | |
# 56, 104, 52, 49, 115, 104 | |
# 3. Convert these numbers to their ASCII values | |
# '8', 'h', '4', '1', 's', 'h' | |
# 4. Reorder the characters by the secret code. Since '5' is the first | |
# value in the secret code, we'll start with index 5 of the ASCII string, | |
# 'h'. Next is index 2, or '4'. | |
# 'h', '4', 'h', '1', 's', '8' | |
# 5. Return our new code: 'h4h1s8', which produces the valid URL of | |
# http://goo.gl/h4h1s8 | |
def calculate_shortened_url(i_color_code, o_color_code, secret_code): | |
s = str(unichr(int(i_color_code[0:2], 16))) | |
s += str(unichr(int(i_color_code[2:4], 16))) | |
s += str(unichr(int(i_color_code[4:6], 16))) | |
s += str(unichr(int(o_color_code[0:2], 16))) | |
s += str(unichr(int(o_color_code[2:4], 16))) | |
s += str(unichr(int(o_color_code[4:6], 16))) | |
# |secret_code| is 6 character string consisting of the integers | |
# 0-5. Reorder |s| by taking its index at the values of |secret_code|. | |
# For example, if |secret_code| is '543210', then we're reversing |s|. | |
output = '' | |
while len(secret_code) > 0: | |
index = int(secret_code[:1]) | |
output += s[index] | |
secret_code = secret_code[1:] | |
return output | |
# Our regular expression for finding the color codes for "I" & "O", | |
# and the commented-out binary strings | |
regex = re.compile('<span style="color: #([0-9]+)">I</span>/<span style="color: #([0-9]+)">O</span>.+<!-- ([ 01]+) -->', re.DOTALL) | |
http = httplib2.Http() | |
# Keep track of what codes we've seen to avoid duplicates | |
found_codes = {} | |
while True: | |
# Fetch the Google Developers page | |
headers, body = http.request("https://developers.google.com") | |
# apply the regex to find matches - not all pages have the codes | |
matches = [m.groups() for m in regex.finditer(body)] | |
if matches and len(matches[0]) == 3: | |
# the color code for the "I" in "I/O" | |
o_color = (matches[0])[1] | |
# the color code for the "O" in "I/O" | |
i_color = (matches[0])[0] | |
# the "secret code", ie: "110000 110001 110011 110010 110100 110101 " | |
code = (matches[0])[2] | |
# Break apart the secret code into words, convert each chunk to an integer, | |
# then join them together to form a 6-character string made up of 0-5. | |
code_str = ''.join([binary_to_ascii(value) for value in code.split()]) | |
# Given the "I" color, the "O" color, and the secret code, determine | |
# our 6-character URL-shortener code | |
shortened_url_code = calculate_shortened_url(i_color, o_color, code_str) | |
if shortened_url_code not in found_codes: | |
# we haven't seen this one yet... | |
found_codes[shortened_url_code] = 1 | |
# print it out - hopefully it's a winner! | |
print('http://goo.gl/%s' % shortened_url_code) |
Can you do a verification of goo.gl URL you are generating similar to what "func verifyGoogl(uri *url.URL)" does at https://gist.github.com/fastest963/10978299? That would eliminate the 404 and 403 easily.
You have bug in calculate_shortened_url.
I don't have any experience with python, but my first try in python is here (feel free to beautify my code):
def calculate_shortened_url(i_color_code, o_color_code, secret_code):
s = str(unichr(int("0x" + i_color_code[0:2], 16)))
s += str(unichr(int("0x" + i_color_code[2:4], 16)))
s += str(unichr(int("0x" + i_color_code[4:6], 16)))
s += str(unichr(int("0x" + o_color_code[0:2], 16)))
s += str(unichr(int("0x" + o_color_code[2:4], 16)))
s += str(unichr(int("0x" + o_color_code[4:6], 16)))
# |secret_code| is 6 character string consisting of the integers
#0-5. Reorder |s| by taking its index at the values of |secret_code|.
# For example, if |secret_code| is '543210', then we're reversing |s|.
output = ''
pos = 0
while len(output) < len(s):
for i in range(0, len(s)):
if pos == int(secret_code[i]):
output += s[i]
pos += 1
return output
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
some links go to random websites. So I am guessing there is something wrong with the logic somewhere. I wonder how some links works!