Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 0 additions & 51 deletions .github/workflows/claude.yml

This file was deleted.

36 changes: 19 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
[![](https://github.com/monkeytypegame/monkeytype/blob/master/frontend/static/images/githubbanner2.png?raw=true)](https://monkeytype.com/)
<br />

[![ChartJs](https://img.shields.io/badge/Chart.js-FF6384?style=for-the-badge&logo=chartdotjs&logoColor=white)](https://www.chartjs.org/)
[![Eslint](https://img.shields.io/badge/eslint-4B32C3?style=for-the-badge&logo=eslint&logoColor=white)](https://eslint.org/)
[![Express](https://img.shields.io/badge/-Express-373737?style=for-the-badge&logo=Express&logoColor=white)](https://expressjs.com/)
[![Firebase](https://img.shields.io/badge/firebase-DD2C00?style=for-the-badge&logo=firebase&logoColor=black)](https://firebase.google.com/)
[![Fontawesome](https://img.shields.io/badge/fontawesome-538DD7?style=for-the-badge&logo=fontawesome&logoColor=white)](https://fontawesome.com/)
[![HTML5](https://img.shields.io/badge/html5-E34F26?style=for-the-badge&logo=html5&logoColor=white)](https://developer.mozilla.org/en-US/docs/Web/HTML)
[![MongoDB](https://img.shields.io/badge/-MongoDB-47A248?style=for-the-badge&logo=mongodb&logoColor=white)](https://www.mongodb.com/)
[![OXLint](https://img.shields.io/badge/oxlint-2b3c5a?style=for-the-badge&logo=oxc&logoColor=white)](https://oxc.rs/docs/guide/usage/linter.html)
[![PNPM](https://img.shields.io/badge/pnpm-F69220?style=for-the-badge&logo=pnpm&logoColor=white)](https://pnpm.io/)
[![Redis](https://img.shields.io/badge/Redis-FF4438?style=for-the-badge&logo=redis&logoColor=white)](https://redis.io/)
[![SASS](https://img.shields.io/badge/SASS-CC6699?style=for-the-badge&logo=SASS&logoColor=white)](https://sass-lang.com/)
[![Solid](https://img.shields.io/badge/solid-2C4F7C?style=for-the-badge&logo=solid&logoColor=white)](https://www.solidjs.com/)
[![Tailwind](https://img.shields.io/badge/tailwind-06B6D4?style=for-the-badge&logo=tailwindcss&logoColor=white)](https://tailwindcss.com/)
[![AnimeJs](https://img.shields.io/badge/Anime.js-ff4b4b?style=for-the-badge&logo=animedotjs&logoColor=white)](https://animejs.com/)&nbsp;
[![ChartJs](https://img.shields.io/badge/Chart.js-FF6384?style=for-the-badge&logo=chartdotjs&logoColor=white)](https://www.chartjs.org/)&nbsp;
[![Eslint](https://img.shields.io/badge/eslint-4B32C3?style=for-the-badge&logo=eslint&logoColor=white)](https://eslint.org/)&nbsp;
[![Express](https://img.shields.io/badge/-Express-373737?style=for-the-badge&logo=Express&logoColor=white)](https://expressjs.com/)&nbsp;
[![Firebase](https://img.shields.io/badge/firebase-DD2C00?style=for-the-badge&logo=firebase&logoColor=black)](https://firebase.google.com/)&nbsp;
[![Fontawesome](https://img.shields.io/badge/fontawesome-538DD7?style=for-the-badge&logo=fontawesome&logoColor=white)](https://fontawesome.com/)&nbsp;
[![HTML5](https://img.shields.io/badge/html5-E34F26?style=for-the-badge&logo=html5&logoColor=white)](https://developer.mozilla.org/en-US/docs/Web/HTML)&nbsp;
[![MongoDB](https://img.shields.io/badge/-MongoDB-47A248?style=for-the-badge&logo=mongodb&logoColor=white)](https://www.mongodb.com/)&nbsp;
[![OXLint](https://img.shields.io/badge/oxlint-2b3c5a?style=for-the-badge&logo=oxc&logoColor=white)](https://oxc.rs/docs/guide/usage/linter.html)&nbsp;
[![PNPM](https://img.shields.io/badge/pnpm-F69220?style=for-the-badge&logo=pnpm&logoColor=white)](https://pnpm.io/)&nbsp;
[![Redis](https://img.shields.io/badge/Redis-FF4438?style=for-the-badge&logo=redis&logoColor=white)](https://redis.io/)&nbsp;
[![SASS](https://img.shields.io/badge/SASS-CC6699?style=for-the-badge&logo=SASS&logoColor=white)](https://sass-lang.com/)&nbsp;
[![Solid](https://img.shields.io/badge/solid-2C4F7C?style=for-the-badge&logo=solid&logoColor=white)](https://www.solidjs.com/)&nbsp;
[![Tailwind](https://img.shields.io/badge/tailwind-06B6D4?style=for-the-badge&logo=tailwindcss&logoColor=white)](https://tailwindcss.com/)&nbsp;
[![Tanstack](https://img.shields.io/badge/Tanstack-EDE8D1?style=for-the-badge&logo=tanstack&logoColor=3A3A38)](https://tanstack.com/)&nbsp;
[![TsRest](https://img.shields.io/badge/-TSREST-9333ea?style=for-the-badge&logoColor=white&logo=data:image/svg%2bxml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB3aWR0aD0iMjAuMzA2Nzc4bW0iCiAgIGhlaWdodD0iMTIuMDgzMjMzbW0iCiAgIHZpZXdCb3g9IjAgMCAyMC4zMDY3NzggMTIuMDgzMjMzIgogICB2ZXJzaW9uPSIxLjEiCiAgIGlkPSJzdmcxIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0ibmFtZWR2aWV3MSIKICAgICBwYWdlY29sb3I9IiM1MDUwNTAiCiAgICAgYm9yZGVyY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMSIKICAgICBpbmtzY2FwZTpzaG93cGFnZXNoYWRvdz0iMCIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMCIKICAgICBpbmtzY2FwZTpwYWdlY2hlY2tlcmJvYXJkPSIxIgogICAgIGlua3NjYXBlOmRlc2tjb2xvcj0iI2QxZDFkMSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0ibW0iIC8+CiAgPGRlZnMKICAgICBpZD0iZGVmczEiIC8+CiAgPGcKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIgogICAgIGlkPSJsYXllcjEiCiAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTMuODE5ODA1NCwtMi4yMTQ3MTkzKSI+CiAgICA8cGF0aAogICAgICAgZD0ibSAxNS40NTgwMzUsOC45NzMzOTUzIDguNjMzMjUsMC4wNDQ4NyAwLjAwOSwtMS42NjgxOTggLTguNjMzMjIsLTAuMDQ0ODUgeiBtIDAuMDI2MywtNS4wNTYxMDggOC42MzMyNSwwLjA0NDg1IDAuMDA5LC0xLjcwMjU2OCAtOC42MzMyNSwtMC4wNDQ4NSB6IG0gLTAuMDQ0OCw4LjYzMzI0NzcgOC42MzMyMywwLjA0NDg1IC0wLjAwOSwxLjcwMjU2NyAtOC42MzMyNSwtMC4wNDQ4NSB6IgogICAgICAgZmlsbD0iI2ZmZmZmZiIKICAgICAgIGlkPSJwYXRoMSIKICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC4yNjQ1ODMiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAxMS4xMTE3MjUsMTAuMjg2NjI4IGMgMS42NTEsLTAuNjE5MTI0NyAyLjU5Njg4LC0xLjk2MDU2MjcgMi41OTY4OCwtMy44MDA3Mzk3IDAsLTIuNjQ4NDc5IC0xLjkyNjE2LC00LjI0Nzg4NSAtNS4wNzMzNzk2LC00LjI0Nzg4NSBoIC00LjgxNTQyIHYgMS43MDI1OTQgaCA0Ljc0NjYzIGMgMi4wODA5Mzk2LDAgMy4xNjQ0MDk2LDAuOTI4Njg3IDMuMTY0NDA5NiwyLjU0NTI5MSAwLDEuNTk5NDA2IC0xLjA4MzQ3LDIuNTQ1MjkyIC0zLjE2NDQwOTYsMi41NDUyOTIgaCAtNC43NDY2MyB2IDUuMjQ1MzYzNyBoIDEuOTYwNTYgdiAtMy41NzcxNjYgaCAyLjg1NDg2IGMgMC4yMDYzNywwIDAuNDI5OTUsMCAwLjYxOTEyLC0wLjAxNzIgbCAyLjUyODA5OTYsMy41OTQzNjQgaCAyLjEzMjU0IHoiCiAgICAgICBmaWxsPSIjZmZmZmZmIgogICAgICAgaWQ9InBhdGgyIgogICAgICAgc3R5bGU9InN0cm9rZS13aWR0aDowLjI2NDU4MyIgLz4KICA8L2c+Cjwvc3ZnPgo=)](https://ts-rest.com/)
[![Turborepo](https://img.shields.io/badge/-Turborepo-FF1E56?style=for-the-badge&logo=turborepo&logoColor=white)](https://turborepo.org/)
[![TypeScript](https://img.shields.io/badge/typescript-3178C6?style=for-the-badge&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
[![Vite](https://img.shields.io/badge/Vite-9135FF?style=for-the-badge&logo=Vite&logoColor=white)](https://vitejs.dev/)
[![Vitest](https://img.shields.io/badge/vitest-00FF74?style=for-the-badge&logo=vitest&logoColor=white)](https://vitest.dev/)
[![Turborepo](https://img.shields.io/badge/-Turborepo-FF1E56?style=for-the-badge&logo=turborepo&logoColor=white)](https://turborepo.org/)&nbsp;
[![TypeScript](https://img.shields.io/badge/typescript-3178C6?style=for-the-badge&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)&nbsp;
[![Vite](https://img.shields.io/badge/Vite-9135FF?style=for-the-badge&logo=Vite&logoColor=white)](https://vitejs.dev/)&nbsp;
[![Vitest](https://img.shields.io/badge/vitest-00FF74?style=for-the-badge&logo=vitest&logoColor=white)](https://vitest.dev/)&nbsp;
[![Zod](https://img.shields.io/badge/-Zod-408AFF?style=for-the-badge&logo=zod&logoColor=white)](https://zod.dev/)

# About
Expand Down
2 changes: 1 addition & 1 deletion docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ If you want to contribute languages but don't know how, check [LANGUAGES.md](/do
- Verify the `id` property is incremented correctly
- Please do not add extremely short quotes (less than 60 characters)
- For quotes not in English, please include translations of quotes in the description of your pull request. This assists in the verification process to ensure the integrity of the quotes.
- Remember to name your pull request properly. For example, if you are adding new quotes for the language `French`, your pull request should be named `impr(quotes): add French quotes`.
- Remember to name your pull request properly. For example, if you are adding new quotes for the language `French`, your pull request should be named `impr(quotes): add French quotes (@yourusername)`.

If you want to contribute quotes but don't know how, check [QUOTES.md](/docs/QUOTES.md)

Expand Down
25 changes: 25 additions & 0 deletions docs/SELF_HOSTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- [Prerequisites](#prerequisites)
- [Quickstart](#quickstart)
- [Hosting over the network (HTTPS)](#hosting-over-the-network-https)
- [Security](#security)
- [Account System](#account-system)
- [Setup Firebase](#setup-firebase)
- [Update backend configuration](#update-backend-configuration)
Expand Down Expand Up @@ -61,6 +62,30 @@ docker compose up -d --force-recreate
> After updating your configuration and recreating the containers, clear your browser cache or perform a hard reload (Ctrl + F5) to make sure your browser isn't running an old cached version of the frontend.


## Security

Do not expose the Monkeytype backend directly to the internet. Instead, place it behind a reverse proxy and configure the backend to only accept connections from the reverse proxy.

The backend's built-in rate limiting is based on the authenticated user's `uid` or, for unauthenticated requests, the client's IP address.

To determine the client's IP address, the backend checks the following sources in order:

1. `CF-Connecting-IP` (when requests are proxied through Cloudflare)
2. `X-Forwarded-For`
3. The source IP address of the HTTP connection

We recommend the following configuration:

- If you are **not** using Cloudflare, remove any incoming `CF-Connecting-IP` header in your reverse proxy before forwarding requests.
- Configure your reverse proxy to set the `X-Forwarded-For` header to the client's IP address.
- Configure the backend to only accept connections from the reverse proxy to prevent clients from spoofing trusted headers.


Sources:
- [cloudflare documentation for cf-connecting-ip](https://developers.cloudflare.com/fundamentals/reference/http-headers/#cf-connecting-ip)
- [handling headers in traefik](https://doc.traefik.io/traefik/reference/routing-configuration/http/middlewares/headers)


## Account System

By default, user sign-up and login are disabled. To enable this, you'll need to set up a Firebase project.
Expand Down
17 changes: 7 additions & 10 deletions frontend/src/privacy-policy.html
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
appears at the end of this Privacy Statement.
</p>
<p>Table of Contents</p>
<!-- The last three internal links are redunant because the anchor stops at the same location but gives more context to the user when they are viewing the table of contents -->
<!-- The last three internal links are redundant because the anchor stops at the same location but gives more context to the user when they are viewing the table of contents -->
<ul>
<li><a href="#Data_Collection">What data do we collect?</a></li>
<li>
Expand All @@ -146,9 +146,6 @@
<li>
<a href="#Advertisements">Advertisements</a>
</li>
<li>
<a href="#Advertisements2">Advertisements Part 2</a>
</li>
<li><a href="#Cookies">What are cookies?</a></li>
<li><a href="#Usage_of_Cookies">How do we use cookies?</a></li>
<li>
Expand Down Expand Up @@ -384,13 +381,13 @@ <h1 id="Cookies">What are cookies?</h1>
HTTP cookie
</a>
<!--
We need this nbsp to make sure there's no missing whitespace in production.
We need this nbsp to make sure there's no missing whitespace in production.
This is because without it the minifier collapses the whitespace after
"HTTP cookie" and the one after the closing `a` tag into a single space
located after "HTTP cookie" (inside the `a` tag), and because the `a` tag
has display: inline-block, the space will not be rendered. Use nbsp to make
sure the minifier doesn't remove it.
-->
"HTTP cookie" and the one after the closing `a` tag into a single space
located after "HTTP cookie" (inside the `a` tag), and because the `a` tag
has display: inline-block, the space will not be rendered. Use &nbsp; to make
sure the minifier doesn't remove it.
-->
&nbsp;on Wikipedia.
</p>

Expand Down
20 changes: 13 additions & 7 deletions frontend/src/ts/components/modals/QuoteSearchModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,9 @@ function Item(props: {
class="text-text [&_.highlight]:text-main"
dir="auto"
// oxlint-disable-next-line solid/no-innerhtml
innerHTML={Misc.escapeHTML(
highlightMatches(props.quote.text, props.matchedTerms),
innerHTML={highlightMatches(
Misc.escapeHTML(props.quote.text),
props.matchedTerms,
)}
></div>
<div class="grid grid-cols-2 gap-2 sm:grid-cols-[1fr_1fr_3fr]">
Expand All @@ -139,8 +140,9 @@ function Item(props: {
<span
class="[&_.highlight]:text-main"
// oxlint-disable-next-line solid/no-innerhtml
innerHTML={Misc.escapeHTML(
highlightMatches(props.quote.id.toString(), props.matchedTerms),
innerHTML={highlightMatches(
Misc.escapeHTML(props.quote.id.toString()),
props.matchedTerms,
)}
></span>
</div>
Expand All @@ -154,8 +156,9 @@ function Item(props: {
<span
class="[&_.highlight]:text-main"
// oxlint-disable-next-line solid/no-innerhtml
innerHTML={Misc.escapeHTML(
highlightMatches(props.quote.source, props.matchedTerms),
innerHTML={highlightMatches(
Misc.escapeHTML(props.quote.source),
props.matchedTerms,
)}
></span>
</div>
Expand Down Expand Up @@ -291,7 +294,10 @@ export function QuoteSearchModal(): JSXElement {
];
}

setSearchResults({ quotes: matches, matchedTerms: matchedQueryTerms });
setSearchResults({
quotes: matches,
matchedTerms: matchedQueryTerms.map(Misc.escapeHTML),
});
};

const filteredQuotes = (): Quote[] => {
Expand Down
2 changes: 1 addition & 1 deletion frontend/static/quotes/english.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
},
{
"text": "And in the end, the love you take is equal to the love you make.",
"source": "The End",
"source": "The End - The Beatles",
"id": 18,
"length": 64
},
Expand Down
Loading