How to Hijack your head (HTML head tag)
Tags: cloud, javascript, cloudflare, foundryvtt
Published: 2021-06-29 06:31:20

## Disclosure

This is aimed as a guide to add scripts or styles to the `<head>` tag of websites that you host and do not have access to the source or do not want to monkey patch source. 

Additional note, you can ride on the free tier of CloudFlares service workers if you do not serve more than 100k requests on your foundry instance `/join` route. 

## Introduction

In this example, we will be creating a service worker on CloudFlare which gives us the option to inject a `<link>` element into the `<head>` element of a websites served HTML. For the example, we will be inject a style sheet into the `<head>` to change the appearance of FoundryVTT. 

The link we will be applying is the style effects from [Foundry VTT Prettier Login Screen by TheEpicSnowWolf](https://github.com/TheEpicSnowWolf/Foundry-VTT-Prettier-Login-Screen).

## Requirements

- CloudFlare domain, or sub-domain, pointing to your FoundryVTT instance.
- A hosted FoundryVTT instance that can be served by your domain or sub-domain. 
- Minimal knowledge of JavaScript. 


## Steps

1). Open CloudFlare and Login.

2). (If you have multiple domains) Use the drop down or the cards to select the domain your foundry instance is hosted on. 

3). Click the Workers tab at the top:

![Click Workers tab](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ut4t2beeo7tjxhvqdksg.png)
 
4). On the Workers page, click Manage Workers

![Manage Workers Button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/741i6o8ankd4b3sdqi1y.png)
 
5). On the Manage Workers page, click Create a Worker

![Create a Worker](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lsuczdx19zlxgeg6j7ke.png)

6). In the script section, lets create an element handler: 

```javascript
class ElementHandler {
  element(element) {
    element.append(`<link
      rel="stylesheet" 
      type="text/css" 
      data-id="foundry-login"
      href="https://cdn.jsdelivr.net/gh/TheEpicSnowWolf/Foundry-VTT-Prettier-Login-Screen@main/foundry_login.css"  
    >`, {html: true});
    console.log("injected");
  }
}
```

This element handler, will consume the `<head>` element on the HTML dom and append a link to the `foundry_login.css` script found in the [Foundry VTT Prettier Login Screen repository by TheEpicSnowWolf](https://github.com/TheEpicSnowWolf/Foundry-VTT-Prettier-Login-Screen).

7). Next lets add a handle request function:

```javascript
async function handleRequest(req) {
  const res = await fetch(req)
  
  if (res.url.includes('example.com/join')) {
    return new HTMLRewriter().on("head", new ElementHandler()).transform(res)
  }  
  
  return res;
}
```

This function is designed to take the request, process the request, and check if the URL itself matches the `/join` route. In the script above, replace the `example.com` with your domain or `sub-domain.domian.tld` (ex `dnd.example.com`)


8). After that, add the event listener to hook into the worker API: 

```javascript
addEventListener("fetch", (event) => {
  event.respondWith(
    handleRequest(event.request).catch(
      (err) => new Response(err.stack, { status: 500 })
    )
  );
});
```

9). Click the Save and Deploy button: 

![Script plus Save and Deploy Button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e7tmeplbgttefhi0jr8v.png)
 
10). With the script saved, click the script name in the upper right hand corner: 

![click script name](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nnlw51kobuacy33m6dj7.png)
 
11). On the workers configuration page, uncheck the box that says Workers.dev route

![workers.dev route](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3smkawm8d2jhm1i5adak.png)

12). Use the drop down menu in the upper right hand corner to select your domain name.

![Click Website domain](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7aqdgtjnlkzsv4tks33f.png)
 
13). Click the Workers tab again

![Click Workers tab](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ut4t2beeo7tjxhvqdksg.png)

14). This time, click the Add Route button.

![Add Route Button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ohv4nmv5s673gue9dysj.png)
 
15). In the Add Route screen, change the Route to be `example.com` or `sub-domain.domian.tld` with a trailing `/join` if you are doing this for foundry. 

16). In the Worker drop down, select the new worker you created: 

17). Click the save button: 

![Save Button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vrr2rq74z8mbbtiwjv7w.png)

18). Finally, visit your website where the service worker is attached :heart:

![Foundry with new CSS](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oaahm6dj58jolsdla5qj.png)
 

## Conclusion

This is incredibly useful for sites where you do not want to monkey with the code and instead inject other scripts. It can be used for Analytics, Authentication, and much more. The possibilities are endless! :smile:


### Source Code

Source code for service worker: [Foundry VTT Service Worker]( https://gist.github.com/mbround18/07cc1d102a29c07d4cba58d8ab30c0f8)

### Shoutouts

Credit to [@TheEpicSnowWolf on GitHub](https://github.com/TheEpicSnowWolf) for putting together the CSS in [the repository Foundry VTT Prettier Login Screen](https://github.com/TheEpicSnowWolf/Foundry-VTT-Prettier-Login-Screen)


Credit to [Derek Johnson on StackOverflow](https://stackoverflow.com/users/1274335/derek-johnson) for the original code snippet in their [StackOverflow question "Inject HTML with Cloudflare worker"](https://stackoverflow.com/questions/68161234/inject-html-with-cloudflare-worker)