Security News
Supply Chain Attack Detected in Solana's web3.js Library
A supply chain attack has been detected in versions 1.95.6 and 1.95.7 of the popular @solana/web3.js library.
@dataunlocker/defender-react
Advanced tools
DataUnlocker Defender protects your web app against network and JavaScript intrusions 🦾
💊 DataUnlocker is like a magic pill that makes all front end data collection and tracking tools work even when browsing with ad blockers, network filters, VPN etc.
In turn, DataUnlocker Defender is a controller script tightly coupled with your web application's source code, making it impossible to cut it out of the JavaScript web app.
This package is a React wrapper over a plain core module. Check other packages for your specific tooling:
⚠️ We highly recommend you to follow guided onboarding on admin.dataunlocker.com instead of trying to install this package manually.
DataUnlocker Defender is designed to be installed directly to your client-side JavaScript web app,
like you would install any typical NPM package. However, you will need to provide DATAUNLOCKER_ID
environment variable before installing this package.
export DATAUNLOCKER_ID=000000000000000000000000
npm install @dataunlocker/defender-react
You can also append the DATAUNLOCKER_ID
variable to .npmrc
file, located in the root of your project.
You can create this file if it doesn't exist. Note that environment variables will override ones which are
defined in .npmrc
file.
DATAUNLOCKER_ID=000000000000000000000000
DATAUNLOCKER_ID
DATAUNLOCKER_ENDPOINT
(OPTIONAL)
website.com/eXamPLe
.eXamPLe.website.com
.custom.site.com/optional-path
.You will be guided at DataUnlocker Admin about further installation steps.
DataUnlocker installation is always considered "clean" (working even when ad blockers are on) when you install it for the first time. I.e. the installation is unique to every domain and there's no feasible generic filter against it. However, as the time passes by, DataUnlocker on your web app may or may not get noticed by adblock community, so you have to properly integrate it to avoid DataUnlocker being "voided" over time.
DataUnlocker Defender checks that your DataUnlocker setup works properly within your web app, on every page load. Simply put, it tells you if something is trying to block or bypass DataUnlocker via the corresponding handlers. It is important to program your web app in a way that if this check fails, your web app reacts to it (for example, you can stop interactivity in your web app, stop sending or receiving data, prevent rendering, navigation etc). This is a core paradigm of DataUnlocker self-defense mechanism. No worries: the tracking haters community won't intentionally release a filter to break your web app, as users will start disabling ad blockers and complain on inability to circumvent DataUnlocker.
❗️ If you don’t properly handle the Defender check's “error“ and “load“ in your web app, the blockers will be able to circumvent DataUnlocker and void it over time.
A few more things to note:
document.body.innerHTML = '...'
can be easily defused too (JavaScript rules in uBlock, Brave etc).Defender check will pass for 100% of your users (including those using ad blockers), but it has to be preprogrammed in a specific way to ensure nothing (like ad blocker) can "cut" DataUnlocker from your web app.
DataUnlocker Defender's API for React is very straightforward:
import {
Defender,
DefenderErrorComponent,
Placeholder,
Spinner,
useDefender,
} from '@dataunlocker/defender-react';
import { FC, ReactNode, useEffect } from 'react';
const CustomError: DefenderErrorComponent = ({ error }) => (
<Placeholder error={error} />
);
// Your application's root node.
const Root: FC<{ children: ReactNode }> = ({ children }) => {
return (
// <Defender> handles all states: loading and error. You can also do custom handling by only using `useDefender`.
<Defender
loading={<Spinner />}
errorComponent={CustomError}
onLoad={initTracking}
>
{children}
</Defender>
);
};
const initTracking = () => {
/* Your tracking code. Alternatively, use DataUnloocker's secure enclave. */
};
Mind this:
error
at any time (after or before the load event). error
is set once when DataUnlocker setup is detected as broken or circumvented.isLoading
and error
it will be easy for ad blockers to block DataUnlocker.
isLoading
is false
;error
; optionally, notify the user about the error (included in <Defender/>
).load
/error
should be observable immediately, in a sense that anyone who contributes to adblock filter lists won't be clicking through your entire web app after finding a set of rules that circumvent DataUnlocker.load
was emitted), a page refresh will happen along with an error
event. This is an intended behavior.console.log
.You can use DataUnlocker's secure enclave to house the tracking tools code such as Google Tag Manager (GTM).
layout.tsx
:
import { FC, ReactNode } from 'react';
import { Defender, Spinner } from '@dataunlocker/defender-react';
const Layout: FC<{ children: ReactNode }> = ({ children }) => {
// ✅ Handles all Defender states.
return <Defender loading={<Spinner />}>{children}</Defender>;
};
// ✅ Tracking tools are configured in "DataUnlocker's secure enclave" in DataUnlocker Admin,
// and will be injected by DataUnlocker automatically.
export default Layout;
Alternatively if you prefer
layout.tsx
:
import { FC, ReactNode, useEffect } from 'react';
import { Defender, Spinner, useDefender } from '@dataunlocker/defender-react';
// Your tracking initialization function. Example: GTM.
const initTracking = () => {
const dataLayerVariableName = Date.now().toString(36).slice(-5); // Make DataLayer variable name random to avoid JS blocking
const _window = window as any;
const dataLayer = (_window[dataLayerVariableName] =
_window[dataLayerVariableName] || []);
dataLayer.push(['js', new Date()]);
dataLayer.push(['config', 'G-279DATA']);
const script = document.createElement('script');
script.src = `https://www.googletagmanager.com/gtag/js?id=G-AAAA&l=${dataLayerVariableName}`;
document.body.appendChild(script);
};
const Layout: FC<{ children: ReactNode }> = ({ children }) => {
// ✅ Handles 3 states below. If you need custom handling, implement it with `useDefender` hook only.
// 1. Defender reports an error (abstracted): displays this error to the user. This protects your DataUnlocker installation.
// 2. Defender is not yet loaded (abstracted): makes your application non-interactive by displaying the `loading` component.
// 3. Defender has no errors and is loaded: renders your application.
return (
<Defender loading={<Spinner />} onLoad={initTracking}>
{children}
</Defender>
);
};
export default Layout;
✅ Make sure to minify and tree shake your application's javascript bundle.
layout.tsx
:
import { FC, ReactNode, useEffect } from 'react';
import { Placeholder, useDefender } from '@dataunlocker/defender-react';
const initTracking = () => {
// Your tracking initialization. Example: GTM
const dataLayerVariableName = Date.now().toString(36).slice(-5); // Make DataLayer variable name random to avoid JS blocking
const _window = window as any;
const dataLayer = (_window[dataLayerVariableName] =
_window[dataLayerVariableName] || []);
dataLayer.push(['js', new Date()]);
dataLayer.push(['config', 'G-279DATA']);
const script = document.createElement('script');
script.src = `https://www.googletagmanager.com/gtag/js?id=G-AAAA&l=${dataLayerVariableName}`;
document.body.appendChild(script);
};
const Layout: FC<{ children: ReactNode }> = ({ children }) => {
const [isLoading, defenderError] = useDefender(initTracking);
// ✅ Handle 3 states manually (without using <Defender/> component):
// 1. Defender reports an error: display this error to the user. This protects your DataUnlocker installation.
// 2. Defender is not yet loaded: make your application non-interactive or display the loading state.
// 3. Defender has no errors and is loaded: render your application.
return defenderError ? (
<Placeholder error={defenderError} />
) : isLoading ? (
<div>The app is loading, please wait...</div>
) : (
/* Your app's existing code */
children
);
};
export default Layout;
Handle both isLoading
and error
, which is equally and crucially important.
layout.tsx
:
import { FC, ReactNode, useEffect } from 'react';
import { Defender, useDefender } from '@dataunlocker/defender-react';
const initTracking = () => {
// Your tracking initialization function.
};
const Layout: FC<{ children: ReactNode }> = ({ children }) => {
const [isLoading, defenderError] = useDefender();
useEffect(() => {
if (!isLoading) {
initTracking();
}
}, [isLoading]);
// ❌ Missing loading state handling. Defender may never load nor error.
return defenderError ? (
<Placeholder error={defenderError} />
) : (
/* Your app's existing code */
children
);
};
export default Layout;
Defender retrieves a validation code with cryptographic signature from DataUnlocker's servers per each web app page load,
which helps it ensure that the connection and the setup is genuine. Without getting a signed response from DataUnlocker
servers for whatever reason, Defender will report an interference (onError
).
Consider the following to mitigate risks:
onError
.Facts about Defender:
FAQs
DataUnlocker Defender for React applications.
We found that @dataunlocker/defender-react demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
A supply chain attack has been detected in versions 1.95.6 and 1.95.7 of the popular @solana/web3.js library.
Research
Security News
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
Security News
Research
Socket researchers have discovered malicious npm packages targeting crypto developers, stealing credentials and wallet data using spyware delivered through typosquats of popular cryptographic libraries.