Compare commits

...

2 commits

Author SHA1 Message Date
irl
a27970713e feat: reorganise for cloud content
Some checks failed
ci / build_and_publish (push) Failing after 1m15s
2026-02-23 19:09:21 +00:00
irl
c7d058c599 feat: reorganise for cloud content 2026-02-22 19:21:02 +00:00
42 changed files with 321 additions and 105 deletions

View file

@ -1,41 +1,3 @@
# Website
This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.
## Installation
```bash
yarn
```
## Local Development
```bash
yarn start
```
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
## Build
```bash
yarn build
```
This command generates static content into the `build` directory and can be served using any static contents hosting service.
## Deployment
Using SSH:
```bash
USE_SSH=true yarn deploy
```
Not using SSH:
```bash
GIT_USER=<Your GitHub username> yarn deploy
```
If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.

6
docs/account/index.md Normal file
View file

@ -0,0 +1,6 @@
---
sidebar_position: 10
---
# User Accounts

View file

@ -1,5 +0,0 @@
---
label: Admin Guide
position: 30
link:
type: "generated-index"

View file

@ -1,5 +0,0 @@
# Introduction
:::warning[Under construction]
This documentation is a work in progress. Please [get in touch with us](mailto:help@cdr.link) if you have any questions.
:::

View file

@ -0,0 +1,5 @@
---
label: Background Topics
position: 5
link:
type: "generated-index"

View file

@ -0,0 +1,33 @@
---
title: Collateral Freedom
sidebar_position: 10
---
Collateral freedom is an anti-censorship strategy that attempts to make it **economically prohibitive** for censors to
block a resource.
The diverse needs of businesses to exchange information across international borders makes it impossible to build a
catalogue of "good" and "bad" networks or websites.
A censor requires some confidence when they block a resource that it won't be affecting economic activity.
Its difficult to achieve accuracy with filtering as most internet traffic is encrypted and must be categorised
at speed to make blocking decisions.
As a result, censors will usually err on the side of under-blocking.
One way to exploit this is by deploying solutions in large platforms that are **“too big to block”**, like public cloud
providers.
Public cloud providers host large numbers of clients in shared infrastructure to benefit from economies of scale, but
this sharing also makes it difficult to know what content is being accessed.
Similarly, large social networks host content from large numbers of publishers but all traffic between the user and the
social network is typically encrypted and so the censor cannot know what is being read.
Blocking the cloud provider would have a negative impact on businesses and would hurt state revenue, and blocking the
social media platform would cause backlash from the people: neither is an attractive option for the censor.
Another approach is to use constantly rotating identifiers, as even where a resource may be easy to block once
identified, a new resource can be deployed quickly to replace it rendering the blocks ineffective.
Due to erring on the side of under-blocking, attempts to access previously unseen content usually succeed.
Even with a procedure for screening or approval, blocking by default would bog down innovation and development to the
extent that it could cease, certainly falling behind other economies.
This approach is particularly suited for news media where the majority of readers will be interested in an article for
only a short time after it is published, and if it is later blocked by the censor then the effect will be minimal.
With collateral freedom on your side **you can have the upper hand** when it comes to making your content accessible to
your audience.

View file

@ -1,10 +1,10 @@
---
sidebar_position: 1
sidebar_label: Overview
sidebar_position: 0
sidebar_label: Welcome
---
# Documentation Overview
:::warning[Under construction]
This documentation is a work in progress. Please [get in touch with us](mailto:help@cdr.link) if you have any questions.
This documentation is a work in progress. Please [get in touch with us](mailto:contact@sr2.uk) if you have any questions.
:::

View file

