Fix notrack

This commit is contained in:
kmmiio99o 2025-10-10 23:54:06 +02:00
parent 8d716c970c
commit a4eb98bd8f
6 changed files with 223 additions and 119 deletions

View file

@ -1,36 +1,230 @@
import network from "./lib/network";
import console from "./lib/console";
import miscellanous from "./lib/miscellanous";
import sentry from "./lib/sentry";
import { defineCorePlugin } from "..";
import { findByProps } from "@metro";
import { instead } from "@lib/api/patcher";
import { logger } from "@lib/utils/logger";
const patches = [
network(),
console(),
miscellanous(),
// Sentry causes issues
// sentry(),
];
// Type for functions that need to be cleaned up when plugin is disabled
type PatchCleanupFn = () => void;
// Store all active patches for cleanup
let patches: PatchCleanupFn[] = [];
// AnalyticsUtils and other tracking utilities
const AnalyticsUtils = findByProps("AnalyticsActionHandlers");
const SuperPropUtils = findByProps("encodeProperties", "track");
const VoiceStateUtils = findByProps("getVoiceStateMetadata");
const CrashReportUtils = findByProps("submitLiveCrashReport");
const MetricsUtils = findByProps("_metrics");
// Sentry interface definition to avoid TypeScript errors
interface SentryClient {
getOptions: () => { enabled: boolean };
close: () => void;
open: () => void;
}
interface SentryScope {
clear: () => void;
}
interface SentryHub {
getClient: () => SentryClient | undefined;
getStackTop: () => { scope: SentryScope };
getScope: () => SentryScope;
addBreadcrumb?: (breadcrumb: unknown) => void;
}
interface GlobalSentry {
hub?: SentryHub;
}
// Get Sentry objects with proper type checking
const sentryGlobal = (globalThis as unknown as { __SENTRY__?: GlobalSentry })
.__SENTRY__;
const sentryHub = sentryGlobal?.hub;
const sentryClient = sentryHub?.getClient();
// Sentry related objects with type safety
const Sentry = {
initializer: findByProps("initSentry"),
main: sentryHub,
client: sentryClient,
};
// Utility function to create no-operation patches
const noop = (prop: string, parent: Record<string, any>): PatchCleanupFn => {
try {
return instead(prop, parent, () => undefined);
} catch (e) {
return () => false;
}
};
// Network tracking prevention
function patchNetwork(): PatchCleanupFn {
// Analytics and tracking endpoints to block
const analyticsTest =
/client-analytics\.braintreegateway\.com|discord\.com\/api\/v9\/(science|track)|app\.adjust\..*|.*\.ingest\.sentry\.io/;
try {
const unpatch = instead(
"send",
XMLHttpRequest.prototype,
function (
this: XMLHttpRequest & { __sentry_xhr__?: { url: string } },
args: unknown[],
orig: Function,
) {
if (
this.__sentry_xhr__?.url &&
analyticsTest.test(this.__sentry_xhr__.url)
) {
return undefined;
}
return orig.apply(this, args);
},
);
return unpatch;
} catch (e) {
return () => false;
}
}
// Console patching to remove Sentry wrappers
function patchConsole(): PatchCleanupFn {
type ConsoleFunction = Function & { __sentry_original__?: Function };
type ConsoleFunctions = Record<string, ConsoleFunction>;
const sentrified: ConsoleFunctions = {};
try {
// We need to use Object.keys because TypeScript doesn't allow indexing Console with strings
(Object.keys(console) as Array<keyof Console>).forEach((key) => {
const consoleFunc = (console as unknown as ConsoleFunctions)[key];
if (consoleFunc) {
sentrified[key] = consoleFunc;
const originalFunc = consoleFunc.__sentry_original__;
(console as unknown as ConsoleFunctions)[key] =
originalFunc ?? consoleFunc;
}
});
} catch (e) {
logger.log("Failed to de-sentrify console functions!", e);
}
return () => {
Object.keys(sentrified).forEach((key) => {
if (sentrified[key]) {
(console as unknown as ConsoleFunctions)[key] = sentrified[key];
}
});
};
}
// Miscellaneous tracking functions
function patchMiscellaneous(): PatchCleanupFn {
const miscPatches = [
// Global analytics utilities
AnalyticsUtils?.AnalyticsActionHandlers &&
noop("handleTrack", AnalyticsUtils.AnalyticsActionHandlers),
AnalyticsUtils?.AnalyticsActionHandlers &&
noop("handleFingerprint", AnalyticsUtils.AnalyticsActionHandlers),
// Super properties tracking
SuperPropUtils && noop("track", SuperPropUtils),
// Voice state metadata tracking
VoiceStateUtils && noop("trackWithMetadata", VoiceStateUtils),
// Crash reporter
CrashReportUtils && noop("submitLiveCrashReport", CrashReportUtils),
// Metrics
MetricsUtils?._metrics && noop("push", MetricsUtils._metrics),
].filter(Boolean) as PatchCleanupFn[];
return () => miscPatches.forEach((p) => p());
}
// Sentry error reporting prevention
function patchSentry(): PatchCleanupFn {
const sentryPatches: PatchCleanupFn[] = [];
// Add patches if Sentry components exist
if (Sentry.initializer) {
sentryPatches.push(noop("initSentry", Sentry.initializer));
}
if (Sentry.main && Sentry.main.addBreadcrumb) {
sentryPatches.push(noop("addBreadcrumb", Sentry.main));
}
// Disable Sentry client
if (Sentry.client) {
try {
Sentry.client.getOptions().enabled = false;
Sentry.client.close();
if (Sentry.main) {
if (Sentry.main.getStackTop) {
Sentry.main.getStackTop().scope.clear();
}
if (Sentry.main.getScope) {
Sentry.main.getScope().clear();
}
}
} catch (e) {
// Silent fail
}
}
return () => {
try {
sentryPatches.forEach((p) => p());
// Re-enable Sentry client on cleanup
if (Sentry.client) {
Sentry.client.getOptions().enabled = true;
Sentry.client.open();
}
} catch (e) {
// Silent fail
}
};
}
export default defineCorePlugin({
manifest: {
id: "vendetta.notrack",
version: "1.0.0",
type: "plugin",
spec: 3,
main: "",
display: {
name: "NoTrack",
description: "Disables Discord's telemetry",
authors: [{ name: "maisymoe" }]
}
manifest: {
id: "bunny.notrack",
version: "1.0.0",
type: "plugin",
spec: 3,
main: "",
display: {
name: "NoTrack",
description: "Disables Discord's telemetry",
authors: [{ name: "maisymoe" }],
},
start() {
network(),
console(),
miscellanous(),
sentry()
}
});
},
start() {
// Apply all patches
patches = [
patchNetwork(),
patchConsole(),
patchMiscellaneous(),
patchSentry(),
].filter(Boolean);
logger.log("NoTrack: Enabled - all telemetry tracking disabled");
},
stop() {
// Call all cleanup functions
patches.forEach((p) => p?.());
patches = [];
logger.log("NoTrack: Disabled - telemetry tracking restored");
},
});

View file

@ -1,16 +0,0 @@
import { logger } from "@lib/utils/logger";
export default () => {
const sentrified = {};
try {
Object.keys(console).forEach((x) => {
sentrified[x] = console[x];
console[x] = console[x].__sentry_original__ ?? console[x];
});
} catch(e) {
logger.log("Failed to de-sentrify console functions!", e);
};
return () => Object.keys(console).forEach((x) => console[x] = sentrified[x]);
}

View file

@ -1,33 +0,0 @@
import { findByProps } from "@metro";
import { noop } from "./utils";
// Stuff in here is non-specific tracking scattered around the app
const AnalyticsUtils = findByProps("AnalyticsActionHandlers");
const SuperPropUtils = findByProps("encodeProperties", "track");
const VoiceStateUtils = findByProps("getVoiceStateMetadata");
const CrashReportUtils = findByProps("submitLiveCrashReport");
const MetricsUtils = findByProps("_metrics");
export default () => {
const patches = [
// Global analytics utilities
...(["handleTrack", "handleFingerprint"].map((i) => noop(i, AnalyticsUtils.AnalyticsActionHandlers))),
// TODO: This is a getter - look into patching it
// noop("analyticsTrackingStoreMaker", AnalyticsUtils),
// Super properties tracking
noop("track", SuperPropUtils),
// Voice state metadata tracking
noop("trackWithMetadata", VoiceStateUtils),
// Crash reporter
noop("submitLiveCrashReport", CrashReportUtils),
// Whatever "metrics" implies
noop("push", MetricsUtils._metrics),
];
return () => patches.forEach((p) => p());
}

View file

@ -1,12 +0,0 @@
import { instead } from "@lib/api/patcher";
export default () => {
// https://github.com/yellowsink/shelter-plugins/blob/3a62d1557b704f4617f72882edba826218eb8c6e/plugins/antitrack/index.js#L10-L25
const analyticsTest = /client-analytics\.braintreegateway\.com|discord\.com\/api\/v9\/(science|track)|app\.adjust\..*|.*\.ingest\.sentry\.io/;
return instead(
"send",
XMLHttpRequest.prototype,
function (args, orig) { if (!analyticsTest.test(this.__sentry_xhr__?.url)) return orig.apply(this, args) },
);
}

View file

@ -1,26 +0,0 @@
import { findByProps } from "@metro";
import { noop } from "./utils";
const Sentry = {
initializer: findByProps("initSentry"),
main: globalThis.__SENTRY__?.hub,
client: globalThis.__SENTRY__?.hub?.getClient(),
};
export default () => {
const patches = [
noop("initSentry", Sentry.initializer),
noop("addBreadcrumb", Sentry.main),
];
Sentry.client.getOptions().enabled = false;
Sentry.client.close();
Sentry.main.getStackTop().scope.clear();
Sentry.main.getScope().clear();
return () => {
patches.forEach((p) => p());
Sentry.client.getOptions().enabled = true;
Sentry.client.open();
};
}

View file

@ -1,3 +0,0 @@
import { instead } from "@lib/api/patcher";
export const noop = (prop: string, parent: any) => instead(prop, parent, () => {});