From a0843f3171307790e96a502fc0f806dc146d3f98 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Sat, 13 Aug 2016 01:56:21 -0400 Subject: [PATCH 1/6] Update to latest Mozilla SpecialPowers code for Proxy.create This fixes the "Proxy.create is not a function" errors during PDF metadata retrieval in Firefox 48 after the old Proxy API removal, but it still throws "doc.location is null". Addresses #1076 --- .../xpcom/translation/translate_firefox.js | 429 ++++++++---------- 1 file changed, 181 insertions(+), 248 deletions(-) diff --git a/chrome/content/zotero/xpcom/translation/translate_firefox.js b/chrome/content/zotero/xpcom/translation/translate_firefox.js index f2cf4f691b..5efb730743 100644 --- a/chrome/content/zotero/xpcom/translation/translate_firefox.js +++ b/chrome/content/zotero/xpcom/translation/translate_firefox.js @@ -37,10 +37,12 @@ const BOMs = { Components.utils.import("resource://gre/modules/NetUtil.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); -Zotero.Translate.DOMWrapper = new function() { +Zotero.Translate.DOMWrapper = new function() { + var Cu = Components.utils; + /* * BEGIN SPECIAL POWERS WRAPPING CODE - * https://mxr.mozilla.org/mozilla-central/source/testing/mochitest/tests/SimpleTest/specialpowersAPI.js?raw=1 + * https://dxr.mozilla.org/mozilla-central/source/testing/specialpowers/content/specialpowersAPI.js */ function isWrappable(x) { if (typeof x === "object") @@ -49,30 +51,75 @@ Zotero.Translate.DOMWrapper = new function() { }; function isWrapper(x) { - return isWrappable(x) && (typeof x.__wrappedObject !== "undefined"); + return isWrappable(x) && (typeof x.SpecialPowers_wrappedObject !== "undefined"); }; function unwrapIfWrapped(x) { return isWrapper(x) ? unwrapPrivileged(x) : x; }; - function isXrayWrapper(x) { - try { - return x.toString().indexOf("XrayWrapper") !== -1; - } catch(e) { - // The toString() implementation could theoretically throw. But it never - // throws for Xray, so we can just assume non-xray in that case. + function wrapIfUnwrapped(x) { + return isWrapper(x) ? x : wrapPrivileged(x); + } + + function isObjectOrArray(obj) { + if (Object(obj) !== obj) return false; - } + let arrayClasses = ['Object', 'Array', 'Int8Array', 'Uint8Array', + 'Int16Array', 'Uint16Array', 'Int32Array', + 'Uint32Array', 'Float32Array', 'Float64Array', + 'Uint8ClampedArray']; + let className = Cu.getClassName(obj, true); + return arrayClasses.indexOf(className) != -1; + } + + // In general, we want Xray wrappers for content DOM objects, because waiving + // Xray gives us Xray waiver wrappers that clamp the principal when we cross + // compartment boundaries. However, there are some exceptions where we want + // to use a waiver: + // + // * Xray adds some gunk to toString(), which has the potential to confuse + // consumers that aren't expecting Xray wrappers. Since toString() is a + // non-privileged method that returns only strings, we can just waive Xray + // for that case. + // + // * We implement Xrays to pure JS [[Object]] and [[Array]] instances that + // filter out tricky things like callables. This is the right thing for + // security in general, but tends to break tests that try to pass object + // literals into SpecialPowers. So we waive [[Object]] and [[Array]] + // instances before inspecting properties. + // + // * When we don't have meaningful Xray semantics, we create an Opaque + // XrayWrapper for security reasons. For test code, we generally want to see + // through that sort of thing. + function waiveXraysIfAppropriate(obj, propName) { + if (propName == 'toString' || isObjectOrArray(obj) || + /Opaque/.test(Object.prototype.toString.call(obj))) + { + return XPCNativeWrapper.unwrap(obj); + } + return obj; } // We can't call apply() directy on Xray-wrapped functions, so we have to be // clever. function doApply(fun, invocant, args) { - return Function.prototype.apply.call(fun, invocant, args); + // We implement Xrays to pure JS [[Object]] instances that filter out tricky + // things like callables. This is the right thing for security in general, + // but tends to break tests that try to pass object literals into + // SpecialPowers. So we waive [[Object]] instances when they're passed to a + // SpecialPowers-wrapped callable. + // + // Note that the transitive nature of Xray waivers means that any property + // pulled off such an object will also be waived, and so we'll get principal + // clamping for Xrayed DOM objects reached from literals, so passing things + // like {l : xoWin.location} won't work. Hopefully the rabbit hole doesn't + // go that deep. + args = args.map(x => isObjectOrArray(x) ? Cu.waiveXrays(x) : x); + return Reflect.apply(fun, invocant, args); } - - function wrapPrivileged(obj, overrides) { + + function wrapPrivileged(obj) { // Primitives pass straight through. if (!isWrappable(obj)) @@ -82,38 +129,13 @@ Zotero.Translate.DOMWrapper = new function() { if (isWrapper(obj)) throw "Trying to double-wrap object!"; - // Make our core wrapper object. - var handler = new SpecialPowersHandler(obj, overrides); + let dummy; + if (typeof obj === "function") + dummy = function() {}; + else + dummy = Object.create(null); - // If the object is callable, make a function proxy. - if (typeof obj === "function") { - var callTrap = function() { - // The invocant and arguments may or may not be wrappers. Unwrap them if necessary. - var invocant = unwrapIfWrapped(this); - var unwrappedArgs = Array.prototype.slice.call(arguments).map(unwrapIfWrapped); - - return wrapPrivileged(doApply(obj, invocant, unwrappedArgs)); - }; - var constructTrap = function() { - // The arguments may or may not be wrappers. Unwrap them if necessary. - var unwrappedArgs = Array.prototype.slice.call(arguments).map(unwrapIfWrapped); - - // Constructors are tricky, because we can't easily call apply on them. - // As a workaround, we create a wrapper constructor with the same - // |prototype| property. - var FakeConstructor = function() { - doApply(obj, this, unwrappedArgs); - }; - FakeConstructor.prototype = obj.prototype; - - return wrapPrivileged(new FakeConstructor()); - }; - - return Proxy.createFunction(handler, callTrap, constructTrap); - } - - // Otherwise, just make a regular object proxy. - return Proxy.create(handler); + return new Proxy(dummy, new SpecialPowersHandler(obj)); }; function unwrapPrivileged(x) { @@ -129,219 +151,130 @@ Zotero.Translate.DOMWrapper = new function() { if (!isWrapper(x)) throw "Trying to unwrap a non-wrapped object!"; - // Unwrap. - return x.__wrappedObject; + var obj = x.SpecialPowers_wrappedObject; + // unwrapped. + return obj; }; - function crawlProtoChain(obj, fn) { - var rv = fn(obj); - if (rv !== undefined) - return rv; - if (Object.getPrototypeOf(obj)) - return crawlProtoChain(Object.getPrototypeOf(obj), fn); - }; - - /* - * We want to waive the __exposedProps__ security check for SpecialPowers-wrapped - * objects. We do this by creating a proxy singleton that just always returns 'rw' - * for any property name. - */ - function ExposedPropsWaiverHandler() { - // NB: XPConnect denies access if the relevant member of __exposedProps__ is not - // enumerable. - var _permit = { value: 'rw', writable: false, configurable: false, enumerable: true }; - return { - getOwnPropertyDescriptor: function(name) { return _permit; }, - ownKeys: function() { throw Error("Can't enumerate ExposedPropsWaiver"); }, - enumerate: function() { throw Error("Can't enumerate ExposedPropsWaiver"); }, - defineProperty: function(name) { throw Error("Can't define props on ExposedPropsWaiver"); }, - deleteProperty: function(name) { throw Error("Can't delete props from ExposedPropsWaiver"); } - }; - }; - ExposedPropsWaiver = new Proxy({}, ExposedPropsWaiverHandler()); - - function SpecialPowersHandler(obj, overrides) { - this.wrappedObject = obj; - this.overrides = overrides ? overrides : {}; - }; - - // Allow us to transitively maintain the membrane by wrapping descriptors - // we return. - SpecialPowersHandler.prototype.doGetPropertyDescriptor = function(name, own) { - - // Handle our special API. - if (name == "__wrappedObject") - return { value: this.wrappedObject, writeable: false, configurable: false, enumerable: false }; - if (name == "__wrapperOverrides") - return { value: this.overrides, writeable: false, configurable: false, enumerable: false }; - // Handle __exposedProps__. - if (name == "__exposedProps__") - return { value: ExposedPropsWaiver, writable: false, configurable: false, enumerable: false }; - - // In general, we want Xray wrappers for content DOM objects, because waiving - // Xray gives us Xray waiver wrappers that clamp the principal when we cross - // compartment boundaries. However, Xray adds some gunk to toString(), which - // has the potential to confuse consumers that aren't expecting Xray wrappers. - // Since toString() is a non-privileged method that returns only strings, we - // can just waive Xray for that case. - var obj = name == 'toString' ? XPCNativeWrapper.unwrap(this.wrappedObject) - : this.wrappedObject; - - // - // Call through to the wrapped object. - // - // Note that we have several cases here, each of which requires special handling. - // - var desc; - - // Hack for overriding some properties - if (this.overrides.hasOwnProperty(name)) - return { "enumerable": true, "value": this.overrides[name] }; - // Case 1: Own Properties. - // - // This one is easy, thanks to Object.getOwnPropertyDescriptor(). - else if (own) - desc = Object.getOwnPropertyDescriptor(obj, name); - - // Case 2: Not own, not Xray-wrapped. - // - // Here, we can just crawl the prototype chain, calling - // Object.getOwnPropertyDescriptor until we find what we want. - // - // NB: Make sure to check this.wrappedObject here, rather than obj, because - // we may have waived Xray on obj above. - else if (!isXrayWrapper(this.wrappedObject)) - try { - desc = crawlProtoChain(obj, function(o) {return Object.getOwnPropertyDescriptor(o, name);}); - } catch(e) { - // we hit bug 560072 if DOM is not wrapped - // https://bugzilla.mozilla.org/show_bug.cgi?id=560072 - if (name in obj) { - // same guess as below - desc = {value: obj[name], writable: false, configurable: true, enumerable: true}; - } - } - - // Case 3: Not own, Xray-wrapped. - // - // This one is harder, because we Xray wrappers are flattened and don't have - // a prototype. Xray wrappers are proxies themselves, so we'd love to just call - // through to XrayWrapper::getPropertyDescriptor(). Unfortunately though, - // we don't have any way to do that. :-( - // - // So we first try with a call to getOwnPropertyDescriptor(). If that fails, - // we make up a descriptor, using some assumptions about what kinds of things - // tend to live on the prototypes of Xray-wrapped objects. - else { - desc = Object.getOwnPropertyDescriptor(obj, name); - if (!desc) { - var getter = Object.prototype.__lookupGetter__.call(obj, name); - var setter = Object.prototype.__lookupSetter__.call(obj, name); - if (getter || setter) - desc = {get: getter, set: setter, configurable: true, enumerable: true}; - else if (name in obj) - desc = {value: obj[name], writable: false, configurable: true, enumerable: true}; - } - } - - // Bail if we've got nothing. - if (typeof desc === 'undefined') - return undefined; - - // When accessors are implemented as JSPropertyOps rather than JSNatives (ie, - // QuickStubs), the js engine does the wrong thing and treats it as a value - // descriptor rather than an accessor descriptor. Jorendorff suggested this - // little hack to work around it. See bug 520882. - if (desc && 'value' in desc && desc.value === undefined) - desc.value = obj[name]; - - // A trapping proxy's properties must always be configurable, but sometimes - // this we get non-configurable properties from Object.getOwnPropertyDescriptor(). - // Tell a white lie. - desc.configurable = true; - - // Transitively maintain the wrapper membrane. - function wrapIfExists(key) { if (key in desc) desc[key] = wrapPrivileged(desc[key]); }; - wrapIfExists('value'); - wrapIfExists('get'); - wrapIfExists('set'); - - return desc; - }; - - SpecialPowersHandler.prototype.getOwnPropertyDescriptor = function(name) { - return this.doGetPropertyDescriptor(name, true); - }; - - SpecialPowersHandler.prototype.getPropertyDescriptor = function(name) { - return this.doGetPropertyDescriptor(name, false); - }; - - function doGetOwnPropertyNames(obj, props) { - - // Insert our special API. It's not enumerable, but getPropertyNames() - // includes non-enumerable properties. - var specialAPI = '__wrappedObject'; - if (props.indexOf(specialAPI) == -1) - props.push(specialAPI); - - - // Do the normal thing. - var flt = function(a) { return props.indexOf(a) == -1; }; - props = props.concat(Object.getOwnPropertyNames(obj).filter(flt)); - - // If we've got an Xray wrapper, include the expandos as well. - if ('wrappedJSObject' in obj) - props = props.concat(Object.getOwnPropertyNames(obj.wrappedJSObject) - .filter(flt)); - - return props; + function SpecialPowersHandler(wrappedObject) { + this.wrappedObject = wrappedObject; } - SpecialPowersHandler.prototype.getOwnPropertyNames = function() { - return doGetOwnPropertyNames(this.wrappedObject, []); - }; + SpecialPowersHandler.prototype = { + construct(target, args) { + // The arguments may or may not be wrappers. Unwrap them if necessary. + var unwrappedArgs = Array.prototype.slice.call(args).map(unwrapIfWrapped); - SpecialPowersHandler.prototype.getPropertyNames = function() { + // We want to invoke "obj" as a constructor, but using unwrappedArgs as + // the arguments. Make sure to wrap and re-throw exceptions! + try { + return wrapIfUnwrapped(Reflect.construct(this.wrappedObject, unwrappedArgs)); + } catch (e) { + throw wrapIfUnwrapped(e); + } + }, - // Manually walk the prototype chain, making sure to add only property names - // that haven't been overridden. - // - // There's some trickiness here with Xray wrappers. Xray wrappers don't have - // a prototype, so we need to unwrap them if we want to get all of the names - // with Object.getOwnPropertyNames(). But we don't really want to unwrap the - // base object, because that will include expandos that are inaccessible via - // our implementation of get{,Own}PropertyDescriptor(). So we unwrap just - // before accessing the prototype. This ensures that we get Xray vision on - // the base object, and no Xray vision for the rest of the way up. - var obj = this.wrappedObject; - var props = []; - props = doGetOwnPropertyNames(this.overrides, props); - while (obj) { - props = doGetOwnPropertyNames(obj, props); - obj = Object.getPrototypeOf(XPCNativeWrapper.unwrap(obj)); + apply(target, thisValue, args) { + // The invocant and arguments may or may not be wrappers. Unwrap + // them if necessary. + var invocant = unwrapIfWrapped(thisValue); + var unwrappedArgs = Array.prototype.slice.call(args).map(unwrapIfWrapped); + + try { + return wrapIfUnwrapped(doApply(this.wrappedObject, invocant, unwrappedArgs)); + } catch (e) { + // Wrap exceptions and re-throw them. + throw wrapIfUnwrapped(e); + } + }, + + has(target, prop) { + if (prop === "SpecialPowers_wrappedObject") + return true; + + return Reflect.has(this.wrappedObject, prop); + }, + + get(target, prop, receiver) { + if (prop === "SpecialPowers_wrappedObject") + return this.wrappedObject; + + let obj = waiveXraysIfAppropriate(this.wrappedObject, prop); + return wrapIfUnwrapped(Reflect.get(obj, prop)); + }, + + set(target, prop, val, receiver) { + if (prop === "SpecialPowers_wrappedObject") + return false; + + let obj = waiveXraysIfAppropriate(this.wrappedObject, prop); + return Reflect.set(obj, prop, unwrapIfWrapped(val)); + }, + + delete(target, prop) { + if (prop === "SpecialPowers_wrappedObject") + return false; + + return Reflect.deleteProperty(this.wrappedObject, prop); + }, + + defineProperty(target, prop, descriptor) { + throw "Can't call defineProperty on SpecialPowers wrapped object"; + }, + + getOwnPropertyDescriptor(target, prop) { + // Handle our special API. + if (prop === "SpecialPowers_wrappedObject") { + return { value: this.wrappedObject, writeable: true, + configurable: true, enumerable: false }; + } + + let obj = waiveXraysIfAppropriate(this.wrappedObject, prop); + let desc = Reflect.getOwnPropertyDescriptor(obj, prop); + + if (desc === undefined) + return undefined; + + // Transitively maintain the wrapper membrane. + function wrapIfExists(key) { + if (key in desc) + desc[key] = wrapIfUnwrapped(desc[key]); + }; + + wrapIfExists('value'); + wrapIfExists('get'); + wrapIfExists('set'); + + // A trapping proxy's properties must always be configurable, but sometimes + // we come across non-configurable properties. Tell a white lie. + desc.configurable = true; + + return desc; + }, + + ownKeys(target) { + // Insert our special API. It's not enumerable, but ownKeys() + // includes non-enumerable properties. + let props = ['SpecialPowers_wrappedObject']; + + // Do the normal thing. + let flt = (a) => !props.includes(a); + props = props.concat(Reflect.ownKeys(this.wrappedObject).filter(flt)); + + // If we've got an Xray wrapper, include the expandos as well. + if ('wrappedJSObject' in this.wrappedObject) { + props = props.concat(Reflect.ownKeys(this.wrappedObject.wrappedJSObject) + .filter(flt)); + } + + return props; + }, + + preventExtensions(target) { + throw "Can't call preventExtensions on SpecialPowers wrapped object"; } - return props; }; - SpecialPowersHandler.prototype.defineProperty = function(name, desc) { - return Object.defineProperty(this.wrappedObject, name, desc); - }; - - SpecialPowersHandler.prototype.delete = function(name) { - return delete this.wrappedObject[name]; - }; - - SpecialPowersHandler.prototype.fix = function() { return undefined; /* Throws a TypeError. */ }; - - // Per the ES5 spec this is a derived trap, but it's fundamental in spidermonkey - // for some reason. See bug 665198. - SpecialPowersHandler.prototype.enumerate = function() { - var t = this; - var filt = function(name) { return t.getPropertyDescriptor(name).enumerable; }; - return this.getPropertyNames().filter(filt); - }; - /* * END SPECIAL POWERS WRAPPING CODE */ From a5d74ceb8119fcf32e9b43ce6aae553faf5a08db Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Sat, 13 Aug 2016 03:35:43 -0400 Subject: [PATCH 2/6] Test with /Applications/Firefox Unbranded.app by default on OS X --- test/runtests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.sh b/test/runtests.sh index 1244e075ed..5dde556297 100755 --- a/test/runtests.sh +++ b/test/runtests.sh @@ -17,7 +17,7 @@ function makePath { DEBUG=false if [ -z "$FX_EXECUTABLE" ]; then if [ "`uname`" == "Darwin" ]; then - FX_EXECUTABLE="/Applications/Firefox.app/Contents/MacOS/firefox" + FX_EXECUTABLE="/Applications/Firefox Unbranded.app/Contents/MacOS/firefox" else FX_EXECUTABLE="firefox" fi From b4e6584417ef0e96b86a1079cda1aaa4eb09861c Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Sat, 13 Aug 2016 19:31:52 -0400 Subject: [PATCH 3/6] Fix PDF metadata recognition in Firefox 48 Reapplies modifications to SpecialPowers code after a0843f317 This is essentially the changes within the SpecialPowers code block from this diff, with some modifications for the new code: git diff 1257b17e..a0571a9a17 chrome/content/zotero/xpcom/translation/translate_firefox.js --- .../xpcom/translation/translate_firefox.js | 62 +++++++++++++++---- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/chrome/content/zotero/xpcom/translation/translate_firefox.js b/chrome/content/zotero/xpcom/translation/translate_firefox.js index 5efb730743..9dec029337 100644 --- a/chrome/content/zotero/xpcom/translation/translate_firefox.js +++ b/chrome/content/zotero/xpcom/translation/translate_firefox.js @@ -51,7 +51,7 @@ Zotero.Translate.DOMWrapper = new function() { }; function isWrapper(x) { - return isWrappable(x) && (typeof x.SpecialPowers_wrappedObject !== "undefined"); + return isWrappable(x) && (typeof x.__wrappedObject !== "undefined"); }; function unwrapIfWrapped(x) { @@ -119,7 +119,7 @@ Zotero.Translate.DOMWrapper = new function() { return Reflect.apply(fun, invocant, args); } - function wrapPrivileged(obj) { + function wrapPrivileged(obj, overrides) { // Primitives pass straight through. if (!isWrappable(obj)) @@ -135,7 +135,7 @@ Zotero.Translate.DOMWrapper = new function() { else dummy = Object.create(null); - return new Proxy(dummy, new SpecialPowersHandler(obj)); + return new Proxy(dummy, new SpecialPowersHandler(obj, overrides)); }; function unwrapPrivileged(x) { @@ -151,13 +151,33 @@ Zotero.Translate.DOMWrapper = new function() { if (!isWrapper(x)) throw "Trying to unwrap a non-wrapped object!"; - var obj = x.SpecialPowers_wrappedObject; + var obj = x.__wrappedObject; // unwrapped. return obj; }; - function SpecialPowersHandler(wrappedObject) { + /* + * We want to waive the __exposedProps__ security check for SpecialPowers-wrapped + * objects. We do this by creating a proxy singleton that just always returns 'rw' + * for any property name. + */ + function ExposedPropsWaiverHandler() { + // NB: XPConnect denies access if the relevant member of __exposedProps__ is not + // enumerable. + var _permit = { value: 'rw', writable: false, configurable: false, enumerable: true }; + return { + getOwnPropertyDescriptor: function(name) { return _permit; }, + ownKeys: function() { throw Error("Can't enumerate ExposedPropsWaiver"); }, + enumerate: function() { throw Error("Can't enumerate ExposedPropsWaiver"); }, + defineProperty: function(name) { throw Error("Can't define props on ExposedPropsWaiver"); }, + deleteProperty: function(name) { throw Error("Can't delete props from ExposedPropsWaiver"); } + }; + }; + ExposedPropsWaiver = new Proxy({}, ExposedPropsWaiverHandler()); + + function SpecialPowersHandler(wrappedObject, overrides) { this.wrappedObject = wrappedObject; + this.overrides = overrides ? overrides: {}; } SpecialPowersHandler.prototype = { @@ -189,22 +209,30 @@ Zotero.Translate.DOMWrapper = new function() { }, has(target, prop) { - if (prop === "SpecialPowers_wrappedObject") + if (prop === "__wrappedObject") return true; + if (this.overrides[prop] !== undefined) { + return true; + } + return Reflect.has(this.wrappedObject, prop); }, get(target, prop, receiver) { - if (prop === "SpecialPowers_wrappedObject") + if (prop === "__wrappedObject") return this.wrappedObject; + if (prop in this.overrides) { + return this.overrides[prop]; + } + let obj = waiveXraysIfAppropriate(this.wrappedObject, prop); return wrapIfUnwrapped(Reflect.get(obj, prop)); }, set(target, prop, val, receiver) { - if (prop === "SpecialPowers_wrappedObject") + if (prop === "__wrappedObject") return false; let obj = waiveXraysIfAppropriate(this.wrappedObject, prop); @@ -212,7 +240,7 @@ Zotero.Translate.DOMWrapper = new function() { }, delete(target, prop) { - if (prop === "SpecialPowers_wrappedObject") + if (prop === "__wrappedObject") return false; return Reflect.deleteProperty(this.wrappedObject, prop); @@ -224,11 +252,22 @@ Zotero.Translate.DOMWrapper = new function() { getOwnPropertyDescriptor(target, prop) { // Handle our special API. - if (prop === "SpecialPowers_wrappedObject") { + if (prop === "__wrappedObject") { return { value: this.wrappedObject, writeable: true, configurable: true, enumerable: false }; } + if (name == "__wrapperOverrides") { + return { value: this.overrides, writeable: false, configurable: false, enumerable: false }; + } + // Handle __exposedProps__. + if (name == "__exposedProps__") { + return { value: ExposedPropsWaiver, writable: false, configurable: false, enumerable: false }; + } + if (prop in this.overrides) { + return this.overrides[prop]; + } + let obj = waiveXraysIfAppropriate(this.wrappedObject, prop); let desc = Reflect.getOwnPropertyDescriptor(obj, prop); @@ -255,10 +294,11 @@ Zotero.Translate.DOMWrapper = new function() { ownKeys(target) { // Insert our special API. It's not enumerable, but ownKeys() // includes non-enumerable properties. - let props = ['SpecialPowers_wrappedObject']; + let props = ['__wrappedObject']; // Do the normal thing. let flt = (a) => !props.includes(a); + props = props.concat(Object.keys(this.overrides).filter(flt)); props = props.concat(Reflect.ownKeys(this.wrappedObject).filter(flt)); // If we've got an Xray wrapper, include the expandos as well. From 8f9d356f1127e4f26c4d313995977d53eb03793b Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Sat, 13 Aug 2016 20:39:41 -0400 Subject: [PATCH 4/6] Update translators --- resource/schema/repotime.txt | 2 +- translators | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resource/schema/repotime.txt b/resource/schema/repotime.txt index e611d50901..586cd4e8da 100644 --- a/resource/schema/repotime.txt +++ b/resource/schema/repotime.txt @@ -1 +1 @@ -2016-07-29 23:30:00 +2016-08-14 00:15:00 diff --git a/translators b/translators index 4f435f5fc5..8f534c9bf1 160000 --- a/translators +++ b/translators @@ -1 +1 @@ -Subproject commit 4f435f5fc59b82f3b607c9d97292dceea8f063d0 +Subproject commit 8f534c9bf19920001ecc2d83eff0357ba6b86786 From 1476d9e71cbab4e2f50a387d190674a120aaae9f Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Sun, 14 Aug 2016 04:16:37 -0400 Subject: [PATCH 5/6] Fix startup error in Firefox 50+ Closes #1077 --- components/zotero-service.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/zotero-service.js b/components/zotero-service.js index edd62f49fb..0f42d11146 100644 --- a/components/zotero-service.js +++ b/components/zotero-service.js @@ -292,9 +292,6 @@ function makeZoteroContext(isConnector) { subscriptLoader.loadSubScript("chrome://zotero/content/xpcom/standalone.js", zContext); } - // load nsTransferable (query: do we still use this?) - subscriptLoader.loadSubScript("chrome://global/content/nsTransferable.js", zContext); - // add connector-related properties zContext.Zotero.isConnector = isConnector; zContext.Zotero.instanceID = instanceID; From 649ce587268672e06e83e907796be909a599d8c1 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Sun, 14 Aug 2016 04:17:46 -0400 Subject: [PATCH 6/6] Update version --- install.rdf | 2 +- resource/config.js | 2 +- update.rdf | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/install.rdf b/install.rdf index b36326d735..52c7f23fef 100644 --- a/install.rdf +++ b/install.rdf @@ -6,7 +6,7 @@ zotero@chnm.gmu.edu Zotero - 4.0.29.11.SOURCE + 4.0.29.12.SOURCE Center for History and New Media
George Mason University
Dan Cohen Sean Takats diff --git a/resource/config.js b/resource/config.js index efddafa54d..f013c5a6d9 100644 --- a/resource/config.js +++ b/resource/config.js @@ -15,7 +15,7 @@ var ZOTERO_CONFIG = { BOOKMARKLET_ORIGIN: 'https://www.zotero.org', HTTP_BOOKMARKLET_ORIGIN: 'http://www.zotero.org', BOOKMARKLET_URL: 'https://www.zotero.org/bookmarklet/', - VERSION: '4.0.29.11.SOURCE' + VERSION: '4.0.29.12.SOURCE' }; EXPORTED_SYMBOLS = ["ZOTERO_CONFIG"]; diff --git a/update.rdf b/update.rdf index 07f1579132..77b6435af3 100644 --- a/update.rdf +++ b/update.rdf @@ -7,7 +7,7 @@ - 4.0.29.11.SOURCE + 4.0.29.12.SOURCE {ec8030f7-c20a-464f-9b0e-13a3a9e97384}