Skip to content

Commit 07fe5bd

Browse files
authored
Merge pull request #1 from phreakocious/manifest_v3
update Chrome extension to manifest v3!
2 parents 1ab08f5 + eac6707 commit 07fe5bd

File tree

2 files changed

+107
-84
lines changed

2 files changed

+107
-84
lines changed

dist/httpgraph.js

Lines changed: 68 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,106 @@
11
/*
22
httpgraph.js
3-
@phreakocious - 2017-2022
3+
@phreakocious - 2017-2025
44
55
Chrome extension to accompany the HTTP Graph plugin for Gephi
66
Collects minimal details from http and https request/response headers and POSTs them to a REST API as you browse
77
I'm not a JS programmer
88
*/
99

10-
var scrub_parameters
11-
var url_backend
12-
const default_rest_port = "65444"
13-
const default_scrub_parameters = false
10+
const default_rest_port = "65444";
11+
const default_scrub_parameters = false;
1412

15-
chrome.storage.local.get({
16-
rest_port: default_rest_port,
17-
scrub_parameters: default_scrub_parameters
18-
}, function(items) {
19-
rest_port = items.rest_port
20-
scrub_parameters = items.scrub_parameters
21-
url_backend = "http://127.0.0.1:" + rest_port + "/add_record" // data will POST to here
22-
})
23-
24-
function sendLog(message, callback) {
25-
//console.log(message)
26-
var xhr = new XMLHttpRequest()
27-
xhr.open("POST", url_backend, true)
28-
xhr.send(message + "\r\n")
29-
}
30-
31-
// hashing function courtesy of bryc https://github.com/bryc/code/blob/master/jshash/experimental/cyrb53.js
32-
const cyrb53 = function(str, seed = 42) {
33-
let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed
13+
// hashing function courtesy of bryc https://github.com/bryc/code/blob/master/jshash/experimental/cyrb53.js
14+
const cyrb53 = (str, seed = 42) => {
15+
let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
3416
for (let i = 0, ch; i < str.length; i++) {
35-
ch = str.charCodeAt(i)
36-
h1 = Math.imul(h1 ^ ch, 2654435761)
37-
h2 = Math.imul(h2 ^ ch, 1597334677)
17+
ch = str.charCodeAt(i);
18+
h1 = Math.imul(h1 ^ ch, 2654435761);
19+
h2 = Math.imul(h2 ^ ch, 1597334677);
3820
}
39-
h1 = Math.imul(h1 ^ (h1>>>16), 2246822507) ^ Math.imul(h2 ^ (h2>>>13), 3266489909)
40-
h2 = Math.imul(h2 ^ (h2>>>16), 2246822507) ^ Math.imul(h1 ^ (h1>>>13), 3266489909)
41-
return 4294967296 * (2097151 & h2) + (h1>>>0)
42-
}
21+
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
22+
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
23+
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
24+
};
4325

4426
function scrubber(match, p1, offset, string) {
45-
return "?SCRUBBED_hash=" + cyrb53(p1)
27+
return "?SCRUBBED_hash=" + cyrb53(p1);
4628
}
4729

48-
function logResponse(details) {
49-
if ( details.url == url_backend || details.tabId < 0 ) return // avoid feedback loop and other ugliness
50-
//console.log(details)
51-
var headers = details.responseHeaders
30+
async function logResponse(details) {
31+
// Get settings from storage every time, as the service worker can be terminated.
32+
const items = await chrome.storage.local.get({
33+
rest_port: default_rest_port,
34+
scrub_parameters: default_scrub_parameters
35+
});
36+
37+
const url_backend = `http://127.0.0.1:${items.rest_port}/add_record`;
5238

53-
var data = {
39+
// Avoid feedback loop and internal browser requests
40+
if ( details.url.startsWith(url_backend) || details.tabId < 0 ) return;
41+
42+
const headers = details.responseHeaders;
43+
let data = {
5444
url: details.url,
5545
ts: details.timeStamp,
5646
ip: details.ip,
5747
method: details.method,
5848
status: details.statusCode,
5949
type: details.type
60-
}
50+
};
6151

62-
for ( var i = 0, l = headers.length; i < l; ++i ) {
63-
header = headers[i].name.toLowerCase()
64-
if ( header == 'content-length' ) {
65-
data.bytes = headers[i].value
66-
} else if ( header == 'content-type' ) {
67-
data.content_type = headers[i].value
52+
for (const header of headers) {
53+
const headerName = header.name.toLowerCase();
54+
if (headerName === 'content-length') {
55+
data.bytes = header.value;
56+
} else if (headerName === 'content-type') {
57+
data.content_type = header.value;
6858
}
6959
}
7060

71-
chrome.tabs.get(details.tabId, function(tab) {
72-
if ( ! chrome.runtime.lastError ) // sometimes the tab does not exist
73-
data.referer = tab.url
61+
// Since chrome.tabs.get uses a callback, we wrap the final part of our logic in a new Promise
62+
// to keep the async/await flow clean.
63+
const finalizeAndSend = new Promise(resolve => {
64+
chrome.tabs.get(details.tabId, (tab) => {
65+
// Check lastError because the tab might have closed before this callback runs
66+
if (!chrome.runtime.lastError && tab) {
67+
data.referer = tab.url;
68+
}
7469

75-
if ( scrub_parameters ) {
76-
data.url = data.url.replace(/\?.*/, scrubber)
77-
if ( data.referer ) {
78-
data.referer = data.referer.replace(/\?.*/, scrubber)
79-
}
80-
}
70+
if (items.scrub_parameters) {
71+
data.url = data.url.replace(/\?.*/, scrubber);
72+
if (data.referer) {
73+
data.referer = data.referer.replace(/\?.*/, scrubber);
74+
}
75+
}
76+
resolve(data);
77+
});
78+
});
8179

82-
sendLog(JSON.stringify(Object.assign(data)))
83-
})
80+
const finalData = await finalizeAndSend;
81+
82+
try {
83+
await fetch(url_backend, {
84+
method: 'POST',
85+
headers: {
86+
'Content-Type': 'application/json'
87+
},
88+
body: JSON.stringify(finalData) + "\r\n"
89+
});
90+
} catch (error) {
91+
console.error("HTTP Graph Error: Could not send data to backend.", error);
92+
}
8493
}
8594

8695
chrome.webRequest.onCompleted.addListener(
8796
logResponse,
8897
{ urls: [ "http://*/*", "https://*/*" ] },
8998
[ "responseHeaders" ]
90-
)
99+
);
91100

92-
chrome.runtime.onInstalled.addListener(function() {
101+
chrome.runtime.onInstalled.addListener(() => {
93102
chrome.storage.local.set({
94103
rest_port: default_rest_port,
95104
scrub_parameters: default_scrub_parameters
96-
})
97-
})
105+
});
106+
});

dist/manifest.json

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,40 @@
11
{
2-
"manifest_version" : 2,
3-
"name" : "HTTP Graph Collector",
4-
"version" : "0.3",
5-
"description" : "Accompanies the HTTP Graph plugin for Gephi. Collects minimal HTTP and HTTPS header data and POSTs to a REST API as you browse.",
6-
"permissions" : [
7-
"http://*/*",
8-
"https://*/*",
9-
"webRequest",
10-
"storage"
11-
],
12-
"background" : {
13-
"persistent" : true,
14-
"scripts" : [
15-
"httpgraph.js"
16-
]
17-
},
18-
"icons": {
19-
"48": "httpgraph-48x48.png",
20-
"128": "httpgraph-128x128.png"
21-
},
22-
"options_ui": {
23-
"page": "options/options.html",
24-
"open_in_tab": false
25-
}
26-
}
2+
"manifest_version": 3,
3+
"name": "HTTP Graph Collector",
4+
"version": "0.4",
5+
"description": "Accompanies the HTTP Graph plugin for Gephi. Collects minimal HTTP and HTTPS header data and POSTs to a REST API as you browse.",
6+
"background":
7+
{
8+
"service_worker": "httpgraph.js"
9+
},
10+
"permissions":
11+
[
12+
"storage",
13+
"webRequest",
14+
"tabs"
15+
],
16+
"host_permissions":
17+
[
18+
"http://*/*",
19+
"https://*/*",
20+
"http://127.0.0.1/*"
21+
],
22+
"action":
23+
{
24+
"default_title": "HTTP Graph Collector",
25+
"default_icon":
26+
{
27+
"48": "httpgraph-48x48.png"
28+
}
29+
},
30+
"icons":
31+
{
32+
"48": "httpgraph-48x48.png",
33+
"128": "httpgraph-128x128.png"
34+
},
35+
"options_ui":
36+
{
37+
"page": "options/options.html",
38+
"open_in_tab": false
39+
}
40+
}

0 commit comments

Comments
 (0)