Skip to content
Snippets Groups Projects
Commit a5767f29 authored by ma1's avatar ma1 Committed by Richard Pospesel
Browse files

Bug 41520: (Regression) Rearranging bookmarks / place items by drag & drop doesn't work anymore

parent 18a9084c
No related branches found
No related tags found
1 merge request!118Bug 41520: (Regression) Rearranging bookmarks / place items by drag & drop doesn't work anymore
......@@ -13,6 +13,7 @@ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
ComponentUtils: "resource://gre/modules/ComponentUtils.jsm",
});
XPCOMUtils.defineLazyGlobalGetters(this, ["crypto"]);
// Module specific constants
const kMODULE_NAME = "Torbutton Drag and Drop Handler";
......@@ -28,52 +29,57 @@ const URLISH_TYPES = Object.freeze([
"application/x-moz-file-promise-url",
]);
/*
Returns true if the text resembles a URL or even just a hostname
in a way that may prompt the O.S. or other applications to send out a
validation DNS query, if not a full request (e.g. " torproject.org",
even with the leading whitespace).
*/
function isURLish(text) {
// Ignore leading whitespace.
text = text.trim();
// Without any protocol or dot in the first chunk, this is unlikely
// to be considered URLish (exception: localhost, but we don't care).
if (!/^[a-z][a-z0-9+-]*:\/\//i.test(text)) {
// no protocol
if (!/^[^.\s\/]+\.[^.\s\/]/.test(text)) {
// no dot
return false;
const MAIN_PROCESS =
Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_DEFAULT;
const EMPTY_PAYLOAD = {};
const OpaqueDrag = {
listening: false,
payload: EMPTY_PAYLOAD,
store(value, type) {
let opaqueKey = crypto.randomUUID();
this.payload = { opaqueKey, value, type };
if (!this.listening && MAIN_PROCESS) {
Services.ppmm.addMessageListener(
"DragDropFilter:GetOpaqueDrag",
() => this.payload
);
this.listening = true;
}
// Prepare for hostname validation via relative URL building.
text = `//${text}`;
return opaqueKey;
},
retrieve(key) {
let { opaqueKey, value, type } = this.payload;
if (opaqueKey === key) {
return { value, type };
}
// Validate URL or hostname.
try {
new URL(text, "https://localhost");
return true;
} catch (e) {
// invalid URL, bail out
if (!MAIN_PROCESS) {
this.payload = Services.cpmm.sendSyncMessage(
"DragDropFilter:GetOpaqueDrag"
)[0];
if (key === this.payload.opaqueKey) {
return this.retrieve(key);
}
return false;
}
// Returns true if any chunk of text is URLish
const hasURLish = text => text.split(/[^\p{L}_.-:\/%~@$-]+/u).some(isURLish);
return EMPTY_PAYLOAD;
},
};
function DragDropFilter() {
this.logger = Cc["@torproject.org/torbutton-logger;1"].getService(
Ci.nsISupports
).wrappedJSObject;
this.logger.log(3, "Component Load 0: New DragDropFilter.");
if (MAIN_PROCESS) {
// We want to update our status in the main process only, in order to
// serve the same opaque drag payload in every process.
try {
Services.obs.addObserver(this, "on-datatransfer-available");
} catch (e) {
this.logger.log(5, "Failed to register drag observer");
}
}
}
DragDropFilter.prototype = {
QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
......@@ -109,23 +115,38 @@ DragDropFilter.prototype = {
const types = aDataTransfer.mozTypesAt(i);
for (const type of types) {
this.logger.log(3, `Type is: ${type}.`);
if (
URLISH_TYPES.includes(type) ||
((type === "text/plain" || type === "text/html") &&
hasURLish(aDataTransfer.getData(type)))
) {
if (URLISH_TYPES.includes(type)) {
this.logger.log(
3,
`Removing transfer data ${aDataTransfer.getData(type)}`
`Removing transfer data ${aDataTransfer.mozGetDataAt(type, i)}`
);
const urlType = "text/x-moz-url";
// Fallback url type, to be parsed by this browser but not externally
const INTERNAL_FALLBACK = "application/x-torbrowser-opaque";
if (types.contains(urlType)) {
const link = aDataTransfer.mozGetDataAt(urlType, i);
const opaqueKey = OpaqueDrag.store(link, urlType);
aDataTransfer.mozSetDataAt(INTERNAL_FALLBACK, opaqueKey, i);
}
for (const type of types) {
aDataTransfer.clearData(type);
if (
type !== INTERNAL_FALLBACK &&
type !== "text/x-moz-place" // don't touch bookmarks
) {
aDataTransfer.mozClearDataAt(type, i);
}
}
break;
}
}
}
},
opaqueDrag: {
get(opaqueKey) {
return OpaqueDrag.retrieve(opaqueKey);
},
},
};
// Assign factory to global object.
......
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment