moebius#337: Added option to remove all session cookies for a specific domain

Issue #31
https://github.com/MoonchildProductions/moebius/pull/337
This commit is contained in:
janekptacijarabaci 2018-03-02 16:38:25 +01:00 • committed by Roy Tam
commit e688e88257
11 changed files with 186 additions and 34 deletions

View file

@ -9,3 +9,6 @@
<!-- LOCALIZATION NOTE : Label of popup menu action to delete all storage items. --> <!-- LOCALIZATION NOTE : Label of popup menu action to delete all storage items. -->
<!ENTITY storage.popupMenu.deleteAllLabel "Delete All"> <!ENTITY storage.popupMenu.deleteAllLabel "Delete All">
<!-- LOCALIZATION NOTE : Label of popup menu action to delete all session cookies. -->
<!ENTITY storage.popupMenu.deleteAllSessionCookiesLabel "Delete All Session Cookies">

View file

@ -26,6 +26,8 @@
<menupopup id="storage-tree-popup"> <menupopup id="storage-tree-popup">
<menuitem id="storage-tree-popup-delete-all" <menuitem id="storage-tree-popup-delete-all"
label="&storage.popupMenu.deleteAllLabel;"/> label="&storage.popupMenu.deleteAllLabel;"/>
<menuitem id="storage-tree-popup-delete-all-session-cookies"
label="&storage.popupMenu.deleteAllSessionCookiesLabel;"/>
<menuitem id="storage-tree-popup-delete"/> <menuitem id="storage-tree-popup-delete"/>
</menupopup> </menupopup>
<menupopup id="storage-table-popup"> <menupopup id="storage-table-popup">
@ -33,6 +35,8 @@
<menuitem id="storage-table-popup-delete-all-from"/> <menuitem id="storage-table-popup-delete-all-from"/>
<menuitem id="storage-table-popup-delete-all" <menuitem id="storage-table-popup-delete-all"
label="&storage.popupMenu.deleteAllLabel;"/> label="&storage.popupMenu.deleteAllLabel;"/>
<menuitem id="storage-table-popup-delete-all-session-cookies"
label="&storage.popupMenu.deleteAllSessionCookiesLabel;"/>
</menupopup> </menupopup>
</popupset> </popupset>

View file

