mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 16:38:19 +01:00
432 lines
18 KiB
Markdown
432 lines
18 KiB
Markdown
<p align="center">
|
|
<a href="https://lysand.org"><img src="https://cdn-web.cpluspatch.com/lysand.webp" alt="Lysand Logo" height=130></a>
|
|
</p>
|
|
|
|
       [](code_of_conduct.md)
|
|
|
|
|
|
## What is this?
|
|
|
|
This is a project to create a federated social network based on the [Lysand](https://lysand.org) protocol. It is currently in alpha phase, with basic federation and API support.
|
|
|
|
This project aims to be a fully featured social network, with a focus on privacy and security. It will implement the Mastodon API for support with clients that already support Mastodon or Pleroma.
|
|
|
|
> **Note:** This project is not affiliated with Mastodon or Pleroma, and is not a fork of either project. It is a new project built from the ground up.
|
|
|
|
## Features
|
|
|
|
- [x] Inbound federation
|
|
- [x] S3 or local media storage
|
|
- [x] Deduplication of uploaded files
|
|
- [x] Federation limits
|
|
- [x] Configurable defaults
|
|
- [x] Full regex-based filters for posts, users and media
|
|
- [x] Custom emoji support
|
|
- [x] Automatic image conversion to WebP or other formats
|
|
- [x] Scripting-compatible CLI with JSON and CSV outputs
|
|
- [ ] Moderation tools
|
|
- [ ] Full Mastodon API support
|
|
- [ ] Outbound federation
|
|
|
|
## Benchmarks
|
|
|
|
> **Note**: These benchmarks are not representative of real-world performance, and are only meant to be used as a rough guide.
|
|
|
|
### Timeline Benchmarks
|
|
|
|
You may run the following command to benchmark the `/api/v1/timelines/home` endpoint:
|
|
|
|
```bash
|
|
TOKEN=token_here bun benchmark:timeline <request_count>
|
|
```
|
|
|
|
The `request_count` variable is optional and defaults to 100. `TOKEN` is your personal user token, used to login to the API.
|
|
|
|
## How do I run it?
|
|
|
|
### Requirements
|
|
|
|
- The [Bun Runtime](https://bun.sh), version 1.0.5 or later (usage of the latest version is recommended)
|
|
- A PostgreSQL database
|
|
- (Optional but recommended) A Linux-based operating system
|
|
|
|
> **Note**: We will not be offerring support to Windows or MacOS users. If you are using one of these operating systems, please use a virtual machine or container to run Lysand.
|
|
|
|
### Installation
|
|
|
|
1. Clone this repository
|
|
|
|
```bash
|
|
git clone https://github.com/lysand-org/lysand.git
|
|
```
|
|
|
|
2. Install the dependencies
|
|
|
|
```bash
|
|
bun install
|
|
```
|
|
|
|
3. Set up a PostgreSQL database, using the `pg_uuidv7` extension
|
|
|
|
You may use the following [Dockerfile](Postgres.Dockerfile) to set it up:
|
|
|
|
```Dockerfile
|
|
# Use the latest Postgres Docker image based on Alpine
|
|
FROM postgres:alpine
|
|
|
|
# Set working directory
|
|
WORKDIR /usr/src/app
|
|
|
|
# Install curl
|
|
RUN apk add --no-cache curl
|
|
|
|
RUN cd "$(mktemp -d)" \
|
|
&& curl -LO "https://github.com/fboulnois/pg_uuidv7/releases/download/v1.3.0/{pg_uuidv7.tar.gz,SHA256SUMS}" \
|
|
&& tar xf pg_uuidv7.tar.gz \
|
|
&& sha256sum -c SHA256SUMS \
|
|
&& PG_MAJOR=$(pg_config --version | sed 's/^.* \([0-9]\{1,\}\).*$/\1/') \
|
|
&& cp "$PG_MAJOR/pg_uuidv7.so" "$(pg_config --pkglibdir)" \
|
|
&& cp sql/pg_uuidv7--1.3.sql pg_uuidv7.control "$(pg_config --sharedir)/extension"
|
|
# Add a script to run the CREATE EXTENSION command
|
|
RUN echo '#!/bin/sh\npsql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "CREATE EXTENSION pg_uuidv7;"' > /docker-entrypoint-initdb.d/init.sh
|
|
|
|
# Make the entrypoint script executable
|
|
RUN chmod +x /docker-entrypoint-initdb.d/init.sh
|
|
```
|
|
|
|
4. Copy the `config.toml.example` file to `config.toml` and fill in the values (you can leave most things to the default, but you will need to configure things such as the database connection)
|
|
|
|
5. Run migrations:
|
|
|
|
```bash
|
|
bun migrate
|
|
```
|
|
|
|
### Running
|
|
|
|
To run the server, simply run the following command:
|
|
|
|
```bash
|
|
bun start
|
|
```
|
|
|
|
### Using the CLI
|
|
|
|
Lysand includes a built-in CLI for managing the server. To use it, simply run the following command:
|
|
|
|
```bash
|
|
bun cli
|
|
```
|
|
|
|
You can use the `help` command to see a list of available commands. These include creating users, deleting users and more.
|
|
|
|
#### Scripting with the CLI
|
|
|
|
Some CLI commands that return data as tables can be used in scripts. To do so, you can use the `--json` flag to output the data as JSON instead of a table, or even `--csv` to output the data as CSV. See `bun cli help` for more information.
|
|
|
|
Flags can be used in any order and anywhere in the script (except for the `bun cli` command itself). The command arguments themselves must be in the correct order, however.
|
|
|
|
### Using Database Commands
|
|
|
|
The `bun prisma` commands allows you to use Prisma commands without needing to add in environment variables for the database config. Just run Prisma commands as you would normally, replacing `bunx prisma` with `bun prisma`.
|
|
|
|
## With Docker
|
|
|
|
> **Note**: Docker is currently broken, as Bun with Prisma does not work well with Docker yet for unknown reasons. The following instructions are for when this is fixed.
|
|
>
|
|
> These instructions will probably also work with Podman and other container runtimes.
|
|
|
|
You can also run Lysand using Docker. To do so, you can:
|
|
|
|
1. Acquire the Postgres Dockerfile from above
|
|
2. Use this repository's [`docker-compose.yml`](docker-compose.yml) file
|
|
3. Create the `lysand-net` docker network:
|
|
```bash
|
|
docker network create lysand-net
|
|
```
|
|
1. Fill in the config file (see [Installation](#installation))
|
|
2. Run the following command:
|
|
```bash
|
|
docker-compose up -d
|
|
```
|
|
|
|
You may need root privileges to run Docker commands.
|
|
|
|
### Running CLI commands inside Docker
|
|
|
|
You can run CLI commands inside Docker using the following command:
|
|
|
|
```bash
|
|
sudo docker exec -it lysand bun cli ...
|
|
```
|
|
|
|
### Running migrations inside Docker
|
|
|
|
You can run migrations inside Docker using the following command (if needed):
|
|
|
|
```bash
|
|
sudo docker exec -it lysand bun migrate
|
|
```
|
|
|
|
## Contributing
|
|
|
|
Contributions are welcome! Please see the [CONTRIBUTING.md](CONTRIBUTING.md) file for more information.
|
|
|
|
## Planned Extra Features
|
|
|
|
- Send notifications to moderators when a report is received
|
|
- Email notifications on certain actions
|
|
|
|
## Federation
|
|
|
|
> **Warning**: Federation has not been tested outside of automated tests. It is not recommended to use this software in production.
|
|
|
|
The following extensions are currently supported or being worked on:
|
|
- `org.lysand:custom_emojis`: Custom emojis
|
|
|
|
## API
|
|
|
|
Lysand implements the Mastodon API, with some extensions. The API is currently in early alpha, and is not recommended for use in production.
|
|
|
|
Working endpoints are:
|
|
|
|
- `/api/v1/accounts`
|
|
- `/api/v1/accounts/:id`
|
|
- `/api/v1/accounts/:id/statuses`
|
|
- `/api/v1/accounts/:id/follow`
|
|
- `/api/v1/accounts/:id/unfollow`
|
|
- `/api/v1/accounts/:id/block`
|
|
- `/api/v1/accounts/:id/unblock`
|
|
- `/api/v1/accounts/:id/mute`
|
|
- `/api/v1/accounts/:id/unmute`
|
|
- `/api/v1/accounts/:id/pin`
|
|
- `/api/v1/accounts/:id/unpin`
|
|
- `/api/v1/accounts/:id/note`
|
|
- `/api/v1/accounts/:id/remove_from_followers`
|
|
- `/api/v1/accounts/relationships`
|
|
- `/api/v1/accounts/update_credentials`
|
|
- `/api/v1/accounts/verify_credentials`
|
|
- `/api/v1/accounts/familiar_followers`
|
|
- `/api/v1/profile/avatar` (`DELETE`)
|
|
- `/api/v1/profile/header` (`DELETE`)
|
|
- `/api/v1/statuses/:id` (`GET`, `DELETE`)
|
|
- `/api/v1/statuses/:id/context`
|
|
- `/api/v1/statuses/:id/favourite`
|
|
- `/api/v1/statuses/:id/unfavourite`
|
|
- `/api/v1/statuses/:id/favourited_by`
|
|
- `/api/v1/statuses/:id/reblogged_by`
|
|
- `/api/v1/statuses/:id/reblog`
|
|
- `/api/v1/statuses/:id/unreblog`
|
|
- `/api/v1/statuses/:id/pin`
|
|
- `/api/v1/statuses/:id/unpin`
|
|
- `/api/v1/statuses`
|
|
- `/api/v1/timelines/public`
|
|
- `/api/v1/timelines/home`
|
|
- `/api/v1/apps`
|
|
- `/api/v1/instance`
|
|
- `/api/v1/custom_emojis`
|
|
- `/api/v1/apps/verify_credentials`
|
|
- `/oauth/authorize`
|
|
- `/oauth/token`
|
|
- `/api/v1/blocks`
|
|
- `/api/v1/mutes`
|
|
- `/api/v2/media`
|
|
|
|
Tests needed but completed:
|
|
|
|
- `/api/v1/media/:id`
|
|
- `/api/v1/favourites`
|
|
|
|
Endpoints left:
|
|
|
|
- `/api/v1/reports`
|
|
- `/api/v1/accounts/:id/lists`
|
|
- `/api/v1/accounts/:id/following`
|
|
- `/api/v1/follow_requests`
|
|
- `/api/v1/follow_requests/:account_id/authorize`
|
|
- `/api/v1/follow_requests/:account_id/reject`
|
|
- `/api/v1/follow_suggestions`
|
|
- `/api/v1/domain_blocks` (`GET`, `POST`, `DELETE`)
|
|
- `/api/v2/filters` (`GET`, `POST`)
|
|
- `/api/v2/filters/:id` (`GET`, `PUT`, `DELETE`)
|
|
- `/api/v2/filters/:filter_id/keywords` (`GET`, `POST`)
|
|
- `/api/v2/filters/keywords/:id` (`GET`, `PUT`, `DELETE`)
|
|
- `/api/v2/filters/:filter_id/statuses` (`GET`, `POST`)
|
|
- `/api/v2/filters/statuses/:id` (`GET`, `DELETE`)
|
|
- `/api/v1/endorsements`
|
|
- `/api/v1/featured_tags` (`GET`, `POST`)
|
|
- `/api/v1/featured_tags/:id` (`DELETE`)
|
|
- `/api/v1/featured_tags/suggestions`
|
|
- `/api/v1/preferences`
|
|
- `/api/v1/followed_tags`
|
|
- `/api/v2/suggestions`
|
|
- `/api/v1/suggestions/:account_id` (`DELETE`)
|
|
- `/api/v1/tags/:id`
|
|
- `/api/v1/tags/:id/follow`
|
|
- `/api/v1/tags/:id/unfollow`
|
|
- `/api/v1/statuses/:id/translate`
|
|
- `/api/v1/statuses/:id/bookmark`
|
|
- `/api/v1/statuses/:id/unbookmark`
|
|
- `/api/v1/statuses/:id/mute`
|
|
- `/api/v1/statuses/:id/unmute`
|
|
- `/api/v1/statuses/:id` (`PUT`)
|
|
- `/api/v1/statuses/:id/history`
|
|
- `/api/v1/statuses/:id/source`
|
|
- `/api/v1/polls/:id`
|
|
- `/api/v1/polls/:id/votes`
|
|
- `/api/v1/scheduled_statuses`
|
|
- `/api/v1/scheduled_statuses/:id` (`GET`, `PUT`, `DELETE`)
|
|
- `/api/v1/timelines/tag/:hashtag`
|
|
- `/api/v1/timelines/list/:list_id`
|
|
- `/api/v1/conversations`
|
|
- `/api/v1/conversations/:id`
|
|
- `/api/v1/conversations/:id/read`
|
|
- `/api/v1/lists` (`GET`, `POST`)
|
|
- `/api/v1/lists/:id` (`GET`, `PUT`, `DELETE`)
|
|
- `/api/v1/markers` (`GET`, `POST`)
|
|
- `/api/v1/lists/:id/accounts` (`GET`, `POST`, `DELETE`)
|
|
- `/api/v1/notifications`
|
|
- `/api/v1/notifications/:id`
|
|
- `/api/v1/notifications/clear`
|
|
- `/api/v1/notifications/:id/dismiss`
|
|
- `/api/v2/search`
|
|
- `/api/v2/instance`
|
|
- `/api/v1/instance/peers`
|
|
- `/api/v1/instance/activity`
|
|
- `/api/v1/instance/rules`
|
|
- `/api/v1/instance/domain_blocks`
|
|
- `/api/v1/instance/extended_description`
|
|
- `/api/v1/directory`
|
|
- `/api/v1/trends/tags`
|
|
- `/api/v1/trends/statuses`
|
|
- `/api/v1/trends/links`
|
|
- `/api/v1/announcements`
|
|
- `/api/v1/announcements/:id/dismiss`
|
|
- `/api/v1/announcements/:id/reactions/:name` (`PUT`, `DELETE`)
|
|
- Admin API
|
|
|
|
WebSocket Streaming API also needed to be added (and push notifications)
|
|
|
|
## Configuration Values
|
|
|
|
Configuration can be found inside the `config.toml` file. The following values are available:
|
|
|
|
### Database
|
|
|
|
- `host`: The hostname or IP address of the database server. Example: `"localhost"`
|
|
- `port`: The port number to use for the database connection. Example: `48654`
|
|
- `username`: The username to use for the database connection. Example: `"lysand"`
|
|
- `password`: The password to use for the database connection. Example: `"mycoolpassword"`
|
|
- `database`: The name of the database to use. Example: `"lysand"`
|
|
|
|
### HTTP
|
|
|
|
- `base_url`: The base URL for the HTTP server. Example: `"https://lysand.social"`
|
|
- `bind`: The hostname or IP address to bind the HTTP server to. Example: `"http://localhost"`
|
|
- `bind_port`: The port number to bind the HTTP server to. Example: `"8080"`
|
|
|
|
#### Security
|
|
|
|
- `banned_ips`: An array of strings representing banned IPv4 or IPv6 IPs. Wildcards, networks and ranges are supported. Example: `[ "192.168.0.*" ]` (empty array)
|
|
|
|
### Media
|
|
|
|
- `backend`: Specifies the backend to use for media storage. Can be "local" or "s3", "local" uploads the file to the local filesystem.
|
|
- `deduplicate_media`: When set to true, the hash of media is checked when uploading to avoid duplication.
|
|
|
|
#### Conversion
|
|
|
|
- `convert_images`: Whether to convert uploaded images to another format. Example: `true`
|
|
- `convert_to`: The format to convert uploaded images to. Example: `"webp"`. Can be "jxl", "webp", "avif", "png", "jpg" or "gif".
|
|
|
|
### S3
|
|
|
|
- `endpoint`: The endpoint to use for the S3 server. Example: `"https://s3.example.com"`
|
|
- `access_key`: Access key to use for S3
|
|
- `secret_access_key`: Secret access key to use for S3
|
|
- `bucket_name`: The bucket to use for S3 (can be left empty)
|
|
- `region`: The region to use for S3 (can be left empty)
|
|
- `public_url`: The public URL to access uploaded media. Example: `"https://cdn.example.com"`
|
|
|
|
### SMTP
|
|
|
|
- `server`: The SMTP server to use for sending emails. Example: `"smtp.example.com"`
|
|
- `port`: The port number to use for the SMTP server. Example: `465`
|
|
- `username`: The username to use for the SMTP server. Example: `"test@example.com"`
|
|
- `password`: The password to use for the SMTP server. Example: `"password123"`
|
|
- `tls`: Whether to use TLS for the SMTP server. Example: `true`
|
|
|
|
### Email
|
|
|
|
- `send_on_report`: Whether to send an email to moderators when a report is received. Example: `false`
|
|
- `send_on_suspend`: Whether to send an email to moderators when a user is suspended. Example: `true`
|
|
- `send_on_unsuspend`: Whether to send an email to moderators when a user is unsuspended. Example: `false`
|
|
|
|
### Validation
|
|
|
|
- `max_displayname_size`: The maximum size of a user's display name, in characters. Example: `30`
|
|
- `max_bio_size`: The maximum size of a user's bio, in characters. Example: `160`
|
|
- `max_note_size`: The maximum size of a user's note, in characters. Example: `500`
|
|
- `max_avatar_size`: The maximum size of a user's avatar image, in bytes. Example: `1048576` (1 MB)
|
|
- `max_header_size`: The maximum size of a user's header image, in bytes. Example: `2097152` (2 MB)
|
|
- `max_media_size`: The maximum size of a media attachment, in bytes. Example: `5242880` (5 MB)
|
|
- `max_media_attachments`: The maximum number of media attachments allowed per post. Example: `4`
|
|
- `max_media_description_size`: The maximum size of a media attachment's description, in characters. Example: `100`
|
|
- `max_username_size`: The maximum size of a user's username, in characters. Example: `20`
|
|
- `username_blacklist`: An array of strings representing usernames that are not allowed to be used by users. Defaults are from Akkoma. Example: `["admin", "moderator"]`
|
|
- `blacklist_tempmail`: Whether to blacklist known temporary email providers. Example: `true`
|
|
- `email_blacklist`: Additional email providers to blacklist. Example: `["example.com", "test.com"]`
|
|
- `url_scheme_whitelist`: An array of strings representing valid URL schemes. URLs that do not use one of these schemes will be parsed as text. Example: `["http", "https"]`
|
|
- `allowed_mime_types`: An array of strings representing allowed MIME types for media attachments. Example: `["image/jpeg", "image/png", "video/mp4"]`
|
|
|
|
### Defaults
|
|
|
|
- `visibility`: The default visibility for new notes. Example: `"public"`
|
|
- `language`: The default language for new notes. Example: `"en"`
|
|
- `avatar`: The default avatar URL. Example: `""` (empty string)
|
|
- `header`: The default header URL. Example: `""` (empty string)
|
|
|
|
### ActivityPub
|
|
|
|
> **Note**: These options do nothing and date back to when Lysand had ActivityPub support. They will be removed in a future version.
|
|
|
|
- `use_tombstones`: Whether to use ActivityPub Tombstones instead of deleting objects. Example: `true`
|
|
- `fetch_all_collection_members`: Whether to fetch all members of collections (followers, following, etc) when receiving them. Example: `false`
|
|
- `reject_activities`: An array of instance domain names without "https" or glob patterns. Rejects all activities from these instances, simply doesn't save them at all. Example: `[ "mastodon.social" ]`
|
|
- `force_followers_only`: An array of instance domain names without "https" or glob patterns. Force posts from this instance to be followers only. Example: `[ "mastodon.social" ]`
|
|
- `discard_reports`: An array of instance domain names without "https" or glob patterns. Discard all reports from these instances. Example: `[ "mastodon.social" ]`
|
|
- `discard_deletes`: An array of instance domain names without "https" or glob patterns. Discard all deletes from these instances. Example: `[ "mastodon.social" ]`
|
|
- `discard_updates`: An array of instance domain names without "https" or glob patterns. Discard all updates (edits) from these instances. Example: `[]`
|
|
- `discard_banners`: An array of instance domain names without "https" or glob patterns. Discard all banners from these instances. Example: `[ "mastodon.social" ]`
|
|
- `discard_avatars`: An array of instance domain names without "https" or glob patterns. Discard all avatars from these instances. Example: `[ "mastodon.social" ]`
|
|
- `discard_follows`: An array of instance domain names without "https" or glob patterns. Discard all follow requests from these instances. Example: `[]`
|
|
- `force_sensitive`: An array of instance domain names without "https" or glob patterns. Force set these instances' media as sensitive. Example: `[ "mastodon.social" ]`
|
|
- `remove_media`: An array of instance domain names without "https" or glob patterns. Remove these instances' media. Example: `[ "mastodon.social" ]`
|
|
|
|
### Filters
|
|
|
|
- `note_filters`: An array of regex filters to drop notes from new activities. Example: `["(https?://)?(www\\.)?youtube\\.com/watch\\?v=[a-zA-Z0-9_-]+", "(https?://)?(www\\.)?youtu\\.be/[a-zA-Z0-9_-]+"]`
|
|
- `username_filters`: An array of regex filters to drop users from new activities based on their username. Example: `[ "^spammer-[a-z]" ]`
|
|
- `displayname_filters`: An array of regex filters to drop users from new activities based on their display name. Example: `[ "^spammer-[a-z]" ]`
|
|
- `bio_filters`: An array of regex filters to drop users from new activities based on their bio. Example: `[ "badword" ]`
|
|
- `emoji_filters`: An array of regex filters to drop users from new activities based on their emoji usage. Example: `[ ":bademoji:" ]`
|
|
|
|
### Logging
|
|
|
|
- `log_requests`: Whether to log all requests. Example: `true`
|
|
- `log_requests_verbose`: Whether to log request and their contents. Example: `false`
|
|
- `log_filters`: Whether to log all filtered objects. Example: `true`
|
|
|
|
### Ratelimits
|
|
|
|
- `duration_coeff`: The amount to multiply every route's duration by. Example: `1.0`
|
|
- `max_coeff`: The amount to multiply every route's max by. Example: `1.0`
|
|
|
|
### Custom Ratelimits
|
|
|
|
- `"/api/v1/timelines/public"`: An object representing a custom ratelimit for the specified API route. Example: `{ duration = 60, max = 200 }`
|
|
|
|
|
|
## License
|
|
|
|
This project is licensed under the [AGPL-3.0](LICENSE). |