зеркало из https://github.com/mozilla/gecko-dev.git
Merge birch to m-c.
This commit is contained in:
Коммит
6d10999514
|
@ -43,6 +43,11 @@ AppsService.prototype = {
|
||||||
return DOMApplicationRegistry.getAppLocalIdByManifestURL(aManifestURL);
|
return DOMApplicationRegistry.getAppLocalIdByManifestURL(aManifestURL);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getAppLocalIdByStoreId: function getAppLocalIdByStoreId(aStoreId) {
|
||||||
|
debug("getAppLocalIdByStoreId( " + aStoreId + " )");
|
||||||
|
return DOMApplicationRegistry.getAppLocalIdByStoreId(aStoreId);
|
||||||
|
},
|
||||||
|
|
||||||
getAppByLocalId: function getAppByLocalId(aLocalId) {
|
getAppByLocalId: function getAppByLocalId(aLocalId) {
|
||||||
debug("getAppByLocalId( " + aLocalId + " )");
|
debug("getAppByLocalId( " + aLocalId + " )");
|
||||||
return DOMApplicationRegistry.getAppByLocalId(aLocalId);
|
return DOMApplicationRegistry.getAppByLocalId(aLocalId);
|
||||||
|
|
|
@ -83,6 +83,11 @@ this.DOMApplicationRegistry = {
|
||||||
return AppsUtils.getCSPByLocalId(this.webapps, aLocalId);
|
return AppsUtils.getCSPByLocalId(this.webapps, aLocalId);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getAppLocalIdByStoreId: function(aStoreId) {
|
||||||
|
debug("getAppLocalIdByStoreId:" + aStoreId);
|
||||||
|
return AppsUtils.getAppLocalIdByStoreId(this.webapps, aStoreId);
|
||||||
|
},
|
||||||
|
|
||||||
getAppByLocalId: function getAppByLocalId(aLocalId) {
|
getAppByLocalId: function getAppByLocalId(aLocalId) {
|
||||||
debug("getAppByLocalId " + aLocalId);
|
debug("getAppByLocalId " + aLocalId);
|
||||||
let app = this.localIdIndex[aLocalId];
|
let app = this.localIdIndex[aLocalId];
|
||||||
|
|
|
@ -90,7 +90,9 @@ this.AppsUtils = {
|
||||||
packageHash: aApp.packageHash,
|
packageHash: aApp.packageHash,
|
||||||
staged: aApp.staged,
|
staged: aApp.staged,
|
||||||
installerAppId: aApp.installerAppId || Ci.nsIScriptSecurityManager.NO_APP_ID,
|
installerAppId: aApp.installerAppId || Ci.nsIScriptSecurityManager.NO_APP_ID,
|
||||||
installerIsBrowser: !!aApp.installerIsBrowser
|
installerIsBrowser: !!aApp.installerIsBrowser,
|
||||||
|
storeId: aApp.storeId || "",
|
||||||
|
storeVersion: aApp.storeVersion || 0
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -126,6 +128,17 @@ this.AppsUtils = {
|
||||||
return Ci.nsIScriptSecurityManager.NO_APP_ID;
|
return Ci.nsIScriptSecurityManager.NO_APP_ID;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getAppLocalIdByStoreId: function(aApps, aStoreId) {
|
||||||
|
debug("getAppLocalIdByStoreId:" + aStoreId);
|
||||||
|
for (let id in aApps) {
|
||||||
|
if (aApps[id].storeId == aStoreId) {
|
||||||
|
return aApps[id].localId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ci.nsIScriptSecurityManager.NO_APP_ID;
|
||||||
|
},
|
||||||
|
|
||||||
getCSPByLocalId: function getCSPByLocalId(aApps, aLocalId) {
|
getCSPByLocalId: function getCSPByLocalId(aApps, aLocalId) {
|
||||||
debug("getCSPByLocalId " + aLocalId);
|
debug("getCSPByLocalId " + aLocalId);
|
||||||
for (let id in aApps) {
|
for (let id in aApps) {
|
||||||
|
|
|
@ -157,6 +157,14 @@ this.DOMApplicationRegistry = {
|
||||||
app.installState = "installed";
|
app.installState = "installed";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default storeId to "" and storeVersion to 0
|
||||||
|
if (this.webapps[id].storeId === undefined) {
|
||||||
|
this.webapps[id].storeId = "";
|
||||||
|
}
|
||||||
|
if (this.webapps[id].storeVersion === undefined) {
|
||||||
|
this.webapps[id].storeVersion = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// At startup we can't be downloading, and the $TMP directory
|
// At startup we can't be downloading, and the $TMP directory
|
||||||
// will be empty so we can't just apply a staged update.
|
// will be empty so we can't just apply a staged update.
|
||||||
app.downloading = false;
|
app.downloading = false;
|
||||||
|
@ -2116,6 +2124,39 @@ this.DOMApplicationRegistry = {
|
||||||
app: app });
|
app: app });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// aStoreId must be a string of the form
|
||||||
|
// <installOrigin>#<storeId from ids.json>
|
||||||
|
// aStoreVersion must be a positive integer.
|
||||||
|
function checkForStoreIdMatch(aStoreId, aStoreVersion) {
|
||||||
|
// Things to check:
|
||||||
|
// 1. if it's a update:
|
||||||
|
// a. We should already have this storeId
|
||||||
|
// b. The manifestURL for the stored app should be the same one we're
|
||||||
|
// updating
|
||||||
|
// c. And finally the version of the update should be higher than the one
|
||||||
|
// on the already installed package
|
||||||
|
// 2. else
|
||||||
|
// a. We should not have this storeId on the list
|
||||||
|
// We're currently launching WRONG_APP_STORE_ID for all the mismatch kind of
|
||||||
|
// errors, and APP_STORE_VERSION_ROLLBACK for the version error.
|
||||||
|
|
||||||
|
// Does an app with this storeID exist already?
|
||||||
|
let appId = self.getAppLocalIdByStoreId(aStoreId);
|
||||||
|
let isInstalled = appId != Ci.nsIScriptSecurityManager.NO_APP_ID;
|
||||||
|
if (aIsUpdate) {
|
||||||
|
if (!isInstalled || (app.localId !== appId)) {
|
||||||
|
// If we don't have the storeId on track already, this
|
||||||
|
// cannot be an update
|
||||||
|
throw "WRONG_APP_STORE_ID";
|
||||||
|
}
|
||||||
|
if (app.storeVersion >= aStoreVersion) {
|
||||||
|
throw "APP_STORE_VERSION_ROLLBACK";
|
||||||
|
}
|
||||||
|
} else if (isInstalled) {
|
||||||
|
throw "WRONG_APP_STORE_ID";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function download() {
|
function download() {
|
||||||
debug("About to download " + aManifest.fullPackagePath());
|
debug("About to download " + aManifest.fullPackagePath());
|
||||||
|
|
||||||
|
@ -2356,6 +2397,31 @@ this.DOMApplicationRegistry = {
|
||||||
throw "INSTALL_FROM_DENIED";
|
throw "INSTALL_FROM_DENIED";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get ids.json if the file is signed
|
||||||
|
if (isSigned) {
|
||||||
|
let idsStream;
|
||||||
|
try {
|
||||||
|
idsStream = zipReader.getInputStream("META-INF/ids.json");
|
||||||
|
} catch (e) {
|
||||||
|
throw zipReader.hasEntry("META-INF/ids.json")
|
||||||
|
? e
|
||||||
|
: "MISSING_IDS_JSON";
|
||||||
|
}
|
||||||
|
let ids =
|
||||||
|
JSON.parse(
|
||||||
|
converter.ConvertToUnicode(
|
||||||
|
NetUtil.readInputStreamToString(
|
||||||
|
idsStream, idsStream.available()) || ""));
|
||||||
|
if ((!ids.id) || !Number.isInteger(ids.version) ||
|
||||||
|
(ids.version <= 0)) {
|
||||||
|
throw "INVALID_IDS_JSON";
|
||||||
|
}
|
||||||
|
let storeId = aApp.installOrigin + "#" + ids.id;
|
||||||
|
checkForStoreIdMatch(storeId, ids.version);
|
||||||
|
app.storeId = storeId;
|
||||||
|
app.storeVersion = ids.version;
|
||||||
|
}
|
||||||
|
|
||||||
let maxStatus = isSigned ? Ci.nsIPrincipal.APP_STATUS_PRIVILEGED
|
let maxStatus = isSigned ? Ci.nsIPrincipal.APP_STATUS_PRIVILEGED
|
||||||
: Ci.nsIPrincipal.APP_STATUS_INSTALLED;
|
: Ci.nsIPrincipal.APP_STATUS_INSTALLED;
|
||||||
|
|
||||||
|
@ -2673,6 +2739,11 @@ this.DOMApplicationRegistry = {
|
||||||
return AppsUtils.getCSPByLocalId(this.webapps, aLocalId);
|
return AppsUtils.getCSPByLocalId(this.webapps, aLocalId);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getAppLocalIdByStoreId: function(aStoreId) {
|
||||||
|
debug("getAppLocalIdByStoreId:" + aStoreId);
|
||||||
|
return AppsUtils.getAppLocalIdByStoreId(this.webapps, aStoreId);
|
||||||
|
},
|
||||||
|
|
||||||
getAppByLocalId: function(aLocalId) {
|
getAppByLocalId: function(aLocalId) {
|
||||||
return AppsUtils.getAppByLocalId(this.webapps, aLocalId);
|
return AppsUtils.getAppByLocalId(this.webapps, aLocalId);
|
||||||
},
|
},
|
||||||
|
|
|
@ -498,24 +498,16 @@ ContactDB.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// containsSearch holds incremental search values for:
|
// containsSearch holds incremental search values for:
|
||||||
// normalized number, national format, international format
|
// normalized number and national format
|
||||||
for (let i = 0; i < normalized.length; i++) {
|
for (let i = 0; i < normalized.length; i++) {
|
||||||
containsSearch[normalized.substring(i, normalized.length)] = 1;
|
containsSearch[normalized.substring(i, normalized.length)] = 1;
|
||||||
}
|
}
|
||||||
if (parsedNumber) {
|
if (parsedNumber && parsedNumber.nationalFormat) {
|
||||||
if (parsedNumber.nationalFormat) {
|
|
||||||
let number = PhoneNumberUtils.normalize(parsedNumber.nationalFormat);
|
let number = PhoneNumberUtils.normalize(parsedNumber.nationalFormat);
|
||||||
for (let i = 0; i < number.length; i++) {
|
for (let i = 0; i < number.length; i++) {
|
||||||
containsSearch[number.substring(i, number.length)] = 1;
|
containsSearch[number.substring(i, number.length)] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (parsedNumber.internationalFormat) {
|
|
||||||
let number = PhoneNumberUtils.normalize(parsedNumber.internationalFormat);
|
|
||||||
for (let i = 0; i < number.length; i++) {
|
|
||||||
containsSearch[number.substring(i, number.length)] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (let num in containsSearch) {
|
for (let num in containsSearch) {
|
||||||
contact.search.tel.push(num);
|
contact.search.tel.push(num);
|
||||||
|
|
|
@ -122,9 +122,7 @@ var steps = [
|
||||||
filterValue: number1.international};
|
filterValue: number1.international};
|
||||||
req = mozContacts.find(options);
|
req = mozContacts.find(options);
|
||||||
req.onsuccess = function () {
|
req.onsuccess = function () {
|
||||||
ok(req.result.length == 1, "Found exactly 1 contact.");
|
ok(req.result.length == 0, "Found exactly 0 contacts.");
|
||||||
findResult1 = req.result[0];
|
|
||||||
ok(findResult1.id == sample_id1, "Same ID");
|
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
req.onerror = onFailure;
|
req.onerror = onFailure;
|
||||||
|
@ -220,9 +218,7 @@ var steps = [
|
||||||
filterValue: number2.international};
|
filterValue: number2.international};
|
||||||
req = mozContacts.find(options);
|
req = mozContacts.find(options);
|
||||||
req.onsuccess = function () {
|
req.onsuccess = function () {
|
||||||
ok(req.result.length == 1, "Found exactly 1 contact.");
|
ok(req.result.length == 0, "Found exactly 1 contact.");
|
||||||
findResult1 = req.result[0];
|
|
||||||
ok(findResult1.id == sample_id1, "Same ID");
|
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
req.onerror = onFailure;
|
req.onerror = onFailure;
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
* We expose Gecko-internal helpers related to "web apps" through this
|
* We expose Gecko-internal helpers related to "web apps" through this
|
||||||
* sub-interface.
|
* sub-interface.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(cfa75628-4d31-481f-b51e-fe0ce18fa98f)]
|
[scriptable, uuid(05c57885-27cf-47fc-8da7-eeec9eb853a7)]
|
||||||
interface mozIApplication: mozIDOMApplication
|
interface mozIApplication: mozIDOMApplication
|
||||||
{
|
{
|
||||||
/* Return true if this app has |permission|. */
|
/* Return true if this app has |permission|. */
|
||||||
|
@ -34,4 +34,10 @@ interface mozIApplication: mozIDOMApplication
|
||||||
|
|
||||||
/* CSP copied from the manifest */
|
/* CSP copied from the manifest */
|
||||||
readonly attribute DOMString csp;
|
readonly attribute DOMString csp;
|
||||||
|
|
||||||
|
/* Store ID if the app is installed from a store */
|
||||||
|
readonly attribute DOMString storeID;
|
||||||
|
|
||||||
|
/* Store version if the app is installed from a store */
|
||||||
|
readonly attribute unsigned long storeVersion;
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,7 +16,7 @@ interface mozIApplication;
|
||||||
* This service allows accessing some DOMApplicationRegistry methods from
|
* This service allows accessing some DOMApplicationRegistry methods from
|
||||||
* non-javascript code.
|
* non-javascript code.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(4ac27836-4d79-4d35-b105-d6fb7f4f8e41)]
|
[scriptable, uuid(1113c6e3-28a2-4315-be10-8b3230eecc0f)]
|
||||||
interface nsIAppsService : nsISupports
|
interface nsIAppsService : nsISupports
|
||||||
{
|
{
|
||||||
mozIDOMApplication getAppByManifestURL(in DOMString manifestURL);
|
mozIDOMApplication getAppByManifestURL(in DOMString manifestURL);
|
||||||
|
@ -62,4 +62,9 @@ interface nsIAppsService : nsISupports
|
||||||
DOMString getWebAppsBasePath();
|
DOMString getWebAppsBasePath();
|
||||||
|
|
||||||
jsval getAppInfo(in DOMString appId);
|
jsval getAppInfo(in DOMString appId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the localId if the app was installed from a store
|
||||||
|
*/
|
||||||
|
DOMString getAppLocalIdByStoreId(in DOMString storeID);
|
||||||
};
|
};
|
||||||
|
|
|
@ -50,7 +50,7 @@ sign_app_with_new_cert()
|
||||||
certutil -d $db -L -n ca1 -r -o $db/ca1.der
|
certutil -d $db -L -n ca1 -r -o $db/ca1.der
|
||||||
certutil -d $db -L -n ee1 -r -o $db/ee1.der
|
certutil -d $db -L -n ee1 -r -o $db/ee1.der
|
||||||
|
|
||||||
python sign_b2g_app.py -d $db -f $passwordfile -k ee1 -i $unsigned_zip -o $out_signed_zip
|
python sign_b2g_app.py -d $db -f $passwordfile -k ee1 -i $unsigned_zip -o $out_signed_zip -S test_app_identifier -V 1
|
||||||
}
|
}
|
||||||
|
|
||||||
rm -Rf $tmpdir
|
rm -Rf $tmpdir
|
||||||
|
|
|
@ -7,6 +7,17 @@ import ctypes
|
||||||
|
|
||||||
import nss_ctypes
|
import nss_ctypes
|
||||||
|
|
||||||
|
# Change the limits in JarSignatureVerification.cpp when you change the limits
|
||||||
|
# here.
|
||||||
|
max_entry_uncompressed_len = 100 * 1024 * 1024
|
||||||
|
max_total_uncompressed_len = 500 * 1024 * 1024
|
||||||
|
max_entry_count = 100 * 1000
|
||||||
|
max_entry_filename_len = 1024
|
||||||
|
max_mf_len = max_entry_count * 50
|
||||||
|
max_sf_len = 1024
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def nss_load_cert(nss_db_dir, nss_password, cert_nickname):
|
def nss_load_cert(nss_db_dir, nss_password, cert_nickname):
|
||||||
nss_ctypes.NSS_Init(nss_db_dir)
|
nss_ctypes.NSS_Init(nss_db_dir)
|
||||||
try:
|
try:
|
||||||
|
@ -32,19 +43,11 @@ def nss_create_detached_signature(cert, dataToSign, wincx):
|
||||||
finally:
|
finally:
|
||||||
nss_ctypes.SEC_PKCS7DestroyContentInfo(p7)
|
nss_ctypes.SEC_PKCS7DestroyContentInfo(p7)
|
||||||
|
|
||||||
def sign_zip(in_zipfile_name, out_zipfile_name, cert, wincx):
|
# We receive a ids_json string for the toBeSigned app
|
||||||
|
def sign_zip(in_zipfile_name, out_zipfile_name, cert, wincx, ids_json):
|
||||||
mf_entries = []
|
mf_entries = []
|
||||||
seen_entries = set()
|
seen_entries = set()
|
||||||
|
|
||||||
# Change the limits in JarSignatureVerification.cpp when you change the limits
|
|
||||||
# here.
|
|
||||||
max_entry_uncompressed_len = 100 * 1024 * 1024
|
|
||||||
max_total_uncompressed_len = 500 * 1024 * 1024
|
|
||||||
max_entry_count = 100 * 1000
|
|
||||||
max_entry_filename_len = 1024
|
|
||||||
max_mf_len = max_entry_count * 50
|
|
||||||
max_sf_len = 1024
|
|
||||||
|
|
||||||
total_uncompressed_len = 0
|
total_uncompressed_len = 0
|
||||||
entry_count = 0
|
entry_count = 0
|
||||||
with zipfile.ZipFile(out_zipfile_name, 'w') as out_zip:
|
with zipfile.ZipFile(out_zipfile_name, 'w') as out_zip:
|
||||||
|
@ -95,6 +98,9 @@ def sign_zip(in_zipfile_name, out_zipfile_name, cert, wincx):
|
||||||
# Add the entry to the manifest we're building
|
# Add the entry to the manifest we're building
|
||||||
mf_entries.append('Name: %s\nSHA1-Digest: %s\n'
|
mf_entries.append('Name: %s\nSHA1-Digest: %s\n'
|
||||||
% (name, b64encode(sha1(contents).digest())))
|
% (name, b64encode(sha1(contents).digest())))
|
||||||
|
if (ids_json):
|
||||||
|
mf_entries.append('Name: %s\nSHA1-Digest: %s\n'
|
||||||
|
% ("META-INF/ids.json", b64encode(sha1(ids_json).digest())))
|
||||||
|
|
||||||
mf_contents = 'Manifest-Version: 1.0\n\n' + '\n'.join(mf_entries)
|
mf_contents = 'Manifest-Version: 1.0\n\n' + '\n'.join(mf_entries)
|
||||||
if len(mf_contents) > max_mf_len:
|
if len(mf_contents) > max_mf_len:
|
||||||
|
@ -112,6 +118,8 @@ def sign_zip(in_zipfile_name, out_zipfile_name, cert, wincx):
|
||||||
out_zip.writestr("META-INF/A.RSA", p7, zipfile.ZIP_DEFLATED)
|
out_zip.writestr("META-INF/A.RSA", p7, zipfile.ZIP_DEFLATED)
|
||||||
out_zip.writestr("META-INF/A.SF", sf_contents, zipfile.ZIP_DEFLATED)
|
out_zip.writestr("META-INF/A.SF", sf_contents, zipfile.ZIP_DEFLATED)
|
||||||
out_zip.writestr("META-INF/MANIFEST.MF", mf_contents, zipfile.ZIP_DEFLATED)
|
out_zip.writestr("META-INF/MANIFEST.MF", mf_contents, zipfile.ZIP_DEFLATED)
|
||||||
|
if (ids_json):
|
||||||
|
out_zip.writestr("META-INF/ids.json", ids_json, zipfile.ZIP_DEFLATED)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description='Sign a B2G app.')
|
parser = argparse.ArgumentParser(description='Sign a B2G app.')
|
||||||
|
@ -126,15 +134,37 @@ def main():
|
||||||
required=True, help="input JAR file (unsigned)")
|
required=True, help="input JAR file (unsigned)")
|
||||||
parser.add_argument('-o', action='store', type=argparse.FileType('wb'),
|
parser.add_argument('-o', action='store', type=argparse.FileType('wb'),
|
||||||
required=True, help="output JAR file (signed)")
|
required=True, help="output JAR file (signed)")
|
||||||
|
parser.add_argument('-I', '--ids-file', action='store', type=argparse.FileType('rb'),
|
||||||
|
help="Path to the ids.json file", dest='I')
|
||||||
|
parser.add_argument('-S', '--storeId', action='store',
|
||||||
|
help="Store Id for the package", dest='S')
|
||||||
|
parser.add_argument('-V', '--storeVersion', action='store', type=int,
|
||||||
|
help="Package Version", dest='V')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Sadly nested groups and neccesarily inclusive groups (http://bugs.python.org/issue11588)
|
||||||
|
# are not implemented. Note that this means the automatic help is slighty incorrect
|
||||||
|
if not((not args.I and args.V and args.S) or (args.I and not args.V and not args.S)):
|
||||||
|
raise ValueError("Either -I or -S and -V must be specified")
|
||||||
|
|
||||||
|
if (args.I):
|
||||||
|
ids_contents = args.I.read(max_entry_uncompressed_len+1)
|
||||||
|
else:
|
||||||
|
ids_contents = '''{
|
||||||
|
"id": "%(id)s",
|
||||||
|
"version": %(version)d
|
||||||
|
}
|
||||||
|
''' % {"id": args.S, "version": args.V}
|
||||||
|
if len(ids_contents) > max_entry_uncompressed_len:
|
||||||
|
raise ValueError("Entry is too large: %s" % (name))
|
||||||
|
|
||||||
db_dir = args.d
|
db_dir = args.d
|
||||||
password = args.f.readline().strip()
|
password = args.f.readline().strip()
|
||||||
cert_nickname = args.k
|
cert_nickname = args.k
|
||||||
|
|
||||||
(wincx, cert) = nss_load_cert(db_dir, password, cert_nickname)
|
(wincx, cert) = nss_load_cert(db_dir, password, cert_nickname)
|
||||||
try:
|
try:
|
||||||
sign_zip(args.i, args.o, cert, wincx)
|
sign_zip(args.i, args.o, cert, wincx, ids_contents)
|
||||||
return 0
|
return 0
|
||||||
finally:
|
finally:
|
||||||
nss_ctypes.CERT_DestroyCertificate(cert)
|
nss_ctypes.CERT_DestroyCertificate(cert)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче