reCAPTCHA WAF Session Token

How to Create a Chrome Extension in 10 Minutes Flat — SitePoint


Have you ever considered building your own Chrome extension but thought the process might be too complex? Well, you’re in for a surprise! In the next few minutes, we’ll not only lay out the basics of what a Chrome extension is, but also guide you through five straightforward steps to craft your own.

Curious to see how? Let’s dive in!

Table of Contents
  1. What Are We Going To Build?
  2. What Is a Google Chrome Extension?
  3. Step 1: Create the Extension Files
  4. Step 2: Create the Manifest File
  5. Step 3: Create the Content Script
  6. Step 4: Adding Some Styling
  7. Step 5: Test the Extension
  8. Taking it Further
  9. Conclusion

What Are We Going To Build?

In recent times, we’ve witnessed an explosion in AI capabilities. And while our new cyber companions offer unprecedented levels of assistance, they also come with a reminder: don’t share sensitive information with them.

I don’t know about you, but more often than not, my fingers are faster than my brain. So, to prevent potential slip-ups, we’re going to build a “molly-guard” for ChatGPT.

If you’re scratching your head wondering what a molly-guard is, it originally referred to a shield put over a button or switch to prevent accidental activation. In our context, it’s a digital guardian ensuring we don’t overshare.

Users can specify a list of words or phrases they deem sensitive. Should we attempt to submit a message to ChatGPT containing any of those words, the extension will jump into action, disabling the submit button and saving us from a potential oversight.

To follow along with this tutorial, you’ll need a ChatGPT account. Don’t have one? You can sign up for free here.

The code for this tutorial is available on GitHub.

What Is a Google Chrome Extension?

Before we get started, let’s clarify what a Chrome extension is. A Chrome extension is a small piece of software designed to enhance or modify the Chrome browsing experience. Extensions are developed using standard web technologies — HTML, JavaScript, and CSS — and they can range from simple tools, like color pickers, to more intricate ones, like password managers. Many of these extensions are available for download on the Chrome Web Store.

Note: for those keen on a deeper understanding of Chrome extensions, Google’s official documentation is an invaluable resource.

It’s worth noting that Google Chrome extensions can take various forms based on their intended function. Some have a browser action, visibly represented by an icon next to the address bar, providing quick access to their features. Others might run silently in the background, across all web pages or only on specific ones, depending on their design.

For our tutorial, we’ll focus on an extension type that uses a content script. This script will allow us to interact and manipulate the DOM of a specific page – in our case, the ChatGPT interface.

Step 1: Create the Extension Files

To kick things off, we need to set up the basic structure for our Chrome extension. Our extension, named chatgpt-mollyguard, will be organized in a dedicated folder. This extension directory will contain all the necessary files to make our molly-guard function smoothly.

Here’s a breakdown:

  • Folder: chatgpt-molly-guard. This is the root directory of our extension. All our files will reside in this folder.
  • File: manifest.json. The heart and soul of our extension. This file contains metadata about the extension, such as its name, version, and permissions it requires. Most importantly, it specifies which scripts to run and on which websites.
  • File: contentScript.js. As its name suggests, this JavaScript file contains the content script. This script has direct access to the web page’s content, allowing us to scan for sensitive words and modify the page as needed.
  • File: wordsList.js. A JavaScript file dedicated to containing the list of sensitive words or phrases the user specifies. We’ve separated this to make it easy for users to customize their list without diving into the core functionality in contentScript.js.
  • File: styles.css. A stylesheet to add some flair to our extension. While our primary goal is functionality, there’s no harm in making our warnings or prompts look good!

To get started:

  1. Create a new folder on your computer named chatgpt-molly-guard.
  2. Inside this folder, create the four files listed above.
  3. With the files in place, we’re ready to start filling in the details.

The files necessary to create our Google Chrome extension: manifest.json, contentScript.js, wordList.js & styles.css

In the next sections, we’ll dive deeper into each file and outline its specific role in the extension.

Step 2: Create the Manifest File

The manifest file is a JSON file that provides the browser with essential details about your extension. This file must be located in the extension’s root directory.