@ -0,0 +1,141 @@
---
label: E2E channels
sidebar_position: 50
description: Setting up E2E channels (Signal and WhatsApp)
---
# End-to-end encrypted channels
## Initial setup
1. Log in to your CDR Link helpdesk admin panel using either Sign in with Google button or Sign in with Zammad credentials:
![Untitled](/docs/link/admin/Untitled.png)
1. Using the left side menu go to Admin → **WhatsApp** (or **Signal**):
![Untitled](/docs/link/admin/d33b0fb2-d2e4-4130-9dfc-4e5e26ab2fad.png)
1. Create the **WhatsApp** (or **Signal**) connection by using the blue Create button in top right corner of the screen:
![Untitled](/docs/link/admin/Untitled%201.png)
You will see a pop-up window like the one below:
- Fill the Name field with some recognisable name (it can be useful to name it like Signal handset 1 in case if you are planning to use more numbers) of the channel
- Fill Phone Number field with your handsets phone number containing the relevant country code.
![Untitled](/docs/link/admin/Untitled%202.png)
- Click Save.
1. You will see next window with QR code similar to the following:
<aside>
💡
You might need to wait up to one minute for the QR code to fully load (you initially will see a similar code as on the screenshot but when it loads it will have a lot more and smaller squares).
</aside>
![Untitled](/docs/link/admin/Untitled%203.png)
- Copy the Token and save it in a safe place.
- Now you need to scan the code. Depending on which channel you are configuring you have to follow the instructions below (they may vary slightly depending on what kind of device you are using, in example we are using Android device):
- For **WhatsApp**:
- Go to main screen (screen with all chats visible).
- On the top right corner tap the three dots icon.
- From the drop down menu tap on the Linked devices.
- Tap the green Link a device button.
- Scan the code from your computers screen.
- For **Signal**:
- Go to the main screen (screen with all chats visible).
- On the top right corner tap the three dots icon.
- From the drop down menu tap on the Settings.
- Tap on the Linked devices.
- Tap the blue Link a device button.
- Scan the code from your computers screen.
- In both cases after scanning the code you should see your newly linked channel connection under the Linked devices list of your WhatsApp/Signal communicator.
- You can press the blue Done button on your connection screen.
1. Now you need to create a bot. Using the left side menu go to Admin → Zammad Settings → Channels → **WhatsApp** (or **Signal**):
![Untitled](/docs/link/admin/Untitled%204.png)
1. Create the **WhatsApp** (or **Signal)** bot by using the green Add WhatsApp bot (or Add Signal bot) button in top right corner of the screen:
![Untitled](/docs/link/admin/Untitled%205.png)
You will see a pop up window like the one below:
- Fill the Phone Number field with same phone number as you used in point 3.
- Paste the bot token from point 4 into the Bot Token field (in case if you lost it you can always come back to the admin and click on the previously created connection in order to retrieve the token.
- In Bot Endpoint field paste:
- For **WhatsApp:**
```json
http://link:3000/link/api/whatsapp
```
- For **Signal**:
```json
http://link:3000/link/api/signal
```
- You can leave the Users and Organization fields as they are or pick the relevant values.
![Untitled](/docs/link/admin/7e1319ba-5c17-4eae-8226-44bbae0f7e54.png)
- Click the Submit button.
- You will see your newly created bot on the list - click the Edit button on the right side of the bot:
![Untitled](/docs/link/admin/Untitled%206.png)
- You will see the same form as previously but with one additional field: Endpoint URL - copy the part after **https://your-helpdesk.cdr.link/api/v1/channels_cdr_whatsapp_webhook/** or **https://your-helpdesk.cdr.link/api/v1/channels_cdr_signal_webhook/** - make sure to copy all of it as it is a very long code as you can see in the example below:
![Untitled](/docs/link/admin/Untitled%207.png)
![Untitled](/docs/link/admin/Untitled%208.png)
- Paste the code in the safe temporary place and click on the Cancel & Go Back link on the left bottom corner of the form.
1. The last part is to create a Webhook. Go back to the Admin panel, select Admin → Webhooks:
![Untitled](/docs/link/admin/Untitled%209.png)
- Click the blue Create button in top right corner:
![Untitled](/docs/link/admin/Untitled%2010.png)
- You will see a webhook creation form like the one below:
![Untitled](/docs/link/admin/Untitled%2011.png)
- In the Name field type some name that is relating to the channel name and handset.
- The method drop down menu should be left with Post.
- In the Endpoint field paste:
- For **WhatsApp**:
```text
http://zammad-nginx:8080/api/v1/channels_cdr_whatsapp_webhook/xxxxxxx
```
`where xxxxxx should be replaced with the code copied from Endpoint URL from point 6`
- For **Signal**:
```text
http://zammad-nginx:8080/api/v1/channels_cdr_signal_webhook/xxxxxxx
```
`where xxxxxx should be replaced with the code copied from Endpoint URL from point 6`
- Below there are two drop down menus:
- In the left one pick the relevant channel.
- In the right one pick the bot name that you created in step 3.
- Click the blue Save button.
🎉 Congrats! Your connection is ready!
## Reconnection

15
docs/link/admin/index.mdx Normal file
View file

@ -0,0 +1,15 @@
---
sidebar_label: Admin Guide
sidebar_position: 30
---
import DocCardList from '@theme/DocCardList';
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
# Admin Guide
:::warning[Under construction]
This documentation is a work in progress. Please [get in touch with us](mailto:contact@sr2.uk) if you have any questions.
:::
<DocCardList items={useCurrentSidebarCategory().items} />

View file

@ -1,5 +1,5 @@
# Introduction
:::warning[Under construction]
This documentation is a work in progress. Please [get in touch with us](mailto:help@cdr.link) if you have any questions.
This documentation is a work in progress. Please [get in touch with us](mailto:contact@sr2.uk) if you have any questions.
:::

View file

@ -1,5 +1,5 @@
---
sidebar_position: 5
sidebar_position: 50
---
# Hosted CDR Link FAQ

15
docs/link/index.mdx Normal file
View file

@ -0,0 +1,15 @@
---
sidebar_position: 20
sidebar_label: Link Helpdesk
---
import DocCardList from '@theme/DocCardList';
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
# Documentation Overview
:::warning[Under construction]
This documentation is a work in progress. Please [get in touch with us](mailto:contact@sr2.uk) if you have any questions.
:::
<DocCardList items={useCurrentSidebarCategory().items.slice(1)} />

26
docs/mirrors/index.mdx Normal file
View file

@ -0,0 +1,26 @@
---
title: Web Mirrors
sidebar_position: 30
---
A web mirror can help users by providing alternate URLs to access censored resources, allowing them to bypass censorship
and access information that may be otherwise blocked.
Web mirrors work by forwarding requests to the original website, and providing a different URL to access that content.
Dynamic web mirrors use frequently changing URLs to evade censorship, making it more difficult for censors to maintain
blocks for the content.
This assumption of a limited lifetime is built-in to the system, allowing for automated block detection to trigger the
deployment of new URLs, and for the new URLs to be made available via the portal, the API, and via dead drops.
Named web mirrors use alternative domain names with limited distribution to evade censorship.
By blending with the "long tail" of web traffic, it may take longer for these mirrors to be discovered.
Web mirrors can be accessed via a normal web browser, making them easily accessible to users without requiring any
special software or technical knowledge.
<figure style={{"text-align": "center"}}>
<img src="/img/mirrors/overview.png" style={{"max-width": "100%", "max-height": "500px"}} />
<figcaption style={{"font-weight": "bold"}}>
The jasima.app portal overview for web mirrors
</figcaption>
</figure>

View file

@ -0,0 +1,32 @@
---
title: Troubleshooting
sidebar_position: 100
---
We have collected solutions to common issued faced by web mirrors users.
If you are unable to resolve your issue, please [get in touch](/contact) with us to discuss the options.
## Upstream Rate Limiting
CDNs (Content Delivery Networks) can impose rate limiting or "bot detection" on websites to ensure that the network
resources are efficiently utilized, to protect the websites from Denial of Service (DoS) attacks, and to
maintain the quality of service for all the websites using the CDN.
If you find that mirrors are producing many “Rate Limited Exceeded” or “Access Denied” errors then you may be suffering
from this problem.
These rate limits will be sized according to the expected rate of requests from an average user, however the mirror
system is a bottleneck that aggregates requests from multiple users and passes these on to the original CDN.
When a single system is used to send a large number of requests to a CDN like this, the CDN may interpret this as a
DoS attack and prevent access to the website.
The optimal approach is to configure the origin to use an alternative host for connections, so that the CDN is bypassed
and the backend origin (web server) is used directly.
The mirror will still be the access point for users and this will not reveal the location of the backend origin to your
users.
If this is not possible, then deploying mirrors for websites hosted on CDNs will require either configuration at, or
co-operation from, the CDN provider.
Additional headers can be configured for the origin to authenticate requests that originate from jasima.app, and these
can be used to bypass the protection mechanisms at your CDN.
Consult your CDN's documentation or contact their support team to configure using an additional header to disable the
rate limiting for requests originating from jasima.app.

View file

@ -10,8 +10,8 @@ import {themes as prismThemes} from 'prism-react-renderer';
/** @type {import('@docusaurus/types').Config} */
const config = {
title: 'CDR Link',
tagline: 'A guide for agents, admins, and operators',
title: 'SR2® Cloud',
tagline: 'A cloud for civil society',
favicon: 'img/favicon.ico',
// Future flags, see https://docusaurus.io/docs/api/docusaurus-config#future
@ -20,7 +20,7 @@ const config = {
},
// Set the production url of your site here
url: 'https://docs.cdr.link',
url: 'https://docs.sr2.uk',
// Set the /<baseUrl>/ pathname under which your site is served
// For GitHub pages deployment, it is often '/<projectName>/'
baseUrl: '/',
@ -83,12 +83,12 @@ const config = {
respectPrefersColorScheme: true,
},
navbar: {
title: 'CDR Link',
title: 'SR2® Cloud',
logo: {
alt: '',
src: 'img/link-logo.png',
// href: 'https://www.digiresilience.org/solutions/link/',
// target: '_self',
src: 'img/sr2-logo.webp',
href: '/',
target: '_self',
},
items: [
{
@ -112,16 +112,12 @@ const config = {
title: 'Docs',
items: [
{
label: 'Agent Guide',
to: '/docs/category/agent-guide',
label: 'Link Helpdesk',
to: '/docs/link',
},
{
label: 'Admin Guide',
to: '/docs/category/admin-guide',
},
{
label: 'Operator Guide',
to: '/docs/category/operator-guide',
label: 'Web Mirrors',
to: '/docs/mirrors',
},
],
},
@ -129,30 +125,36 @@ const config = {
title: 'Policy',
items: [
{
label: 'Code of Practice',
href: 'https://digiresilience.org/about/code-practice/',
label: 'Terms and Conditions',
href: 'https://www.sr2.uk/terms',
},
{
label: 'Code of Conduct',
href: 'https://digiresilience.org/about/code-conduct/',
label: 'Privacy Policy',
href: 'https://www.sr2.uk/privacy',
},
{
label: 'Complaints Policy',
href: 'https://www.sr2.uk/complaints',
}
],
},
{
title: 'More',
items: [
{
label: 'Center for Digital Resilience',
href: 'https://digiresilience.org/',
label: 'SR2 Communications',
href: 'https://www.sr2.uk/',
},
{
label: 'GitLab',
href: 'https://gitlab.com/digiresilience/link/',
label: 'Open Source',
href: 'https://guardianproject.dev/sr2/',
},
],
},
],
copyright: `Copyright © 2021-${new Date().getFullYear()}. This documentation is made available to you under the terms of the Creative Commons Attribution 4.0 International licence.`,
copyright: `
<a href="https://cloud.sr2.uk/">SR2 Cloud Documentation</a> © 2021-${new Date().getFullYear()} is licensed under <a href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a><img src="https://mirrors.creativecommons.org/presskit/icons/cc.svg" alt="" style="max-width: 1em;max-height:1em;margin-left: .2em;"><img src="https://mirrors.creativecommons.org/presskit/icons/by.svg" alt="" style="max-width: 1em;max-height:1em;margin-left: .2em;">.
<br>SR2® and SR2 Communications® are registered trademarks of SR2 Communications Limited, a company registered in Scotland, number SC692687.`
},
prism: {
theme: prismThemes.github,

View file

@ -16,6 +16,19 @@ function HomepageHeader() {
{siteConfig.title}
</Heading>
<p className="hero__subtitle">{siteConfig.tagline}</p>
<div className={styles.buttons}>
<Link
className="button button--primary button--lg disabled"
to="/">
Login to Console 🧑💻
</Link>
<Link
className="button button--secondary button--lg"
to="/docs">
Read the Docs 📚
</Link>
</div>
</div>
</header>
);
@ -26,7 +39,7 @@ export default function Home() {
return (
<Layout
title={`${siteConfig.title}`}
description="A guide for agents, admins, and operators of the CDR Link secure helpdesk platform.">
description="Cloud.">
<HomepageHeader />
<main>
<HomepageFeatures />

View file

@ -8,7 +8,7 @@
text-align: center;
position: relative;
overflow: hidden;
background-image: linear-gradient(270deg, rgb(255, 113, 21), rgb(250, 201, 66));
background-image: linear-gradient(270deg, #004B67, #009A64);
}
@media screen and (max-width: 996px) {
@ -21,4 +21,5 @@
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View file

@ -1,25 +0,0 @@
<svg width="840" height="857" viewBox="0 0 840 857" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d)">
<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="41" y="41" width="758" height="775">
<path fill-rule="evenodd" clip-rule="evenodd" d="M79.6604 41.0193L798.203 78.6581L759.543 815.981L41.0001 778.342L79.6604 41.0193Z" fill="white"/>
</mask>
<g mask="url(#mask0)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M257.577 179.457L247.85 411.222C247.844 411.412 247.788 411.599 247.694 411.765L117.322 637.207C116.619 638.415 114.772 637.612 115.179 636.276L255.282 179.066C255.685 177.745 257.633 178.08 257.577 179.457ZM611.39 284.61L712.43 561.445C712.877 562.67 711.297 563.603 710.441 562.62L329.394 124.082C328.523 123.082 329.712 121.636 330.86 122.294L608.648 281.356C609.917 282.086 610.888 283.234 611.39 284.61ZM272.819 430.195L698.005 613.883C699.063 614.342 698.9 615.888 697.776 616.112L97.5989 737.09C96.6075 737.286 95.845 736.222 96.3522 735.349L272.819 430.195ZM279.391 398.465L290.666 129.839C290.71 128.779 292.029 128.317 292.728 129.121L673.189 566.981C674.009 567.924 672.985 569.324 671.84 568.83L280.1 399.588C279.657 399.398 279.374 398.949 279.391 398.465ZM633.872 260.097L269.832 51.6458C266.383 49.6734 261.996 51.4057 260.831 55.2071L41.603 770.65C40.2278 775.135 44.1502 779.467 48.7517 778.537L764.408 634.286C768.128 633.535 770.305 629.651 769.007 626.089L636.614 263.351C636.112 261.979 635.137 260.826 633.872 260.097Z" fill="url(#paint0_linear)"/>
</g>
</g>
<defs>
<filter id="filter0_d" x="0.00927734" y="0.00976562" width="839.184" height="856.98" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="20.5"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0471014 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
<linearGradient id="paint0_linear" x1="368.206" y1="875.676" x2="614.412" y2="219" gradientUnits="userSpaceOnUse">
<stop stop-color="#ED633A"/>
<stop offset="1" stop-color="#FEE128"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

BIN
static/img/sr2-logo.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB