in src/js/background.js [301:515]
export function handleMessages(message, sender, sendResponse) {
console.log('in handle messages ', message);
if (message.type == MESSAGE_TYPE.UPDATE_ICON) {
updateIcon(message, sender);
return;
}
if (message.type == MESSAGE_TYPE.LOAD_MANIFEST) {
// validate manifest
if ([ORIGIN_TYPE.FACEBOOK].includes(message.origin)) {
validateMetaCompanyManifest(
message.rootHash,
message.otherHashes,
message.leaves
).then(valid => {
console.log('result is ', valid);
if (valid) {
let origin = manifestCache.get(message.origin);
if (origin == null) {
origin = new Map();
manifestCache.set(message.origin, origin);
}
// roll through the existing manifests and remove expired ones
if (ORIGIN_TIMEOUT[message.origin] > 0) {
for (let [key, manif] of origin.entries()) {
if (manif.start + ORIGIN_TIMEOUT[message.origin] < Date.now()) {
origin.delete(key);
}
}
}
let manifest = origin.get(message.version);
if (!manifest) {
manifest = {
leaves: [],
root: message.rootHash,
start: Date.now(),
};
origin.set(message.version, manifest);
}
message.leaves.forEach(leaf => {
if (!manifest.leaves.includes(leaf)) {
manifest.leaves.push(leaf);
}
});
sendResponse({ valid: true });
} else {
sendResponse({ valid: false });
}
});
} else {
const slicedHash = message.rootHash.slice(2);
const slicedLeaves = message.leaves.map(leaf => {
return leaf.slice(2);
});
validateManifest(
slicedHash,
slicedLeaves,
ORIGIN_HOST[message.origin],
message.version,
message.workaround
).then(validationResult => {
if (validationResult.valid) {
// store manifest to subsequently validate JS
let origin = manifestCache.get(message.origin);
if (origin == null) {
origin = new Map();
manifestCache.set(message.origin, origin);
}
// roll through the existing manifests and remove expired ones
if (ORIGIN_TIMEOUT[message.origin] > 0) {
for (let [key, manif] of origin.entries()) {
if (manif.start + ORIGIN_TIMEOUT[message.origin] < Date.now()) {
origin.delete(key);
}
}
}
console.log('result is ', validationResult.valid);
origin.set(message.version, {
leaves: slicedLeaves,
root: slicedHash,
start: Date.now(),
});
sendResponse({ valid: true });
} else {
sendResponse(validationResult);
}
});
}
return true;
}
if (message.type == MESSAGE_TYPE.JS_WITH_SRC) {
// exclude known extension scripts from analysis
if (
message.src.indexOf('chrome-extension://') === 0 ||
message.src.indexOf('moz-extension://') === 0
) {
addDebugLog(
sender.tab.id,
'Warning: User installed extension inserted script ' + message.src
);
sendResponse({
valid: false,
type: 'EXTENSION',
reason: 'User installed extension has inserted script',
});
return;
}
const origin = manifestCache.get(message.origin);
if (!origin) {
addDebugLog(
sender.tab.id,
'Error: JS with SRC had no matching origin ' + message.origin
);
sendResponse({ valid: false, reason: 'no matching origin' });
return;
}
const manifestObj = origin.get(message.version);
const manifest = manifestObj && manifestObj.leaves;
if (!manifest) {
addDebugLog(
sender.tab.id,
'Error: JS with SRC had no matching manifest. origin: ' +
message.origin +
' version: ' +
message.version
);
sendResponse({ valid: false, reason: 'no matching manifest' });
return;
}
// fetch and process the src
processJSWithSrc(message, manifestObj, sender.tab.id).then(valid => {
console.log('sending processJSWithSrc response ', valid);
sendResponse({ valid: valid });
});
return true;
}
if (message.type == MESSAGE_TYPE.RAW_JS) {
const origin = manifestCache.get(message.origin);
if (!origin) {
addDebugLog(
sender.tab.id,
'Error: RAW_JS had no matching origin ' + message.origin
);
sendResponse({ valid: false, reason: 'no matching origin' });
return;
}
const manifestObj = origin.get(message.version);
const manifest = manifestObj && manifestObj.leaves;
if (!manifest) {
addDebugLog(
sender.tab.id,
'Error: JS with SRC had no matching manifest. origin: ' +
message.origin +
' version: ' +
message.version
);
sendResponse({ valid: false, reason: 'no matching manifest' });
return;
}
// fetch the src
const encoder = new TextEncoder();
const encodedJS = encoder.encode(message.rawjs);
// hash the src
crypto.subtle.digest('SHA-256', encodedJS).then(jsHashBuffer => {
const jsHashArray = Array.from(new Uint8Array(jsHashBuffer));
const jsHash = jsHashArray
.map(b => b.toString(16).padStart(2, '0'))
.join('');
console.log('generate hash is ', jsHash);
if (manifestObj.leaves.includes(jsHash)) {
sendResponse({ valid: true });
} else {
addDebugLog(
sender.tab.id,
'Error: hash does not match ' +
message.origin +
', ' +
message.version +
', unmatched JS is ' +
message.rawjs.substring(0, 500)
);
sendResponse({
valid: false,
hash: jsHash,
reason:
'Error: hash does not match ' +
message.origin +
', ' +
message.version +
', unmatched JS is ' +
message.rawjs,
});
}
});
return true;
}
if (message.type == MESSAGE_TYPE.DEBUG) {
addDebugLog(sender.tab.id, message.log);
return;
}
if (message.type == MESSAGE_TYPE.GET_DEBUG) {
const debuglist = getDebugLog(message.tabId);
console.log('debug list is ', message.tabId, debuglist);
sendResponse({ valid: true, debugList: debuglist });
return;
}
}