16 KiB
What is this?
This is a project to create a federated social network based on the Lysand 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
- Inbound federation
- S3 or local media storage
- Deduplication of uploaded files
- Federation limits
- Configurable defaults
- Full regex-based filters for posts, users and media
- Custom emoji support
- Automatic image conversion to WebP or other formats
- Moderation tools
- Full Mastodon API support
- Outbound federation
How do I run it?
Requirements
- The Bun Runtime, 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
- Clone this repository
git clone https://github.com/lysand-org/lysand.git
- Install the dependencies
bun install
- Set up a PostgreSQL database, using the
pg_uuidv7extension
You may use the following Dockerfile to set it up:
# 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
-
Copy the
config.toml.examplefile toconfig.tomland fill in the values (you can leave most things to the default, but you will need to configure things such as the database connection) -
Run migrations:
bun migrate
Running
To run the server, simply run the following command:
bun start
Contributing
Contributions are welcome! Please see the 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:48654username: 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:trueconvert_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 S3secret_access_key: Secret access key to use for S3bucket_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:465username: 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
send_on_report: Whether to send an email to moderators when a report is received. Example:falsesend_on_suspend: Whether to send an email to moderators when a user is suspended. Example:truesend_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:30max_bio_size: The maximum size of a user's bio, in characters. Example:160max_note_size: The maximum size of a user's note, in characters. Example:500max_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:4max_media_description_size: The maximum size of a media attachment's description, in characters. Example:100max_username_size: The maximum size of a user's username, in characters. Example:20username_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:trueemail_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:truefetch_all_collection_members: Whether to fetch all members of collections (followers, following, etc) when receiving them. Example:falsereject_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:truelog_requests_verbose: Whether to log request and their contents. Example:falselog_filters: Whether to log all filtered objects. Example:true
Ratelimits
duration_coeff: The amount to multiply every route's duration by. Example:1.0max_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.
