diff --git a/.vitepress/config.mts b/.vitepress/config.mts index fa72384..779187b 100644 --- a/.vitepress/config.mts +++ b/.vitepress/config.mts @@ -1,9 +1,20 @@ +import tailwindcss from "@tailwindcss/vite"; import { defineConfig } from "vitepress"; // https://vitepress.dev/reference/site-config export default defineConfig({ title: "Lysand Documentation", description: "Documentation for Lysand, a new federated protocol", + vite: { + plugins: [tailwindcss()], + }, + vue: { + template: { + compilerOptions: { + isCustomElement: (tag) => tag === "iconify-icon", + }, + }, + }, srcDir: "docs", themeConfig: { // https://vitepress.dev/reference/default-theme-config @@ -11,6 +22,8 @@ export default defineConfig({ { text: "Home", link: "/" }, { text: "Specification", link: "/spec" }, { text: "Objects", link: "/objects" }, + { text: "Security", link: "/security/api" }, + { text: "Extensions", link: "/extensions" }, ], sidebar: [ @@ -118,10 +131,19 @@ export default defineConfig({ { text: "Events", link: "/extensions/events" }, { text: "Reports", link: "/extensions/reports" }, { text: "Vanity", link: "/extensions/vanity" }, + { + text: "Interactivity", + link: "/extensions/interactivity", + }, ], }, ], + footer: { + message: "Released under the MIT License.", + copyright: "Copyright © 2023-present Gaspard Wierzbinski", + }, + socialLinks: [ { icon: "github", link: "https://github.com/lysand-org/" }, ], @@ -131,11 +153,12 @@ export default defineConfig({ editLink: { pattern: "https://github.com/lysand-org/docs/edit/main/docs/:path", }, + externalLinkIcon: true, logo: "https://cdn.lysand.org/logo.webp", }, lastUpdated: true, cleanUrls: true, - titleTemplate: ":title · Lysand 2.0 Docs", + titleTemplate: ":title · Lysand Docs", head: [["link", { rel: "icon", href: "/favicon.png", type: "image/png" }]], lang: "en-US", }); diff --git a/.vitepress/theme/custom.css b/.vitepress/theme/custom.css new file mode 100644 index 0000000..bbb1605 --- /dev/null +++ b/.vitepress/theme/custom.css @@ -0,0 +1,61 @@ +@import "tailwindcss"; + +@theme { +} +:root { + /* --vp-home-hero-image-background-image: linear-gradient( + to top right, + rgb(249, 168, 212), + rgb(216, 180, 254), + rgb(129, 140, 248) + ); + --vp-home-hero-image-filter: brightness(0.8) saturate(1.2); */ + --vp-home-hero-name-color: rgb(249, 168, 212); + --vp-c-brand-1: rgb(249, 168, 212); + --lysand-gradient: linear-gradient( + to right, + rgb(249, 168, 212), + rgb(216, 180, 254), + rgb(129, 140, 248) + ); + --vp-color-primary: rgb(249, 168, 212); + --vp-color-secondary: rgb(216, 180, 254); + --vp-button-brand-bg: transparent; + --vp-c-bg-soft: rgb(250, 250, 250); +} + +.dark { + --vp-c-bg: rgb(24, 24, 24); + --vp-c-bg-soft: rgb(32, 32, 32); +} + +.VPFeature { + border-radius: 0.3rem !important; + transition: all 0.2s ease-in-out !important; +} + +.VPFeature:hover { + transform: scale(1.02); + border-color: var(--vp-color-primary); +} + +.VPButton.medium { + border-radius: 0.3rem !important; + transition: all 0.2s ease-in-out !important; +} + +.VPButton.medium:hover { + transform: scale(1.02); +} + +.VPButton.brand { + background: var(--lysand-gradient); + border: none !important; +} + +@media (min-width: 960px) { + .image-container { + width: 50% !important; + margin-right: 0.5rem !important; + } +} diff --git a/.vitepress/theme/index.ts b/.vitepress/theme/index.ts new file mode 100644 index 0000000..c495bc1 --- /dev/null +++ b/.vitepress/theme/index.ts @@ -0,0 +1,4 @@ +import DefaultTheme from "vitepress/theme"; +import "./custom.css"; + +export default DefaultTheme; diff --git a/bun.lockb b/bun.lockb index e9a9c04..76e1389 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/components/Features.vue b/components/Features.vue new file mode 100644 index 0000000..4f67e79 --- /dev/null +++ b/components/Features.vue @@ -0,0 +1,78 @@ + + + \ No newline at end of file diff --git a/components/Team.vue b/components/Team.vue new file mode 100644 index 0000000..da995aa --- /dev/null +++ b/components/Team.vue @@ -0,0 +1,92 @@ + + + \ No newline at end of file diff --git a/docs/extensions/interactivity.md b/docs/extensions/interactivity.md new file mode 100644 index 0000000..2a8cf1b --- /dev/null +++ b/docs/extensions/interactivity.md @@ -0,0 +1,10 @@ +# Interactivity + +> [!WARNING] +> This extension is a work in progress and is not to be used in any production system. The specification is subject to change. + +On platforms like Discord, users can interact with messages with custom fields like buttons or dropdowns. This extension allows you to define these fields in your messages. + +![Discord Buttons in action](/assets/discord-buttons.webp) + +... \ No newline at end of file diff --git a/docs/extensions/vanity.md b/docs/extensions/vanity.md index a195005..3b20094 100644 --- a/docs/extensions/vanity.md +++ b/docs/extensions/vanity.md @@ -48,7 +48,13 @@ Here is an example object: }, "birthday": "1998-04-12", "location": "+40.6894-074.0447/", - "activitypub": "@erikuden@mastodon.de" + "activitypub": [ + "@erikuden@mastodon.de" + ], + "aliases": [ + "https://burger.social/accounts/349ee237-c672-41c1-aadc-677e185f795a", + "https://social.lysand.org/users/f565ef02-035d-4974-ba5e-f62a8558331d" + ] } } } @@ -131,12 +137,20 @@ Clients might choose to display a map of the user's location. | Name | Type | Required | | :--------- | :----- | :------- | -| activitypub | String | No | +| activitypub | Array of String | No | -The user's ActivityPub profile. This should be a string in the format `@username@domain`. +The user's ActivityPub profile. This should be an array of strings in the format `@username@domain`. Servers are expected to use standard WebFinger resolution to fetch the user's ActivityPub profile if needed. +### Aliases + +| Name | Type | Required | +| :------ | :----- | :------- | +| aliases | Array of String | No | + +Aliases to the user's profile on other Lysand-compatible servers. This should be an array of URIs resolving to the user's Lysand object. + ## Types ```typescript @@ -150,7 +164,8 @@ interface VanityExtension { }; birthday?: string; location?: string; - activitypub?: string; + activitypub?: string[]; + aliases?: string[]; } ``` diff --git a/docs/groups.md b/docs/groups.md index f02c892..55c1c76 100644 --- a/docs/groups.md +++ b/docs/groups.md @@ -5,7 +5,7 @@ Groups are a way to organize the visibility of objects on the server. Groups can > [!NOTE] > Groups replace the old "visibility" system for Notes, which was designed for a microblogging context. Groups are more flexible and can be used for any application. > -> Notes can still use visibility in cases where groups are not needed with the `followers` and `public` group URIs. +> Notes can still use visibility in cases where groups are not needed with the `followers` and `public` values where you'd typically put a group URI (for example, in a [Publication](./objects/publications.md)'s `group` field'). # Group Entity diff --git a/docs/index.md b/docs/index.md index 8c96233..ef819a6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -16,32 +16,13 @@ hero: - theme: alt text: Lysand Server link: https://github.com/lysand-org/lysand - -features: - - title: JSON-based APIs - details: Simple JSON objects are used to represent all data - - title: Built-in namespaced extensions - details: Extensions for common use cases are built-in, such as custom emojis and reactions - - title: Easy to implement - details: The protocol is simple to implement, and can be used with any language - - title: Secure by default - details: All requests are signed with the latest cryptographic algorithms - - title: No vendor-specific implementations - details: Everything is heavily standardized to ensure compatibility - - title: TypeScript types - details: TypeScript types are provided for every object in the protocol --- ---- + -> [!INFO] -> The latest version of Lysand is **3.0**, released on **(beta site)** by [**CPlusPatch**](https://cpluspatch.com). -> -> Lysand 3.0 features **stricter security** and **more modularizarion**. + - \ No newline at end of file + \ No newline at end of file diff --git a/docs/objects/publications.md b/docs/objects/publications.md index 7e2242c..36b3f20 100644 --- a/docs/objects/publications.md +++ b/docs/objects/publications.md @@ -12,13 +12,28 @@ Here is an example publication: "created_at": "2021-01-01T00:00:00.000Z", "content": { "text/plain": { - "content": "Hello, world!" + "content": "Hello, world! I own this website: https://google.com" }, "text/html": { - "content": "Hello, world!" + "content": "Hello, world! I own this website! https://google.com" } }, - "visibility": "public", + "category": "microblog", + "device": { + "name": "Megalodon for Android", + "version": "1.3.89", + "url": "https://sk22.github.io/megalodon" + }, + "previews": [ + { + "link": "https://google.com", + "title": "Google", + "description": "The world's most popular search engine", + "image": "https://cdn.example.com/previews/6e0204a2-746c-4972-8602-c4f37fc63bbe.png", + "icon": "https://google.com/favicon.ico" + } + ], + "group": "public", "attachments": [ { "image/png": { @@ -85,9 +100,55 @@ An example value for the `content` field would be: > > Lysand also recommends that servers always include a `text/plain` version of each object, as it is the most basic content type that is supported by all clients, such as command line clients. +> [!WARNING] +> Servers should not trust the `text/html` content type, as it could contain malicious code. Servers should always sanitize the content before displaying it to the user. +> +> Additionally, frontends should warn users before clicking on links that do not match the link text, such as `https://google.com` + It is up to the client to choose which content format to display to the user. The client may choose to display the first content format that it supports, or it may choose to display the content format that it thinks is the most appropriate. -Lysand recommends that clients display the richest content format that they support, such as HTML or more exotic formats such as MFM. +Clients should display the richest content format that they support, such as HTML or more exotic formats such as MFM. + +### Category + +| Name | Type | Required | +| :------- | :----------- | :------- | +| category | CategoryType | No | + +Category of the publication. Used for clients to possibly display notes in different ways, for example a note with the `microblog` category could be displayed in a timeline, while a note with the `forum` category could be displayed Reddit-style. + +See [the Types section](#types) for more information on the `CategoryType` enum. + +### Device + +| Name | Type | Required | +| :----- | :----- | :------- | +| device | Device | No | + +Device that the publication was created on. If it is not provided, it is assumed that the publication was created on a generic device. + +Servers should avoid collecting any information that could be used to identify the user, such as IP addresses or user agents. A simple name is recommended. + +### Previews + +| Name | Type | Required | +| :------- | :------------------- | :------- | +| previews | Array of LinkPreview | No | + +Previews for links in the publication. Optional. This is to avoid the [stampeding mastodon problem](https://github.com/mastodon/mastodon/issues/23662) where a link preview is fetched by every server that sees the publication, creating an accidental DDOS attack. + +> [!WARNING] +> Servers should make sure not to trust the previews, as they could be faked by remote servers. This is not a very good attack vector, but it is still possible to redirect users to malicious links. + +### Group + +| Name | Type | Required | +| :---- | :----- | :------- | +| group | String | No | + +URI of a [Group](../groups.md), or `public` or `followers`. + +Refer to the [Groups](../groups.md) page for more information on groups, their implementation and what to do if this value is not provided. ### Attachments @@ -216,6 +277,10 @@ interface Publication extends Entity { type: "Note" | "Patch"; author: string; content?: ContentFormat; + category?: CategoryType; + device?: Device; + previews?: LinkPreview[]; + group?: string | "public" | "followers"; attachments?: ContentFormat[]; replies_to?: string; quotes?: string; @@ -246,4 +311,34 @@ enum Visibility { Followers = "followers", Direct = "direct" } +``` + +```typescript +interface LinkPreview { + link: string; + title: string; + description?: string; + image?: string; + icon?: string; +} +``` + +```typescript +interface Device { + name: string; + version?: string; + url?: string; +} +``` + +```typescript +/* + * microblog -> Twitter, Mastodon-style + * forum -> Reddit-style + * blog -> Wordpress, WriteFreely-style + * image -> Instagram-style + * video -> YouTube-style + * audio -> SoundCloud, Spotify-style + */ +type CategoryType = "microblog" | "forum" | "blog" | "image" | "video" | "audio" ``` \ No newline at end of file diff --git a/docs/public/assets/discord-buttons.webp b/docs/public/assets/discord-buttons.webp new file mode 100644 index 0000000..593b25a Binary files /dev/null and b/docs/public/assets/discord-buttons.webp differ diff --git a/package.json b/package.json index 952c10e..3ea6396 100644 --- a/package.json +++ b/package.json @@ -8,5 +8,10 @@ "@biomejs/biome": "^1.7.1", "vitepress": "^1.1.0" }, - "trustedDependencies": ["@biomejs/biome"] + "trustedDependencies": ["@biomejs/biome"], + "dependencies": { + "@tailwindcss/vite": "^4.0.0-alpha.14", + "iconify-icon": "^2.1.0", + "tailwindcss": "^4.0.0-alpha.14" + } }