This guide assumes you’re creating a wallet using a web browser extension, but the same principles apply to integrate our APIs for Mobile or Desktop wallets.

Let us know if you’d like to see a guide for a specific use-case that’s not covered here.

Overview

The goal of integrating ChainPatrol’s API into your wallet is to prevent users from interacting with a malicious website that is intended to steal their funds or credentials.

To achieve this goal, you will need to do the following:

  • 🔍 Detect when a user has visited a new website
  • 🥷 Check if the website is malicious with the ChainPatrol API
  • ⚠️ Display a warning to the user if the website is malicious
  • 🤞 Allow the user to continue if they wish
  • 😅 Allow the user to report a false positive

Let’s dive deeper into each of these steps:

Detecting navigation to a new website

In the code examples below, we’re using Mozilla’s webextension-polyfill to smooth out the differences between the Chrome and Firefox APIs.

The first step is to detect when a user has visited a new website. If you’re building a web browser extension, you have a couple of choices:

This approach requires adding the webNavigation permission to your manifest.json file:

{
  "permissions": ["webNavigation"]
}

If your extension does not already have this permission, this will trigger a new permissions request when the user installs/updates your extension to “Read your browsing history”.

Alternatively, you can make this permission optional and request it at runtime to avoid disabling your extension for users who don’t want to grant this permission. Read more about optional permissions here.

Then you can listen for the onBeforeNavigate event in your Background script:

import browser from 'webextension-polyfill';

browser.webNavigation.onBeforeNavigate.addListener(async function (details) {
  // Filter out subframes and any navigation events that don't have a URL
  if (details.frameId !== 0 || !details.url) {
    return;
  }

  // ...
});

Option 2: Use the browser.tabs.onUpdated API

This approach requires adding the tabs permission to your manifest.json:

{
  "permissions": ["tabs"]
}

If your extension does not already have this permission, this will trigger a new permissions request when the user installs/updates your extension to “Read your browsing history”.

Alternatively, you can make this permission optional and request it at runtime to avoid disabling your extension for users who don’t want to grant this permission. Read more about optional permissions here.

Then you can listen for the onUpdated event in your Background script:

import browser from 'webextension-polyfill';

browser.tabs.onUpdated.addListener(async function (tabId, changeInfo, tab) {
  // Filter out any tab change events that aren't complete, aren't for the
  // active tab, or tabs that don't have a URL
  if (changeInfo.status !== 'complete' || !tab.active || !tab.url) {
    return;
  }

  // ...
});

Option 3: Get the current URL from a content script

This option assumes you already have a content script that runs on every page, ie. you have something like this in your manifest.json:

{
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"]
    }
  ]
}

If your extension does not already have this permission, this will trigger a new permissions request when the user installs your extension to “Read and change all your data on all websites”.

This is a very broad permission, and the warning message may scare some users away if you don’t already have this permission. For this reason, we recommend using one of the other options above if possible. But if you need to use this option, you can make this permission optional and inject the content script at runtime. Read more about this approach here.

If you’re already using a content script in your extension, you can get the current URL from the window.location object without needing to add any additional permissions.

const url = window.location.href;

You can read this value at any time, but we recommend reading it either when the page first loads, or when the user attempts to initiate a transaction in your wallet app.

You’ll need to send this URL to your background script so that it can check if the website is malicious. This can be done using message passing:

// content.js
const url = window.location.href;

// send the URL to the background script
browser.runtime.sendMessage({ type: 'CHAINPATROL_CHECK_URL', url });
// background.js

// listen for the message from the content script
browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.type === 'CHAINPATROL_CHECK_URL') {
    // do something with request.url
  }
});

Checking if the website is malicious

Once we know the user has visited a new website, we can check if the website is malicious with the ChainPatrol API.

// check if a URL is blocked
export const checkUrl = async (url: string) => {
  const response = await fetch(
    'https://app.chainpatrol.io/api/v2/asset/check',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-API-KEY': 'YOUR API KEY',
      },
      body: JSON.stringify({ type: 'URL', content: url }),
    }
  );

  const data = await response.json();

  return data.status === 'BLOCKED';
};

Displaying a warning to the user

If the website is malicious, you should display a warning to the user.

Our recommended approach is to redirect the user to a warning page which will let the user know that they are about to visit a malicious website, and give them the option to safely exit, continue, or report a false positive if they believe the website is not malicious.

There are two options for creating the warning page:

If you need help deciding which option is best for you, please feel free to reach out to us.

Conclusion

We’ve now added a layer of security to your wallet by protecting users from scams and phishing.

Next Steps