Here’s our manifest structure. Copy this code into manifest.json:

<code class="javascript language-javascript"><span class="token punctuation">{</span>
  <span class="token string">"manifest_version"</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span>
  <span class="token string">"name"</span><span class="token operator">:</span> <span class="token string">" <a href="https://yourselfhood.com/go/bN"  class="lar_link lar_link_outgoing" data-linkid="2202" data-postid="3943"  title="ChatGPT"   target="_blank" >ChatGPT</a> Molly-guard"</span><span class="token punctuation">,</span>
  <span class="token string">"version"</span><span class="token operator">:</span> <span class="token string">"1.0"</span><span class="token punctuation">,</span>
  <span class="token string">"description"</span><span class="token operator">:</span> <span class="token string">"Prevents submission if specific words are typed into chat window"</span><span class="token punctuation">,</span>
  <span class="token string">"content_scripts"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      <span class="token string">"matches"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"https://chat.openai.com/*"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token string">"css"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"styles.css"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token string">"js"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"wordsList.js"</span><span class="token punctuation">,</span> <span class="token string">"contentScript.js"</span><span class="token punctuation">]</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">]</span>
<span class="token punctuation">}</span>
</code>

The manifest file has three mandatory fields, namely: manifest_version, name and version. Everything else is optional.

Key Manifest Elements

  • manifest_version: an integer specifying the version of the manifest file format. We’re using Manifest V3, the latest version available. Be aware that Google is actively phasing out Manifest V2 extensions in 2023.
  • name: a short, plain text string (max 45 characters) that identifies the extension.
  • version: one to four dot-separated integers identifying the version of the extension.
  • description: a plain text string (no HTML, max 132 characters) that describes the extension.
  • content_scripts: this key specifies statically loaded JavaScript or CSS files to be used every time a page is opened that matches a URL pattern (specified by the matches key). Here, we’re saying that our script should run on any URL starting with https://chat.openai.com/.

Of the above fields, Google will use the name, version and description when displaying your extension on Chrome’s extension management page () and in the Chrome Web Store.

Though our manifest is streamlined for our needs, many other fields can add depth and functionality to your extensions. Fields such action, default_locale, icons, and so on, offer customization options, UI control, and internationalization support.

For a comprehensive overview of what’s available in the manifest.json file, please consult Google’s official documentation.

Step 3: Create the Content Script

Content scripts in a Chrome extension are JavaScript files that run in the context of web pages. They can view and manipulate the DOM of the page they’re running on, enabling them to modify both the web page’s content and behavior.

This is our content script. Copy the following code into the contentScript.js file:

