Skip to content

Commit

Permalink
docs: added new proxy documentation for activities
Browse files Browse the repository at this point in the history
  • Loading branch information
Pkmmte committed Jun 23, 2024
1 parent d35fa07 commit 83046bb
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 1 deletion.
38 changes: 38 additions & 0 deletions docs/docs/discord-activities/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,44 @@ These docs cover everything you need to know about creating **Discord Activities
description="Add multiplayer functionality to your Discord Activity."
/>
<Card href="../hosting/overview" title="🚀 Hosting" description="Deploy your activity for others to use." />
<Card href="./proxy" title="🛡️ Discord Proxy" description="Things to know about Discord's Proxy." />
</CardContainer>

## Tutorials

Creating **Discord Activities** is easy to learn, but we also have tutorials to help you get started quickly.

<CardContainer>
<Card
href="https://dev.to/waveplay/how-to-build-a-discord-activity-easily-with-robojs-5bng"
title="📚 How to Build a Discord Activity"
description="Create a Discord Activity in seconds."
/>
<Card
href="https://dev.to/waveplay/how-to-add-multiplayer-to-your-discord-activity-lo1"
title="📚 Add Multiplayer to Your Activity"
description="Create a multiplayer Discord Activity."
/>
<Card
href="https://dev.to/waveplay/achieve-game-like-scaling-in-discord-activities-and-web-apps-using-css-874"
title="📚 Achieve Game-like Scaling"
description="Scale your Discord Activity like a game."
/>
<Card
href="https://dev.to/waveplay/how-to-fix-stuck-ready-event-in-discord-embedded-app-sdk-h9e"
title="📚 Fix Stuck DiscordSDK Ready Event"
description="Prevent the .ready() function from getting stuck."
/>
<Card
href="https://dev.to/waveplay/resolve-content-security-policy-csp-issues-in-your-discord-activity-using-a-nodejs-proxy-2634"
title="📚 Resolve CSP Issues with a Proxy"
description="Use a Node.js proxy to resolve CSP issues."
/>
<Card
href="https://dev.to/waveplay"
title="🔗 More Tutorials"
description="Explore more tutorials for Discord Activities."
/>
</CardContainer>

## Plugin Power Ups
Expand Down
132 changes: 132 additions & 0 deletions docs/docs/discord-activities/proxy.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { Card } from '@site/src/components/shared/Card'
import { CardContainer } from '@site/src/components/shared/CardContainer'

# 🛡️ Discord Proxy

