Skip to content

Instantly share code, notes, and snippets.

@syntacticsugar
Forked from kroo/README.md
Created May 13, 2014 17:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save syntacticsugar/b5542688eb3fab776a65 to your computer and use it in GitHub Desktop.
Save syntacticsugar/b5542688eb3fab776a65 to your computer and use it in GitHub Desktop.

How to Use

Open up Terminal.app in your /Applications/Utilities directory, then type in these commands, one after each other:

  1. Create a temporary directory for cycript:

    mkdir cycript && cd cycript
    
  2. Pull the latest cycript from cycript.org:

    curl -L https://cydia.saurik.com/api/latest/3 -o cycript.zip
    
  3. Unzip cycript:

    unzip cycript.zip
    
  4. Download fix_growlvoice.js:

    curl https://gist.githubusercontent.com/kroo/11205755/raw/fix_growlvoice.js -o fix_growlvoice.js
    
  5. Start GrowlVoice now.

    open -a GrowlVoice
    
  6. A popup window should appear about malformed JSON. Close it.

  7. Ensure cycript is executable:

    chmod +x ./cycript
    
  8. Patch the running GrowlVoice process:

    sudo ./cycript -p GrowlVoice fix_growlvoice.js
    

Each time you restart GrowlVoice, you will need to run this fix script again. Run cd ~/cycript && sudo ./cycript -p GrowlVoice fix_growlvoice.js to run the script sometime later.

/**
* A quick n' dirty hack to fix a dying GrowlVoice
*
* GrowlVoice is now officially dead: https://twitter.com/GrowlVoice/status/455931023868448768
* However, Google didn't really shut off API access (there wasn't really any to begin with);
* they slightly mangled a JSON object GrowlVoice was looking for on one of Google Voice's
* internal pages.
*
* The following is a Cycript script that will bring a dead GrowlVoice back
* to life for the moment (until Google decides to mangle things more).
*
* To use:
*
* - Download cycript from cycript.org, and extract somewhere sane
* - download this script to the same place as cycript
* - Start GrowlVoice (it will complain about malformed JSON)
* - Run sudo ./cycript -p GrowlVoice fix_growlvoice.js
*/
@import com.saurik.substrate.MS
var oldm = {},
NSUTF8StringEncoding = 4,
MESSAGE = @selector(accountInfoFetcher:finishedWithData:error:),
START_TOKEN = 'var _gcData = ',
END_TOKEN = '};';
// It's failing in accountInfoFetcher:finishedWithData:error:, a callback method
// that parses a response from Google's auth page, and pulls in a bunch of info.
//
// Since it's failing there, let's hook it, and massage the data we're getting
// back until GrowlVoice can understand it again.
//
// Using MobileSubstrate, the following line 'swizzles' the method, replacing
// it with our own wrapper function:
MS.hookMessage(GoogleVoiceLoginInterface, MESSAGE, function (fetcher, data, err) {
// In particular, we need to find a json object embedded in the page that was
// just returned into this function (as the second arg, data).
// Convert to NSString from NSData
var sdata = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// Find the start and end of the JSON object, then split the page into 3
// sections: before the json object, after, and the object itself. This is
// pretty fragile, but exactly what GrowlVoice does, so we might as well be
// consistant.
var startIndex = sdata.indexOf(START_TOKEN) + START_TOKEN.length;
var endIndex = sdata.indexOf(END_TOKEN, startIndex) + 1;
var prefix = sdata.slice(0, startIndex);
var suffix = sdata.slice(endIndex);
var authJSON = sdata.slice(startIndex, endIndex);
// Now, fix the JSON object. This method is robust, but dangerous:
// Google's new JSON encoding format only works when evaluating as a
// javascript statement -- it's really not even close to valid json.
// Therefore, we evaluate that line as a javascript statement, then
// re-encode back to well-formed json.
eval('var gcData = ' + authJSON);
var fixedJSON = JSON.stringify(gcData);
// reconstruct the original page, and pass back through to the original method
var newdata = [(prefix + fixedJSON + suffix) dataUsingEncoding:NSUTF8StringEncoding];
oldm->call(this, fetcher, newdata, err);
}, oldm);
// trigger the signin process again
[choose(GoogleVoiceLoginInterface)[0] signIn];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment