Skip to content

Commit

Permalink
Merge branch 'subdomains-support'
Browse files Browse the repository at this point in the history
  • Loading branch information
dud3z committed Jan 21, 2017
2 parents 5bdf251 + a71ea60 commit a9f9899
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 22 deletions.
113 changes: 93 additions & 20 deletions src/knoxss.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
scan URLs via the KNOXSS service.
*/

/* keep track of the extension's state state across the tabs */
/* keep track of the extension's state state across the tabs
(default value in [brackets]) */
var domain_state = {
/*
domain: {
active: true|false,
xssed: true|false,
urls: []
active: true|[false],
xssed: true|[false],
is_second_level_domain: true|false,
handle_subdomains: [true]|false,
parent_domain: '', [empty]
urls: [], [empty]
}
*/
};
Expand All @@ -29,11 +33,28 @@ function setCurrentDomain(domain) {
}

function createState(domain) {
setState(domain, {
active: false,
var isLevel2Domain = isSecondLevelDomain(domain);
var parentIsActive = false;
var parentDomain = getSecondLevelDomain(domain);

if(!isLevel2Domain) {
// it might be a subdomain of a currently active second-level domain
if(hasState(parentDomain)) {
var ds = getState(parentDomain);
parentIsActive = ds.active && ds.handle_subdomains;
}
}

var newState = {
active: parentIsActive,
xssed: false,
is_second_level_domain: isLevel2Domain,
handle_subdomains: isLevel2Domain,
parent_domain: parentDomain,
urls: []
});
};

setState(domain, newState);
return getState(domain);
}

Expand Down Expand Up @@ -90,6 +111,8 @@ function tabUpdate(tabId, changeInfo, tab) {
setPopupDomain(tab, domain);

var ds = getOrCreateState(domain);
updateUI(tab, domain, ds);

if( ds.active ) {
// the extension is active for the specified domain

Expand All @@ -107,8 +130,6 @@ function tabUpdate(tabId, changeInfo, tab) {
// query the KNOXSS service
queryKnoxss(tab, domain, currentUrl, cookies);
});
} else {
updateUI(tab, domain, ds);
}
} else {
console.log("Ignoring update request on invalid domain \"" + domain + "\"");
Expand All @@ -131,6 +152,9 @@ function onMessage(request, sender, sendResponse) {
deleteDomainState();
syncWithActiveTab();
// return false;
} else if( request.handle_subdomains ) {
// enable or disable processing of subdomains for the active tab
setHandleSubdomains(request.value);
}
return false;
}
Expand All @@ -145,7 +169,64 @@ main();

/** Utilities */

/* UI abstraction utilities */
/* UI and abstraction utilities */

/* enables or disables the processing of subdomains for the currently active tab */
function setHandleSubdomains(value) {
getActiveTab().then((tabs) => {
var tab = tabs[0];
var domain = getDomainFromURL(tab.url);
if(isValidDomain(domain)) {
var ds = getOrCreateState(domain);
ds.handle_subdomains = value;
setState(domain, ds);
console.log("Automatic subdomain handling " + (value ? "activated" : "deactivated") + " for \"*." + domain + "\"");

updateSubdomainsState(domain);
updateUI(tab, domain, ds);
} else {
console.log("Ignoring toggle processing subdomains request on invalid domain \"" + domain + "\"");
}
});
}

/* updates state for each subdomain that belongs to the specified domain */
function updateSubdomainsState(domain) {
var ds = getOrCreateState(domain);

// search and update for subdomains
for(var subdomain in domain_state) {
if(isSubdomainOf(domain, subdomain)) {
var subds = getOrCreateState(subdomain);
subds.active = ds.handle_subdomains && ds.active;
console.log("Subdomain \"" + subdomain + "\" has been automatically " + (subds.active ? "activated" : "deactivated") + ", parent domain is \"" + subds.parent_domain + "\"");
}
}

storeDomainState();
}

/* whether the specified domain is a subdomain of the specified domain */
function isSubdomainOf(domain, subdomain) {
var ds = getOrCreateState(domain);
var subds = getOrCreateState(subdomain);
if(ds.is_second_level_domain && !subds.is_second_level_domain && subds.parent_domain === domain) {
return true;
}
return false;
}

/* whether the specified domain is a second-level domain */
function isSecondLevelDomain(domain) {
return (domain.split('.').length == 2);
}

function getSecondLevelDomain(domain) {
// early exit
if(isSecondLevelDomain(domain)) return domain;
var parts = domain.split('.');
return parts[parts.length-2] + "." + parts[parts.length-1];
}

// Stores and signal the specified domain as the currently active one
// so `storage.onChanged` listeners may react accordingly: this only
Expand All @@ -169,6 +250,8 @@ function toggleState() {
ds.xssed = false;
ds.active = !ds.active;
setState(domain, ds);

updateSubdomainsState(domain);
updateUI(tab, domain, ds);
} else {
console.log("Ignoring toggle request on invalid domain \"" + domain + "\"");
Expand Down Expand Up @@ -214,16 +297,6 @@ function getActiveTab() {
// update the browser_action button only if either the request comes from the active tab
// or the domain is the same for both tabs
function updateUI(tab, domain, state) {
/*
TODO: use different icons instead of using only one.
TODO2: verify using both a `browser_action` and a `page_action` is supported
across browsers (it doesn't look it will be supported on Chrome ;/)
Currently the KNOXSS icon is used to signal XSS presence as a page action:
some proper graphics should be done the same as the current badge appears
on the Toggle toolbar extension's button.
*/

getActiveTab().then((tabs) => {
var activeTab = tabs[0];
var canUpdate = (activeTab.id == tab.id) || (getDomainFromURL(activeTab.url) === getDomainFromURL(tab.url));
Expand Down
12 changes: 10 additions & 2 deletions src/popup/popup.css
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,19 @@ hr {
width: 90%;
}

#domainlist input[type="checkbox"] {
#handle_subdomains {
display: inline-block;
margin: 0;
padding: 0 0 0 0;
height: 20px;
}

#handle_subdomains input[type="checkbox"] {
display: inline-block;
position: relative;
padding: 0;
vertical-align: middle;
margin: 0 4px 0 0;
vertical-align: top;
}

.domainitem {
Expand Down
1 change: 1 addition & 0 deletions src/popup/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<td>
<h3 id="domain">domain</h3>
<h4 id="state">state</h4>
<label id="handle_subdomains"><input type="checkbox"><span id="subdomain">Handle subdomains</span></label>
</td>
</tr>
<tr>
Expand Down
25 changes: 25 additions & 0 deletions src/popup/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
var ui_icon = document.querySelector('img#icon');
var ui_domain = document.querySelector('#domain');
var ui_state = document.querySelector('#state');
var ui_subdomains = document.querySelector('#handle_subdomains');
var ui_subdomains_cb = document.querySelector('#handle_subdomains input[type=checkbox]');
var ui_subdomains_text = document.querySelector('#handle_subdomains span');
var ui_toggle = document.querySelector('#toggle');
var ui_title = document.querySelector('#title');
var ui_copy = document.querySelector('#copy');
Expand Down Expand Up @@ -190,13 +193,27 @@ function hideClearState() {
hide(ui_clearstate);
}

function showHandleSubdomains(domain, handleSubdomains) {
show(ui_subdomains);
show(ui_subdomains_cb);
setHtml(ui_subdomains_text, "Auto-activate on <strong>*." + domain + "</strong> subdomains.");
ui_subdomains_cb.checked = handleSubdomains;
}

function showSubdomainOf(domain) {
show(ui_subdomains);
hide(ui_subdomains_cb);
setHtml(ui_subdomains_text, "Subdomain of <strong>*." + domain + "</strong>");
}

// resets the UI to a minimal state, only the icon, the
// domain and the state are shown
function resetUI() {
show(ui_icon);
show(ui_domain);
show(ui_state);

hide(ui_subdomains);
disableToggle();
hideResults();
hideTitle();
Expand Down Expand Up @@ -241,6 +258,11 @@ function updateUI(data) {

// domain
setDomain("<span class='domain " + (state.xssed ? "xssed" : state.active ? "active" : "") + "'>" + domain + "</span>");
if(state.is_second_level_domain) {
showHandleSubdomains(domain, state.handle_subdomains);
} else {
showSubdomainOf(state.parent_domain);
}

if( state.active ) {
showTitle("No XSS found yet.");
Expand Down Expand Up @@ -276,6 +298,9 @@ ui_clearstate.onclick = function(e) {
browser.runtime.sendMessage({clear_state: true});
}

ui_subdomains_cb.onchange = function(e) {
browser.runtime.sendMessage({handle_subdomains: true, value: this.checked});
}

/* sync UI to data changes */
browser.storage.onChanged.addListener((changes, area) => { reload(); });
Expand Down

0 comments on commit a9f9899

Please sign in to comment.