1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/addon-sdk/source/python-lib/cuddlefish/preflight.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,77 @@ 1.4 +# This Source Code Form is subject to the terms of the Mozilla Public 1.5 +# License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 +# file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.7 + 1.8 +import os, sys 1.9 +import base64 1.10 +import simplejson as json 1.11 + 1.12 +def create_jid(): 1.13 + """Return 'jid1-XYZ', where 'XYZ' is a randomly-generated string. (in the 1.14 + previous jid0- series, the string securely identified a specific public 1.15 + key). To get a suitable add-on ID, append '@jetpack' to this string. 1.16 + """ 1.17 + # per https://developer.mozilla.org/en/Install_Manifests#id all XPI id 1.18 + # values must either be in the form of a 128-bit GUID (crazy braces 1.19 + # and all) or in the form of an email address (crazy @ and all). 1.20 + # Firefox will refuse to install an add-on with an id that doesn't 1.21 + # match one of these forms. The actual regexp is at: 1.22 + # http://mxr.mozilla.org/mozilla-central/source/toolkit/mozapps/extensions/internal/XPIProvider.jsm#130 1.23 + # So the JID needs an @-suffix, and the only legal punctuation is 1.24 + # "-._". So we start with a base64 encoding, and replace the 1.25 + # punctuation (+/) with letters (AB), losing a few bits of integrity. 1.26 + 1.27 + # even better: windows has a maximum path length limitation of 256 1.28 + # characters: 1.29 + # http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx 1.30 + # (unless all paths are prefixed with "\\?\", I kid you not). The 1.31 + # typical install will put add-on code in a directory like: 1.32 + # C:\Documents and Settings\<username>\Application Data\Mozilla\Firefox\Profiles\232353483.default\extensions\$JID\... 1.33 + # (which is 108 chars long without the $JID). 1.34 + # Then the unpacked XPI contains packaged resources like: 1.35 + # resources/$JID-api-utils-lib/main.js (35 chars plus the $JID) 1.36 + # 1.37 + # We create a random 80 bit string, base64 encode that (with 1.38 + # AB instead of +/ to be path-safe), then bundle it into 1.39 + # "jid1-XYZ@jetpack". This gives us 27 characters. The resulting 1.40 + # main.js will have a path length of 211 characters, leaving us 45 1.41 + # characters of margin. 1.42 + # 1.43 + # 80 bits is enough to generate one billion JIDs and still maintain lower 1.44 + # than a one-in-a-million chance of accidental collision. (1e9 JIDs is 30 1.45 + # bits, square for the "birthday-paradox" to get 60 bits, add 20 bits for 1.46 + # the one-in-a-million margin to get 80 bits) 1.47 + 1.48 + # if length were no issue, we'd prefer to use this: 1.49 + h = os.urandom(80/8) 1.50 + s = base64.b64encode(h, "AB").strip("=") 1.51 + jid = "jid1-" + s 1.52 + return jid 1.53 + 1.54 +def preflight_config(target_cfg, filename, stderr=sys.stderr): 1.55 + modified = False 1.56 + config = json.load(open(filename, 'r')) 1.57 + 1.58 + if "id" not in config: 1.59 + print >>stderr, ("No 'id' in package.json: creating a new ID for you.") 1.60 + jid = create_jid() 1.61 + config["id"] = jid 1.62 + modified = True 1.63 + 1.64 + if modified: 1.65 + i = 0 1.66 + backup = filename + ".backup" 1.67 + while os.path.exists(backup): 1.68 + if i > 1000: 1.69 + raise ValueError("I'm having problems finding a good name" 1.70 + " for the backup file. Please move %s out" 1.71 + " of the way and try again." 1.72 + % (filename + ".backup")) 1.73 + backup = filename + ".backup-%d" % i 1.74 + i += 1 1.75 + os.rename(filename, backup) 1.76 + new_json = json.dumps(config, indent=4) 1.77 + open(filename, 'w').write(new_json+"\n") 1.78 + return False, True 1.79 + 1.80 + return True, False