@ -29,15 +29,22 @@ const testCases = [
getCookieId("c1", "test1.example.org", "/browser"), getCookieId("c1", "test1.example.org", "/browser"),
getCookieId("cs2", ".example.org", "/"), getCookieId("cs2", ".example.org", "/"),
getCookieId("c3", "test1.example.org", "/"), getCookieId("c3", "test1.example.org", "/"),
getCookieId("uc1", ".example.org", "/") getCookieId("c4", ".example.org", "/"),
getCookieId("uc1", ".example.org", "/"),
getCookieId("uc2", ".example.org", "/")
] ]
], ],
[ [
["cookies", "sectest1.example.org"], ["cookies", "sectest1.example.org"],
[ [
getCookieId("uc1", ".example.org", "/"), getCookieId("uc1", ".example.org", "/"),
getCookieId("uc2", ".example.org", "/"),
getCookieId("cs2", ".example.org", "/"), getCookieId("cs2", ".example.org", "/"),
getCookieId("sc1", "sectest1.example.org", "/browser/devtools/client/storage/test/") getCookieId("c4", ".example.org", "/"),
getCookieId("sc1", "sectest1.example.org",
"/browser/devtools/client/storage/test/"),
getCookieId("sc2", "sectest1.example.org",
"/browser/devtools/client/storage/test/")
] ]
], ],
[["localStorage", "http://test1.example.org"], [["localStorage", "http://test1.example.org"],

View file

@ -8,11 +8,13 @@
// Test deleting all cookies // Test deleting all cookies
function* performDelete(store, rowName, deleteAll) { function* performDelete(store, rowName, action) {
let contextMenu = gPanelWindow.document.getElementById( let contextMenu = gPanelWindow.document.getElementById(
"storage-table-popup"); "storage-table-popup");
let menuDeleteAllItem = contextMenu.querySelector( let menuDeleteAllItem = contextMenu.querySelector(
"#storage-table-popup-delete-all"); "#storage-table-popup-delete-all");
let menuDeleteAllSessionCookiesItem = contextMenu.querySelector(
"#storage-table-popup-delete-all-session-cookies");
let menuDeleteAllFromItem = contextMenu.querySelector( let menuDeleteAllFromItem = contextMenu.querySelector(
"#storage-table-popup-delete-all-from"); "#storage-table-popup-delete-all-from");
@ -25,13 +27,19 @@ function* performDelete(store, rowName, deleteAll) {
yield waitForContextMenu(contextMenu, cells.name, () => { yield waitForContextMenu(contextMenu, cells.name, () => {
info(`Opened context menu in ${storeName}, row '${rowName}'`); info(`Opened context menu in ${storeName}, row '${rowName}'`);
if (deleteAll) { switch (action) {
menuDeleteAllItem.click(); case "deleteAll":
} else { menuDeleteAllItem.click();
menuDeleteAllFromItem.click(); break;
let hostName = cells.host.value; case "deleteAllSessionCookies":
ok(menuDeleteAllFromItem.getAttribute("label").includes(hostName), menuDeleteAllSessionCookiesItem.click();
break;
case "deleteAllFrom":
menuDeleteAllFromItem.click();
let hostName = cells.host.value;
ok(menuDeleteAllFromItem.getAttribute("label").includes(hostName),
`Context menu item label contains '${hostName}'`); `Context menu item label contains '${hostName}'`);
break;
} }
}); });
@ -48,15 +56,21 @@ add_task(function* () {
getCookieId("c1", "test1.example.org", "/browser"), getCookieId("c1", "test1.example.org", "/browser"),
getCookieId("c3", "test1.example.org", "/"), getCookieId("c3", "test1.example.org", "/"),
getCookieId("cs2", ".example.org", "/"), getCookieId("cs2", ".example.org", "/"),
getCookieId("uc1", ".example.org", "/") getCookieId("c4", ".example.org", "/"),
getCookieId("uc1", ".example.org", "/"),
getCookieId("uc2", ".example.org", "/")
] ]
], ],
[ [
["cookies", "sectest1.example.org"], [ ["cookies", "sectest1.example.org"], [
getCookieId("cs2", ".example.org", "/"), getCookieId("cs2", ".example.org", "/"),
getCookieId("c4", ".example.org", "/"),
getCookieId("sc1", "sectest1.example.org", getCookieId("sc1", "sectest1.example.org",
"/browser/devtools/client/storage/test/"), "/browser/devtools/client/storage/test/"),
getCookieId("uc1", ".example.org", "/") getCookieId("sc2", "sectest1.example.org",
"/browser/devtools/client/storage/test/"),
getCookieId("uc1", ".example.org", "/"),
getCookieId("uc2", ".example.org", "/")
] ]
], ],
]); ]);
@ -64,6 +78,7 @@ add_task(function* () {
info("delete all from domain"); info("delete all from domain");
// delete only cookies that match the host exactly // delete only cookies that match the host exactly
let id = getCookieId("c1", "test1.example.org", "/browser"); let id = getCookieId("c1", "test1.example.org", "/browser");
yield performDelete(["cookies", "test1.example.org"], id, "deleteAllFrom");
yield performDelete(["cookies", "test1.example.org"], id, false); yield performDelete(["cookies", "test1.example.org"], id, false);
info("test state after delete all from domain"); info("test state after delete all from domain");
@ -73,24 +88,57 @@ add_task(function* () {
["cookies", "test1.example.org"], ["cookies", "test1.example.org"],
[ [
getCookieId("cs2", ".example.org", "/"), getCookieId("cs2", ".example.org", "/"),
getCookieId("uc1", ".example.org", "/") getCookieId("c4", ".example.org", "/"),
getCookieId("uc1", ".example.org", "/"),
getCookieId("uc2", ".example.org", "/")
] ]
], ],
[ [
["cookies", "sectest1.example.org"], ["cookies", "sectest1.example.org"],
[ [
getCookieId("cs2", ".example.org", "/"), getCookieId("cs2", ".example.org", "/"),
getCookieId("c4", ".example.org", "/"),
getCookieId("uc1", ".example.org", "/"), getCookieId("uc1", ".example.org", "/"),
getCookieId("uc2", ".example.org", "/"),
getCookieId("sc1", "sectest1.example.org", getCookieId("sc1", "sectest1.example.org",
"/browser/devtools/client/storage/test/"), "/browser/devtools/client/storage/test/"),
getCookieId("sc2", "sectest1.example.org",
"/browser/devtools/client/storage/test/")
]
],
]);
info("delete all session cookies");
// delete only session cookies
id = getCookieId("cs2", ".example.org", "/");
yield performDelete(["cookies", "sectest1.example.org"], id,
"deleteAllSessionCookies");
info("test state after delete all session cookies");
yield checkState([
// Cookies with expiry date must not be deleted.
[
["cookies", "test1.example.org"],
[
getCookieId("c4", ".example.org", "/"),
getCookieId("uc2", ".example.org", "/")
]
],
[
["cookies", "sectest1.example.org"],
[
getCookieId("c4", ".example.org", "/"),
getCookieId("uc2", ".example.org", "/"),
getCookieId("sc2", "sectest1.example.org",
"/browser/devtools/client/storage/test/")
] ]
], ],
]); ]);
info("delete all"); info("delete all");
// delete all cookies for host, including domain cookies // delete all cookies for host, including domain cookies
id = getCookieId("uc1", ".example.org", "/"); id = getCookieId("uc2", ".example.org", "/");
yield performDelete(["cookies", "sectest1.example.org"], id, true); yield performDelete(["cookies", "sectest1.example.org"], id, "deleteAll");
info("test state after delete all"); info("test state after delete all");
yield checkState([ yield checkState([

View file

@ -23,7 +23,9 @@ add_task(function* () {
getCookieId("c1", "test1.example.org", "/browser"), getCookieId("c1", "test1.example.org", "/browser"),
getCookieId("cs2", ".example.org", "/"), getCookieId("cs2", ".example.org", "/"),
getCookieId("c3", "test1.example.org", "/"), getCookieId("c3", "test1.example.org", "/"),
getCookieId("uc1", ".example.org", "/") getCookieId("c4", ".example.org", "/"),
getCookieId("uc1", ".example.org", "/"),
getCookieId("uc2", ".example.org", "/")
] ]
], ],
[["localStorage", "http://test1.example.org"], ["ls1", "ls2"]], [["localStorage", "http://test1.example.org"], ["ls1", "ls2"]],

View file

@ -20,7 +20,10 @@ document.cookie = "c1=foobar; expires=" +
new Date(cookieExpiresTime1).toGMTString() + "; path=/browser"; new Date(cookieExpiresTime1).toGMTString() + "; path=/browser";
document.cookie = "cs2=sessionCookie; path=/; domain=" + partialHostname; document.cookie = "cs2=sessionCookie; path=/; domain=" + partialHostname;
document.cookie = "c3=foobar-2; expires=" + document.cookie = "c3=foobar-2; expires=" +
new Date(cookieExpiresTime2).toGMTString() + "; path=/"; new Date(cookieExpiresTime1).toGMTString() + "; path=/";
document.cookie = "c4=foobar-3; expires=" +
new Date(cookieExpiresTime2).toGMTString() + "; path=/; domain=" +
partialHostname;
// ... and some local storage items .. // ... and some local storage items ..
localStorage.setItem("ls1", "foobar"); localStorage.setItem("ls1", "foobar");
localStorage.setItem("ls2", "foobar-2"); localStorage.setItem("ls2", "foobar-2");

View file

@ -1,4 +1,4 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html>
<!-- <!--
Iframe for testing multiple host detetion in storage actor Iframe for testing multiple host detetion in storage actor
@ -9,7 +9,10 @@ Iframe for testing multiple host detetion in storage actor
<body> <body>
<script type="application/javascript;version=1.7"> <script type="application/javascript;version=1.7">
"use strict"; "use strict";
let cookieExpiresTime = 2000000000000;
document.cookie = "sc1=foobar;"; document.cookie = "sc1=foobar;";
document.cookie = "sc2=foobar-2; expires=" +
new Date(cookieExpiresTime).toGMTString() + ";";
localStorage.setItem("iframe-s-ls1", "foobar"); localStorage.setItem("iframe-s-ls1", "foobar");
sessionStorage.setItem("iframe-s-ss1", "foobar-2"); sessionStorage.setItem("iframe-s-ss1", "foobar-2");
dump("added cookies and storage from secured iframe\n"); dump("added cookies and storage from secured iframe\n");

View file

@ -9,7 +9,10 @@ Iframe for testing multiple host detetion in storage actor
<body> <body>
<script> <script>
"use strict"; "use strict";
let cookieExpiresTime = 2000000000000;
document.cookie = "uc1=foobar; domain=.example.org; path=/"; document.cookie = "uc1=foobar; domain=.example.org; path=/";
document.cookie = "uc2=foobar-2; expires=" +
new Date(cookieExpiresTime).toGMTString() + "; path=/; domain=.example.org";
localStorage.setItem("iframe-u-ls1", "foobar"); localStorage.setItem("iframe-u-ls1", "foobar");
sessionStorage.setItem("iframe-u-ss1", "foobar1"); sessionStorage.setItem("iframe-u-ss1", "foobar1");
sessionStorage.setItem("iframe-u-ss2", "foobar2"); sessionStorage.setItem("iframe-u-ss2", "foobar2");

View file

@ -163,6 +163,7 @@ function StorageUI(front, target, panelWin, toolbox) {
this.onRemoveItem = this.onRemoveItem.bind(this); this.onRemoveItem = this.onRemoveItem.bind(this);
this.onRemoveAllFrom = this.onRemoveAllFrom.bind(this); this.onRemoveAllFrom = this.onRemoveAllFrom.bind(this);
this.onRemoveAll = this.onRemoveAll.bind(this); this.onRemoveAll = this.onRemoveAll.bind(this);
this.onRemoveAllSessionCookies = this.onRemoveAllSessionCookies.bind(this);
this.onRemoveTreeItem = this.onRemoveTreeItem.bind(this); this.onRemoveTreeItem = this.onRemoveTreeItem.bind(this);
this._tablePopupDelete = this._panelDoc.getElementById( this._tablePopupDelete = this._panelDoc.getElementById(
@ -178,10 +179,20 @@ function StorageUI(front, target, panelWin, toolbox) {
"storage-table-popup-delete-all"); "storage-table-popup-delete-all");
this._tablePopupDeleteAll.addEventListener("command", this.onRemoveAll); this._tablePopupDeleteAll.addEventListener("command", this.onRemoveAll);
this._tablePopupDeleteAllSessionCookies = this._panelDoc.getElementById(
"storage-table-popup-delete-all-session-cookies");
this._tablePopupDeleteAllSessionCookies.addEventListener("command",
this.onRemoveAllSessionCookies);
this._treePopupDeleteAll = this._panelDoc.getElementById( this._treePopupDeleteAll = this._panelDoc.getElementById(
"storage-tree-popup-delete-all"); "storage-tree-popup-delete-all");
this._treePopupDeleteAll.addEventListener("command", this.onRemoveAll); this._treePopupDeleteAll.addEventListener("command", this.onRemoveAll);
this._treePopupDeleteAllSessionCookies = this._panelDoc.getElementById(
"storage-tree-popup-delete-all-session-cookies");
this._treePopupDeleteAllSessionCookies.addEventListener("command",
this.onRemoveAllSessionCookies);
this._treePopupDelete = this._panelDoc.getElementById("storage-tree-popup-delete"); this._treePopupDelete = this._panelDoc.getElementById("storage-tree-popup-delete");
this._treePopupDelete.addEventListener("command", this.onRemoveTreeItem); this._treePopupDelete.addEventListener("command", this.onRemoveTreeItem);
} }
@ -211,12 +222,16 @@ StorageUI.prototype = {
this._treePopup.removeEventListener("popupshowing", this.onTreePopupShowing); this._treePopup.removeEventListener("popupshowing", this.onTreePopupShowing);
this._treePopupDeleteAll.removeEventListener("command", this.onRemoveAll); this._treePopupDeleteAll.removeEventListener("command", this.onRemoveAll);
this._treePopupDeleteAllSessionCookies.removeEventListener("command",
this.onRemoveAllSessionCookies);
this._treePopupDelete.removeEventListener("command", this.onRemoveTreeItem); this._treePopupDelete.removeEventListener("command", this.onRemoveTreeItem);
this._tablePopup.removeEventListener("popupshowing", this.onTablePopupShowing); this._tablePopup.removeEventListener("popupshowing", this.onTablePopupShowing);
this._tablePopupDelete.removeEventListener("command", this.onRemoveItem); this._tablePopupDelete.removeEventListener("command", this.onRemoveItem);
this._tablePopupDeleteAllFrom.removeEventListener("command", this.onRemoveAllFrom); this._tablePopupDeleteAllFrom.removeEventListener("command", this.onRemoveAllFrom);
this._tablePopupDeleteAll.removeEventListener("command", this.onRemoveAll); this._tablePopupDeleteAll.removeEventListener("command", this.onRemoveAll);
this._tablePopupDeleteAllSessionCookies.removeEventListener("command",
this.onRemoveAllSessionCookies);
}, },
/** /**
@ -453,22 +468,24 @@ StorageUI.prototype = {
* @param {object} See onUpdate docs * @param {object} See onUpdate docs
*/ */
handleChangedItems: function (changed) { handleChangedItems: function (changed) {
let [type, host, db, objectStore] = this.tree.selectedItem; if (this.tree.selectedItem) {
if (!changed[type] || !changed[type][host] || let [type, host, db, objectStore] = this.tree.selectedItem;
changed[type][host].length == 0) { if (!changed[type] || !changed[type][host] ||
return; changed[type][host].length == 0) {
} return;
try { }
let toUpdate = []; try {
for (let name of changed[type][host]) { let toUpdate = [];
let names = JSON.parse(name); for (let name of changed[type][host]) {
if (names[0] == db && names[1] == objectStore && names[2]) { let names = JSON.parse(name);
toUpdate.push(name); if (names[0] == db && names[1] == objectStore && names[2]) {
} toUpdate.push(name);
}
}
this.fetchStorageObjects(type, host, toUpdate, REASON.UPDATE);
} catch (ex) {
this.fetchStorageObjects(type, host, changed[type][host], REASON.UPDATE);
} }
this.fetchStorageObjects(type, host, toUpdate, REASON.UPDATE);
} catch (ex) {
this.fetchStorageObjects(type, host, changed[type][host], REASON.UPDATE);
} }
}, },
@ -957,6 +974,15 @@ StorageUI.prototype = {
this._tablePopupDelete.setAttribute("label", this._tablePopupDelete.setAttribute("label",
L10N.getFormatStr("storage.popupMenu.deleteLabel", label)); L10N.getFormatStr("storage.popupMenu.deleteLabel", label));
let showDeleteAllSessionCookies = false;
if (selectedItem && actor.removeAllSessionCookies) {
if (type === "cookies" && selectedItem.length === 2) {
showDeleteAllSessionCookies = true;
}
}
this._tablePopupDeleteAllSessionCookies.hidden = !showDeleteAllSessionCookies;
if (type === "cookies") { if (type === "cookies") {
let host = addEllipsis(data.host); let host = addEllipsis(data.host);
@ -997,6 +1023,17 @@ StorageUI.prototype = {
this._treePopupDeleteAll.hidden = !showDeleteAll; this._treePopupDeleteAll.hidden = !showDeleteAll;
// The delete all session cookies action is displayed for cookie object stores
// (level 2 of tree)
let showDeleteAllSessionCookies = false;
if (actor.removeAllSessionCookies) {
if (type === "cookies" && selectedItem.length === 2) {
showDeleteAllSessionCookies = true;
}
}
this._treePopupDeleteAllSessionCookies.hidden = !showDeleteAllSessionCookies;
// The delete action is displayed for: // The delete action is displayed for:
// - IndexedDB databases (level 3 of the tree) // - IndexedDB databases (level 3 of the tree)
// - Cache objects (level 3 of the tree) // - Cache objects (level 3 of the tree)
@ -1037,14 +1074,27 @@ StorageUI.prototype = {
*/ */
onRemoveAll: function () { onRemoveAll: function () {
// Cannot use this.currentActor() if the handler is called from the // Cannot use this.currentActor() if the handler is called from the
// tree context menu: it returns correct value only after the table // tree context menu: it returns the correct value only after the
// data from server are successfully fetched (and that's async). // table data from server are successfully fetched (and that's async).
let [type, host, ...path] = this.tree.selectedItem; let [type, host, ...path] = this.tree.selectedItem;
let actor = this.storageTypes[type]; let actor = this.storageTypes[type];
let name = path.length > 0 ? JSON.stringify(path) : undefined; let name = path.length > 0 ? JSON.stringify(path) : undefined;
actor.removeAll(host, name); actor.removeAll(host, name);
}, },
/**
* Handles removing all session cookies from the storage
*/
onRemoveAllSessionCookies: function () {
// Cannot use this.currentActor() if the handler is called from the
// tree context menu: it returns the correct value only after the
// table data from server is successfully fetched (and that's async).
let [, host, ...path] = this.tree.selectedItem;
let actor = this.getCurrentActor();
let name = path.length > 0 ? JSON.stringify(path) : undefined;
actor.removeAllSessionCookies(host, name);
},
/** /**
* Handles removing all cookies with exactly the same domain as the * Handles removing all cookies with exactly the same domain as the
* cookie in the selected row. * cookie in the selected row.

View file

@ -628,6 +628,12 @@ StorageActors.createActor({
.originAttributes); .originAttributes);
}), }),
removeAllSessionCookies: Task.async(function* (host, domain) {
let doc = this.storageActor.document;
this.removeAllSessionCookies(host, domain, doc.nodePrincipal
.originAttributes);
}),
maybeSetupChildProcess() { maybeSetupChildProcess() {
cookieHelpers.onCookieChanged = this.onCookieChanged.bind(this); cookieHelpers.onCookieChanged = this.onCookieChanged.bind(this);
@ -644,6 +650,8 @@ StorageActors.createActor({
cookieHelpers.removeCookie.bind(cookieHelpers); cookieHelpers.removeCookie.bind(cookieHelpers);
this.removeAllCookies = this.removeAllCookies =
cookieHelpers.removeAllCookies.bind(cookieHelpers); cookieHelpers.removeAllCookies.bind(cookieHelpers);
this.removeAllSessionCookies =
cookieHelpers.removeAllSessionCookies.bind(cookieHelpers);
return; return;
} }
@ -667,6 +675,8 @@ StorageActors.createActor({
callParentProcess.bind(null, "removeCookie"); callParentProcess.bind(null, "removeCookie");
this.removeAllCookies = this.removeAllCookies =
callParentProcess.bind(null, "removeAllCookies"); callParentProcess.bind(null, "removeAllCookies");
this.removeAllSessionCookies =
callParentProcess.bind(null, "removeAllSessionCookies");
addMessageListener("debug:storage-cookie-request-child", addMessageListener("debug:storage-cookie-request-child",
cookieHelpers.handleParentRequest); cookieHelpers.handleParentRequest);
@ -853,7 +863,8 @@ var cookieHelpers = {
if (hostMatches(cookie.host, host) && if (hostMatches(cookie.host, host) &&
(!opts.name || cookie.name === opts.name) && (!opts.name || cookie.name === opts.name) &&
(!opts.domain || cookie.host === opts.domain) && (!opts.domain || cookie.host === opts.domain) &&
(!opts.path || cookie.path === opts.path)) { (!opts.path || cookie.path === opts.path) &&
(!opts.session || (!cookie.expires && !cookie.maxAge))) {
Services.cookies.remove( Services.cookies.remove(
cookie.host, cookie.host,
cookie.name, cookie.name,
@ -875,6 +886,10 @@ var cookieHelpers = {
this._removeCookies(host, { domain, originAttributes }); this._removeCookies(host, { domain, originAttributes });
}, },
removeAllSessionCookies(host, domain, originAttributes) {
this._removeCookies(host, { domain, originAttributes, session: true });
},
addCookieObservers() { addCookieObservers() {
Services.obs.addObserver(cookieHelpers, "cookie-changed", false); Services.obs.addObserver(cookieHelpers, "cookie-changed", false);
return null; return null;
@ -951,6 +966,12 @@ var cookieHelpers = {
let originAttributes = msg.data.args[2]; let originAttributes = msg.data.args[2];
return cookieHelpers.removeAllCookies(host, domain, originAttributes); return cookieHelpers.removeAllCookies(host, domain, originAttributes);
} }
case "removeAllSessionCookies": {
let host = msg.data.args[0];
let domain = msg.data.args[1];
let originAttributes = msg.data.args[2];
return cookieHelpers.removeAllSessionCookies(host, domain, originAttributes);
}
default: default:
console.error("ERR_DIRECTOR_PARENT_UNKNOWN_METHOD", msg.json.method); console.error("ERR_DIRECTOR_PARENT_UNKNOWN_METHOD", msg.json.method);
throw new Error("ERR_DIRECTOR_PARENT_UNKNOWN_METHOD"); throw new Error("ERR_DIRECTOR_PARENT_UNKNOWN_METHOD");

View file

@ -97,6 +97,14 @@ createStorageSpec({
}, },
response: {} response: {}
} }
}, {
removeAllSessionCookies: {
request: {
host: Arg(0, "string"),
domain: Arg(1, "nullable:string")
},
response: {}
}
} }
) )
}); });