<code class="javascript language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">debounce</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">callback<span class="token punctuation">,</span> wait</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> timeoutId <span class="token operator">=</span> <span class="token keyword null nil">null</span><span class="token punctuation">;</span>
  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token spread operator">...</span>args</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span>
    <span class="token dom variable">window</span><span class="token punctuation">.</span><span class="token method function property-access">clearTimeout</span><span class="token punctuation">(</span>timeoutId<span class="token punctuation">)</span><span class="token punctuation">;</span>
    timeoutId <span class="token operator">=</span> <span class="token dom variable">window</span><span class="token punctuation">.</span><span class="token method function property-access">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span>
      callback<span class="token punctuation">.</span><span class="token method function property-access">apply</span><span class="token punctuation">(</span><span class="token keyword null nil">null</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span> wait<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">containsForbiddenWords</span><span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">return</span> forbiddenWords<span class="token punctuation">.</span><span class="token method function property-access">some</span><span class="token punctuation">(</span><span class="token parameter">word</span> <span class="token arrow operator">=></span> value<span class="token punctuation">.</span><span class="token method function property-access">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">includes</span><span class="token punctuation">(</span>word<span class="token punctuation">.</span><span class="token method function property-access">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">updateUI</span><span class="token punctuation">(</span><span class="token parameter">target</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> containsForbiddenWord <span class="token operator">=</span> <span class="token function">containsForbiddenWords</span><span class="token punctuation">(</span>target<span class="token punctuation">.</span><span class="token property-access">value</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> sendButton <span class="token operator">=</span> target<span class="token punctuation">.</span><span class="token property-access">nextElementSibling</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> parentDiv <span class="token operator">=</span> target<span class="token punctuation">.</span><span class="token property-access">parentElement</span><span class="token punctuation">;</span>

  <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>containsForbiddenWord<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    sendButton<span class="token punctuation">.</span><span class="token property-access">disabled</span> <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    parentDiv<span class="token punctuation">.</span><span class="token property-access">classList</span><span class="token punctuation">.</span><span class="token method function property-access">add</span><span class="token punctuation">(</span><span class="token string">'forbidden-div'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword control-flow">else</span> <span class="token punctuation">{</span>
    sendButton<span class="token punctuation">.</span><span class="token property-access">disabled</span> <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
    parentDiv<span class="token punctuation">.</span><span class="token property-access">classList</span><span class="token punctuation">.</span><span class="token method function property-access">remove</span><span class="token punctuation">(</span><span class="token string">'forbidden-div'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">body</span><span class="token punctuation">.</span><span class="token method function property-access">addEventListener</span><span class="token punctuation">(</span><span class="token string">'keyup'</span><span class="token punctuation">,</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span><span class="token property-access">target</span><span class="token punctuation">.</span><span class="token property-access">id</span> <span class="token operator">===</span> <span class="token string">'prompt-textarea'</span><span class="token punctuation">)</span> <span class="token function">updateUI</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span><span class="token property-access">target</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">300</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token method function property-access">addEventListener</span><span class="token punctuation">(</span><span class="token string">'keydown'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token property-access">target</span><span class="token punctuation">.</span><span class="token property-access">id</span> <span class="token operator">===</span> <span class="token string">'prompt-textarea'</span> <span class="token operator">&&</span> e<span class="token punctuation">.</span><span class="token property-access">key</span> <span class="token operator">===</span> <span class="token string">'Enter'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token function">containsForbiddenWords</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token property-access">target</span><span class="token punctuation">.</span><span class="token property-access">value</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      e<span class="token punctuation">.</span><span class="token method function property-access">stopPropagation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      e<span class="token punctuation">.</span><span class="token method function property-access">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code>

Let’s break this down, step by step.

At the top of the file we declare a debounce function. We’ll use this to ensure that we don’t check for forbidden words every time the user presses a key. That would be a lot of checks! Instead, we’ll wait until the user stop typing before doing anything. I’ve taken this snippet from Josh W. Comeau’s site, so you can check out his post for an explanation of how it works.

Next comes a containsForbiddenWords function. As the name implies, this function returns true if the text passed to it contains any of our forbidden words. We’re lower-casing both values to ensure that the comparison is case-insensitive.

The updateUI function determines if any forbidden words are present in the chat box. If they are, it disables the send button and adds a CSS class (forbidden-div) to the chat box’s parent div. We’ll leverage this in the next step to provide a visual cue to the user.

The script finally registers two event listeners:

  • The first is set to trigger on a keyup event. It checks if the modified element is our target (the chat window) and then calls the updateUI function. Thanks to our debounce function, this won’t run continuously, but only after a brief pause in typing.
  • The second event listener is listening for a keydown event on our target. Specifically, it’s watching for the Enter keypress, which, if pressed while a forbidden word is in the text area, will prevent the the browser’s default action (in this case a form submission).

This effectively stops messages with forbidden words from being sent, both by disabling the send button and by intercepting and halting the Enter keypress.

You’ll also note that we’re using event delegation, as the ChatGPT interface is an SPA. In SPAs, segments of the user interface are dynamically replaced based on user interactions, which can inadvertently detach any event listeners bound to these elements. By anchoring our event listeners to the broader DOM and selectively targeting specific elements, we can circumvent this issue.

Step 4: Adding Some Styling

While the core functionality of our extension is to prevent certain submissions, it’s important for users to instantly recognize why their action is being blocked. Let’s add some styling to provide a visual cue and enhance the user experience.

Here’s the rule we’re using. Add it to the styles.css file:

<code class="css language-css"><span class="token selector"><span class="token class">.forbidden-div</span></span> <span class="token punctuation">{</span>
  <span class="token property">border</span><span class="token punctuation">:</span> <span class="token number">2</span><span class="token unit">px</span> solid <span class="token color">red</span> <span class="token important">!important</span><span class="token punctuation">;</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token hexcode color">#ffe6e6</span> <span class="token important">!important</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code>

This adds a prominent red border and a subtle red background to the input area whenever forbidden words are detected. It immediately draws attention and indicates that something isn’t right. By toggling a class on a parent div, we can easily turn this on and off.

The !important flag is also worth noting. When dealing with web pages that you don’t own — like in this case with ChatGPT — the existing styles can be very specific. To ensure our styles take precedence and are applied correctly, the !important flag overrides any potential conflicts due to existing styles’ specificity.

Step 5: Test the Extension

There’s one last step: populating the list of forbidden words that our extension should monitor for. We can add these in forbiddenWords.js:

<code class="javascript language-javascript"><span class="token keyword">const</span> forbiddenWords <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token string">"my-company.com"</span><span class="token punctuation">,</span>
  <span class="token string">"SitePoint"</span><span class="token punctuation">,</span>
  <span class="token string">"Jim"</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
</code>

Now that our custom Google Chrome extension is all set up, it’s time to test its functionality and ensure everything is working as intended.

  1. Open Chrome and navigate to in the address bar.
  2. Turn on the Developer mode toggle, located at the top right corner.
  3. Click on the Load unpacked button, which will now be visible.
  4. Navigate to and select the directory of your extension (chatgpt-molly-guard in our case) and click Select. Our extension should now appear in the list of installed extensions.

Custom extension is loaded into the Google Chrome browser

Now, to test out the functionality, navigate to ChatGPT, refresh the page and try typing in your restricted words to see if the extension behaves as expected.

If all has gone according to plan, you should see something like the picture below.

The extension working having identified a forbidden word

If you make any changes to your extension code — such as updating the word list — be sure to hit the circular arrow in the bottom right-hand corner on the extension’s card on the extension page. This will reload the extension. You’ll then need to reload the page that your extension is targeting.

Click the circle to reload the Chrome extension

Taking it Further

Our current basic Chrome extension serves its purpose, but there’s always room for improvement. If you’re eager to refine the extension further and expand its capabilities, there are some suggestions below.

1. User Interface for Word List Editing

Currently, our extension relies on a predefined list of restricted words. Implementing a user-friendly interface would allow users to dynamically add, remove, or modify words on the go. This can be done using a popup UI (browser action) that opens when the extension icon is clicked, where users can manage their list. You’ll also need to persist the words to storage.

2. Handling Mouse Paste Events

While our extension detects keypresses, users can bypass this by pasting sensitive information using the mouse’s right-click menu. To plug this loophole, we could add an event listener for the paste event (or consolidate both to listen for input). This will ensure that, whether information is typed or pasted, the filter remains robust.

3. Contextual Override

Blocking certain terms can be a bit too generic. For example, I might want to block mentions of “Jim” (my name) but have no issues referencing “Jim Carey”. To address this, consider introducing a feature which would disable the molly-guard until the next submit event occurs.

You can also check out the Firefox version of this extension, where this functionality has been implemented.

Conclusion

As we’ve discovered, building your own Google Chrome extension isn’t an insurmountable challenge. We started with a clear objective: to create a protective layer for ChatGPT, ensuring that sensitive information remains confidential. Throughout this tutorial, we’ve seen how a handful of files and a bit of code can result in a functional and useful browser extension.

For those eager to dive deeper, Google’s official Chrome Extension documentation is an excellent starting place. Additionally, the Chrome Extension migration guide offers insights on the transition to Manifest V3, which is crucial given the impending phase-out of Manifest V2 in 2023.

Now that you’ve seen how it’s done, I encourage you to refine, enhance, and adapt the extension to suit your needs. You’re welcome to hit me up on Twitter and let me know about any improvements you’ve made.





Source link

Leave a Reply

Your email address will not be published. Required fields are marked *

WP Twitter Auto Publish Powered By : XYZScripts.com