Client network requests made by your **Discord Activity** are "sandboxed" through **[Discord's Proxy](https://discord.com/developers/docs/activities/development-guides#activity-proxy-considerations)**.

That means you cannot directly make network requests to **[external URLs](#external-resources)** from it for security reasons. You may have seen this if you've tried using iframes. There are also **[limitations](#network-limitations)** to what network protocols you can use.

## Content Security Policy (CSP)

So you tried to load a URL from an external resource and got a `blocked:csp` error? That's the **Discord Proxy** doing its job.

**[Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)** is a security feature that helps prevent **[cross-site scripting (XSS)](https://owasp.org/www-community/attacks/xss/)** attacks. It restricts what can load, such as scripts, styles, and images. **Discord** trusts only you **[and itself](https://discord.com/developers/docs/activities/development-guides#exceptions)**. It will throw **CSP** errors at everyone else.

It may be a pain, but it's for your own good. You can work with it by using **[URL Mappings](#url-mapping)**, **[patching URLs](https://github.com/discord/embedded-app-sdk/blob/main/patch-url-mappings.md)**, or **[proxying requests](#proxying-requests)**.

## URL Mapping

Mapping URLs is a way to tell the **Discord Proxy** to allow certain external resources. You can map a URL to a specific path in the **[Discord Developer Portal](https://discord.com/developers/applications)**. This is the recommended way to allow external resources you need in your **Discord Activity**.

Let's say you need to load something from **[GitHub](https://github.com)**. You can map it to a path like `/github` and `/assets`.

<center>`/github` -> `https://github.com`</center>
<center>`/assets` -> `https://raw.githubusercontent.com/Wave-Play/robo.js/main`</center>
<p></p>

This configuration maps URLs you can use in your activity like so:

<center>`/github/Wave-Play/robo.js` -> `https://github.com/Wave-Play/robo.js`</center>
<center>`/assets/README.md` -> `https://raw.githubusercontent.com/Wave-Play/robo.js/main/README.md`</center>
<p></p>

And voila, you can now load those URLs in your **Discord Activity** using the mapped paths.

```HTML
<iframe src="/assets/README.md"></iframe>
```

```js
fetch('/assets/docs/static/img/logo.png')
```

You can reference it as a path or a full URL. **[Construct a full URL](https://discord.com/developers/docs/activities/development-guides#construct-a-full-url)** if you need to.

<CardContainer>
<Card
href="https://discord.com/developers/applications"
title="🔗 Discord Developer Portal"
description="Find it under your app's URL Mappings."
/>
</CardContainer>

:::tip Don't actually use GitHub as a CDN

GitHub is not a CDN. Connect **[your host](https://roboplay.dev)** to a CDN like **[Cloudflare](https://www.cloudflare.com)** or **[Bunny.net](https://bunny.net/)** for your assets.

:::

## URL Patching

Mapping is great if you have control over the paths used, _but what if you don't?_ You know, like when using third-party libraries with hardcoded URLs. You can use the **[Embedded App SDK](https://github.com/discord/embedded-app-sdk/)** to for that!

```js
import { patchUrlMappings } from '@discord/embedded-app-sdk'

patchUrlMappings([{ prefix: '/foo', target: 'foo.com' }])
```

Alternatively, you can use a post-install utility like **[patch-package](https://www.npmjs.com/package/patch-package)** or fork the library to use mapped URLs.

## Security Considerations

The **Discord Proxy** hides the user's IP address and blocks URLs from known **[malicious endpoints](https://www.youtube.com/watch?v=dQw4w9WgXcQ)**. This ensures the safety of the user's data and privacy. However, it also means that you need to be careful when handling external resources.

Don't trust info coming from the Discord client as absolute truth. There could be an impostor among us. Call the Discord API directly from your app's **[Web Server](./server)** with the OAuth2 token you received during **[Authentication](./auth)** if you need information that's not sus.

As always with usernames and channel names: _sanitize before using them_. You never know what might try to sneak in.

## Network Limitations

Want to use **[WebRTC](https://webrtc.org/)** or **[WebTransport](https://w3c.github.io/webrtc-quic/)**? Sorry, you can't. **[Not yet](https://discord.com/developers/docs/activities/development-guides#activity-proxy-considerations)**, at least.

The **Discord Proxy** does _not_ support the following for now:

- **[Some iframe ports](https://developers.cloudflare.com/fundamentals/reference/network-ports/#network-ports-compatible-with-cloudflares-proxy)**
- **[URL Mapping external ports](https://developers.cloudflare.com/workers/platform/known-issues/#custom-ports)**
- **[WebRTC](https://webrtc.org/)**
- **[WebTransport](https://w3c.github.io/webrtc-quic/)**

You'll be fine if you stick to **[WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)** or **[HTTPS](https://developer.mozilla.org/en-US/docs/Glossary/HTTPS)**, as well as some protocols built upon them like **[DASH](https://developer.mozilla.org/en-US/docs/Web/Media/Audio_and_video_delivery/Setting_up_adaptive_streaming_media_sources#mpeg-dash_encoding)** or **[HLS](https://developer.mozilla.org/en-US/docs/Web/Guide/Audio_and_video_delivery/Setting_up_adaptive_streaming_media_sources#hls_encoding)** for streaming.

Need to make a request to a specific port? Have your **Web Server** handle it by **[proxying the request](#proxying-requests)**. This won't always work on iframes, though. You may need to virtualize the source and livestream it from your server. That has its own set of limitations.

## Proxying Requests

As a last resort, you can proxy requests through your **Web Server**. This is useful when you need to make requests to a specific port or handle requests that the **Discord Proxy** can't, but it's not always the best solution.

Creating your own proxy is easy. Just create a file in `/src/api` called `proxy.js` with the following code:

```js
export default async (request) => {
return fetch(request.query.url)
}
```

You can use it like so inside your **Activity Client**:

```jsx
<Player url={'/api/proxy?url=' + ExternalUrl} />
```

This code basically has your **Web Server** to fetch the data and send it back to your **Activity Client**.

While this method is effective for bypassing **CSP** restrictions, it does introduce additional latency because your server has to fetch the resource before serving it back to the activity. This may impact the performance of your activity, especially for large files or high traffic, so make sure your **[Hosting Service](https://docs.roboplay.dev/discord-activities/hosting)** can handle it.

Be aware of potential security risks when using a proxy server, such as **[URL Injections](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html)** and **[SSRF (Server-Side Request Forgery)](<https://owasp.org/Top10/A10_2021-Server-Side_Request_Forgery_(SSRF)>)** attacks. Always use Discord's **URL Mapping** whenever possible.

## Additional Resources

<CardContainer>
<Card
href="https://discord.com/developers/docs/activities/development-guides#activity-proxy-considerations"
title="🔗 Discord Developer Docs"
description="Learn more about the Discord Proxy."
/>
<Card
href="https://dev.to/waveplay/resolve-content-security-policy-csp-issues-in-your-discord-activity-using-a-nodejs-proxy-2634"
title="📚 Resolve CSP Issues with a Proxy"
description="A guide on how to set up a proxy to bypass CSP issues."
/>
</CardContainer>
3 changes: 2 additions & 1 deletion docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ const sidebars = {
label: '✨ Getting Started',
type: 'doc'
},
'discord-activities/multiplayer'
'discord-activities/proxy',
'discord-activities/multiplayer',
]
},
{
Expand Down

0 comments on commit 83046bb

Please sign in to comment.