Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/dimkr/tootik
A federated nanoblogging service with a Gemini frontend.
https://github.com/dimkr/tootik
activitypub activitypub-server fediverse finger finger-protocol gemini gemini-protocol gemini-server go golang gopher gopher-protocol social social-media social-network sqlite
Last synced: about 2 months ago
JSON representation
A federated nanoblogging service with a Gemini frontend.
- Host: GitHub
- URL: https://github.com/dimkr/tootik
- Owner: dimkr
- License: apache-2.0
- Created: 2023-03-19T14:01:48.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-04-13T10:37:32.000Z (5 months ago)
- Last Synced: 2024-04-13T23:54:25.883Z (5 months ago)
- Topics: activitypub, activitypub-server, fediverse, finger, finger-protocol, gemini, gemini-protocol, gemini-server, go, golang, gopher, gopher-protocol, social, social-media, social-network, sqlite
- Language: Go
- Homepage: gemini://hd.206267.xyz
- Size: 733 KB
- Stars: 59
- Watchers: 3
- Forks: 2
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- my-awesome-github-stars - dimkr/tootik - A federated nanoblogging service with a Gemini frontend. (Go)
README
```
.. . .. ..
... . .... ...
... . . . . ... .. . . . . ... ...
.. . . .. . . .. . .. .. . .
., . . . . .. . .. . .
. . . .. .. .... . . . . .. ..
. .. ... . . . . . .. . .
. . . .. . .. ...' .. . . . . .
. . . . . __ . .__ _ __ ,; .'. . . ....
. . . / /____ ___ /./_(_) /__ .' .. . . . .
.. ... . . . /.__/ _ \/ _ \/ __/./ '_/. . .. . . .
.' ... . \__/\___/\___/\__/_/_/\_\ . . . .
. . . . . . ... ... . . ..
.. .. . . .... .. . . .. . . . . . ... ....' .
... . . . .. . ... ... . .. .. .,.. .....
. .. ...... . .''. . .. . . . ...
' . .. .. .. . . ... ......::. .. .,. . .. .... ..
. .... . ..... . .. . . ... . .,'. . .. ,.. ..
. . . . . .. . . .. . . .. .. . . . . . . .'
. .... '... ... . . .. . ... . '. ' ...# localhost.localdomain:8443
Welcome, fedinaut! localhost.localdomain:8443 is an instance of tootik, a federated nanoblogging service.
ββββ
π» My feed
π Mentions
β‘οΈ Followed users
π My profile
π‘ Local feed
ποΈ Communities
π₯ Hashtags
π View profile
π Search posts
π£ New post
βοΈ Settings
π Status
π Help
```[![Latest release](https://img.shields.io/github/v/release/dimkr/tootik)](https://github.com/dimkr/tootik/releases) [![Build status](https://github.com/dimkr/tootik/actions/workflows/ci.yml/badge.svg)](https://github.com/dimkr/tootik/actions) [![Go Reference](https://pkg.go.dev/badge/github.com/dimkr/tootik.svg)](https://pkg.go.dev/github.com/dimkr/tootik)
## Overview
tootik is a federated, text-based social network. A tootik user can interact with others on the same instance, users on other tootik instances, [Mastodon](https://joinmastodon.org/) users, [Lemmy](https://join-lemmy.org/) users and users of other [ActivityPub](https://www.w3.org/TR/activitypub/)-compatible servers. Unlike other social networks, tootik doesn't have a browser-based interface or an app: instead, its minimalistic, text-based interface is served over [Gemini](https://geminiprotocol.net/):
```
Gemini ActivityPub (HTTPS)
β β
βββββββββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββββββββββ
β Bob's Gemini client β£ββββ« tootik instance β ββ¬ββ€ Another tootik instance β
β£ββββββββββββββββββββββββ« β£ββββββββββββββββββ« β βββββββββββββββββββββββββββ
β2024-01-01 alice β β$ ./tootik ... β β ββββββββββββββββββ
β> Hi @bob and @carol! β βββ³ββββββββββββββββ βββ€ Something else β
β... β β β ββββββββββββββββββ
βββββββββββββββββββββββββ β β βββββββββββββββββββββ
βββββββββββββββββ»ββββββββ βββ€ Mastodon instance βββ
β Alice's Gemini client β βββββββββββββββββββββ β
β£ββββββββββββββββββββββββ« ββββββββββββββββββββ΄βββββ
β2024-01-01 bob β β Carol's web browser β
β> Hi @alice! β βββββββββββββββββββββββββ€
β... β ββββ alice β
βββββββββββββββββββββββββ ββββ 17h agoβ
βHi @bob and @carol! β
β β
β βββ bob β
β βββ 16h agoβ
β Hi @alice! β
βββββββββββββββββββββββββ€
βββββββββββββββββββββββββ
ββ Hola ββPublishββ
βββββββββββββββββββββββββ
βββββββββββββββββββββββββ
```This makes tootik lightweight, private and accessible:
* Its UI supports [Gemini](https://geminiprotocol.net/), Gopher, Finger and [Guppy](https://github.com/dimkr/guppy-protocol): there's a wide variety of clients to choose from and some work great on old devices.
* Rich content is reduced to plain text and links: it's a fast, low-bandwidth UI suitable for screen readers.
* Anonymity: you authenticate using a TLS client certificate and don't have to share your email address or real name.
* No promoted content, tracking or analytics: social networking, with the slow and non-commercial vibe of the small internet.
* It's a single static executable, making it easy to [set up your own instance](SETUP.md) instead of joining an existing one.
* All instance data is stored in a single file, a [sqlite](https://sqlite.org/) database that is easy to backup and restore.
* It's lightweight: a <=$5/mo VPS or a SBC is more than enough for a small instance.
* It implements the subset of ActivityPub required for its feature set but not more, to stay small, reliable and maintainable.
* It's written in two languages ([Go](https://go.dev/) and SQL), making the codebase suitable for educational purposes and easy to hack on.
* It's permissively-licensed.## Features
* [Good compatibility with various fediverse servers](FEDERATION.md)
* Text posts, with 3 privacy levels
* Public
* To followers
* To mentioned users
* Sharing of public posts
* Users can follow each other to see non-public posts
* With support for [Mastodon's follower synchronization mechanism](https://docs.joinmastodon.org/spec/activitypub/#follower-synchronization-mechanism), aka [FEP-8fcf](https://codeberg.org/fediverse/fep/src/branch/main/fep/8fcf/fep-8fcf.md)
* Multi-choice polls
* [Lemmy](https://join-lemmy.org/)-style communities
* Follow to join
* Mention community in a public post to start thread
* Community sends posts and replies to all members
* Full-text search within posts
* Upload of posts and user avatars, over [Titan](gemini://transjovian.org/titan)
* Account migration, in both directions## Using tootik
You can join an [existing instance](gemini://hd.206267.xyz) or [set up your own](SETUP.md).
## Building
go generate ./migrations
Then:
go build ./cmd/tootik -tags fts5
or, to build a static executable:
go build -tags netgo,sqlite_omit_load_extension,fts5 -ldflags "-linkmode external -extldflags -static" ./cmd/tootik
## Architecture
```
βββββββββ ββββββββββ βββββββββββ βββββββββββ
β notes β β shares β β persons β β follows β
β£ββββββββ« β£βββββββββ« β£ββββββββββ« β£ββββββββββ«
βobject β βnote β βactor β βfollower β
βauthor β βby β β... β βfollowed β
β... β β... β β β β... β
βββββββββ ββββββββββ βββββββββββ βββββββββββ
```Most user-visible data is stored in 4 tables in tootik's database:
1. `notes`, which contains [Object](https://pkg.go.dev/github.com/dimkr/tootik/ap#Object) objects that represent posts
2. `shares`, which records "user A shared post B" relationships
3. `persons`, which contains [Actor](https://pkg.go.dev/github.com/dimkr/tootik/ap#Actor) objects that represent users
4. `follows`, which records "user A follows user B" relationships`notes.author`, `shares.by`, `follows.follower` and `follows.followed` point to a row in `persons`.
`shares.note` points to a row in `notes`.
```
βββββββββ ββββββββββ βββββββββββ βββββββββββ βββββββββββ βββββββββββ
β notes β β shares β β persons β β follows β β outbox β β inbox β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€ β£ββββββββββ« β£ββββββββββ«
βobject β βnote β βactor β βfollower β βactivity β βactivity β
βauthor β βby β β... β βfollowed β βsender β βsender β
β... β β... β β β β... β β... β β... β
βββββββββ ββββββββββ βββββββββββ βββββββββββ βββββββββββ βββββββββββ
```Federation happens through two tables, `inbox` and `outbox`. Both contain [Activity](https://pkg.go.dev/github.com/dimkr/tootik/ap#Activity) objects that represent actions performed by the users in `persons`.
`inbox` contains activities by users on other servers, while `outbox` contains activities of local users.
```
βββββββββββββββββββ
β gemini.Listener β
ββββββββββ³βββββββββ
ββββββββββ»βββββββββ
β front.Handler β
βββββββ³ββββββββββββ
βββββββββ ββββββββββ ββββββΈβββββ βββββββββββ βββββββββββ βββββββββββ
β notes β β shares β β persons β β follows β β outbox β β inbox β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€
βobject β βnote β βactor β βfollower β βactivity β βactivity β
βauthor β βby β β... β βfollowed β βsender β βsender β
β... β β... β β β β... β β... β β... β
βββββββββ ββββββββββ ββββββ°βββββ βββββββββββ βββββββββββ βββββββββββ
βββββββββ»βββββββ
β fed.Resolver β
ββββββββββββββββ
```[gemini.Listener](https://pkg.go.dev/github.com/dimkr/tootik/front/gemini#Listener) is a Gemini server that handles requests through [Handler](https://pkg.go.dev/github.com/dimkr/tootik/front#Handler). It adds rows to `persons` during new user registration and changes rows when users change properties like their display name.
[Resolver](https://pkg.go.dev/github.com/dimkr/tootik/fed#Resolver) is responsible for fetching [Actor](https://pkg.go.dev/github.com/dimkr/tootik/ap#Actor)s that represents users of other servers. The fetched objects are cached in `persons`.
```
βββββββββββββββββββ
β gemini.Listener β
ββββββββββ¬βββββββββ
ββββββββββ΄ββββββββββ
βββββββββββββ₯ front.Handler β
β ββ°βββββββββ¬ββββββββ°β
βββββΈββββ ββββββββΈββ ββββββ΄βββββ ββΈβββββββββ βββββββββββ βββββββββββ
β notes β β shares β β persons β β follows β β outbox β β inbox β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€
βobject β βnote β βactor β βfollower β βactivity β βactivity β
βauthor β βby β β... β βfollowed β βsender β βsender β
β... β β... β β β β... β β... β β... β
βββββββββ ββββββββββ ββββββ¬βββββ βββββββββββ βββββββββββ βββββββββββ
βββββββββ΄βββββββ
β fed.Resolver β
ββββββββββββββββ
```In addition, Gemini requests can:
* Add rows to `notes` (new post)
* Change rows in `notes` (post editing)
* Add rows to `shares` (user shares a post)
* Remove rows from `shares` (user no longer shares a post)
* Add rows to `follows` (user A followed user B)
* Remove rows from `follows` (user A unfollowed user B)
* ...```
βββββββββββββββββββ
β gemini.Listener β
ββββββββββ¬βββββββββ
ββββββββββ΄ββββββββββ
βββββββββββββ€ front.Handler βββββββββββββ
β ββ¬βββββββββ¬ββββββββ¬β β
βββββ΄ββββ ββββββββ΄ββ ββββββ΄βββββ ββ΄βββββββββ βββΈββββββββ βββββββββββ
β notes β β shares β β persons β β follows β β outbox β β inbox β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€
βobject β βnote β βactor β βfollower β βactivity β βactivity β
βauthor β βby β β... β βfollowed β βsender β βsender β
β... β β... β β β β... β β... β β... β
βββββββββ ββββββββββ ββββββ¬βββββ βββββββββ°ββ ββ°βββββββββ βββββββββββ
βββββββββ΄βββββββ ββ»βββββ»ββββββ
β fed.Resolver β β fed.Queue β
ββββββββββββββββ βββββββββββββ
```Each user action (post creation, post deletion, ...) is recorded as an [Activity](https://pkg.go.dev/github.com/dimkr/tootik/ap#Activity) object written to `outbox`.
[fed.Queue](https://pkg.go.dev/github.com/dimkr/tootik/fed#Queue) is responsible for sending activities to followers from other servers, if needed.
```
βββββββββββββββββ
βββββββββββββββββββ β outbox.Mover β
β gemini.Listener β β outbox.Poller β
ββββββββββ¬βββββββββ β fed.Syncer β
ββββββββββ΄ββββββββββ βββββ³ββββββ³ββββββ
βββββββββββββ€ front.Handler ββββββββββββββ
β ββ¬βββββββββ¬ββββββββ¬β β ββ
βββββ΄ββββ ββββββββ΄ββ ββββββ΄βββββ ββ΄ββββββββΈβ βββ΄βΈβββββββ βββββββββββ
β notes β β shares β β persons β β follows β β outbox β β inbox β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€
βobject β βnote β βactor β βfollower β βactivity β βactivity β
βauthor β βby β β... β βfollowed β βsender β βsender β
β... β β... β β β β... β β... β β... β
βββββββββ ββββββββββ ββββββ¬βββββ βββββββββ¬ββ ββ¬βββββββββ βββββββββββ
βββββββββ΄βββββββ ββ΄βββββ΄ββββββ
β fed.Resolver β β fed.Queue β
ββββββββββββββββ βββββββββββββ
```tootik may perform automatic actions in the name of the user:
1. Follow the new account and unfollow the old one, if a followed user moved their account
2. Update poll results for polls published by the user, and send the new results to followers
3. Handle disagreement between `follows` rows for this user and what other servers know```
βββββββββββββββββ
βββββββββββββββββββ β outbox.Mover β
β gemini.Listener β β outbox.Poller β
ββββββββββ¬βββββββββ β fed.Syncer β
ββββββββββ΄ββββββββββ βββββ¬ββββββ¬ββββββ ββββββββββββββββ
βββββββββββββ€ front.Handler ββββββββΌββββββ ββββ« fed.Listener β£βββ
β ββ¬βββββββββ¬ββββββββ¬β β ββ β βββββββ³βββββββββ β
βββββ΄ββββ ββββββββ΄ββ ββββββ΄βββββ ββ΄ββββββββ΄β βββ΄β΄βββββΈββ ββββββΈβββββ β
β notes β β shares β β persons β β follows β β outbox β β inbox β β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ β
βobject β βnote β βactor β βfollower β βactivity β βactivity β β
βauthor β βby β β... β βfollowed β βsender β βsender β β
β... β β... β β β β... β β... β β... β β
βββββββββ ββββββββββ ββββββ¬βββββ βββββββββ¬ββ ββ¬βββββββββ βββββββββββ β
βββββββββ΄βββββββ ββ΄βββββ΄ββββββ β
β fed.Resolver β β fed.Queue β β
βββββββββ°βββββββ βββββββββββββ β
β β
β β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββ
```Requests from other servers are handled by [fed.Listener](https://pkg.go.dev/github.com/dimkr/tootik/fed#Listener), a HTTP server.
It extracts the signature and key ID from a request using [httpsig.Extract](https://pkg.go.dev/github.com/dimkr/tootik/httpsig#Extract), uses [Resolver](https://pkg.go.dev/github.com/dimkr/tootik/fed#Resolver) to fetch the public key if needed, validates the request using [Verify](https://pkg.go.dev/github.com/dimkr/tootik/httpsig#Signature.Verify) and inserts the received [Activity](https://pkg.go.dev/github.com/dimkr/tootik/ap#Activity) object into `inbox`.
In addition, [fed.Listener](https://pkg.go.dev/github.com/dimkr/tootik/fed#Listener) allows other servers to fetch public activity (like public posts) from `outbox`, so they can fetch some past activity by a newly-followed user.
```
βββββββββββββββββ
βββββββββββββββββββ β outbox.Mover β
β gemini.Listener β β outbox.Poller β
ββββββββββ¬βββββββββ β fed.Syncer β
ββββββββββ΄ββββββββββ βββββ¬ββββββ¬ββββββ ββββββββββββββββ
βββββββββββββ€ front.Handler ββββββββΌββββββ ββββ€ fed.Listener ββββ
β ββ¬βββββββββ¬ββββββββ¬β β ββ β βββββββ¬βββββββββ β
βββββ΄ββββ ββββββββ΄ββ ββββββ΄βββββ ββ΄ββββββββ΄β βββ΄β΄βββββ΄ββ ββββββ΄βββββ β
β notes β β shares β β persons β β follows β β outbox β β inbox β β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ β
βobject β βnote β βactor β βfollower β βactivity β βactivity β β
βauthor β βby β β... β βfollowed β βsender β βsender β β
β... β β... β β β β... β β... β β... β β
βββββ°ββββ βββββ°βββββ ββββββ¬βββββ ββββββ°βββ¬ββ ββ¬βββββββββ ββββββββ°βββ β
β β βββββββββ΄βββββββ β ββ΄βββββ΄ββββββ βββββββ»ββββββββ β
β β β fed.Resolver β β β fed.Queue β β inbox.Queue β β
β β βββββββββ¬βββββββ β βββββββββββββ βββ³ββ³ββ³ββββββββ β
β β β βββββββββββββββββββββββ β β β
β βββββββββββββΏββββββββββββββββββββββββββββββββββββ β β
βββββββββββββββββββββββΏββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββ
```Once inserted into `inbox`, [inbox.Queue](https://pkg.go.dev/github.com/dimkr/tootik/inbox#Queue) processes the received activities:
* Adds new posts received in `Create` activities to `notes`
* Edits post in `notes` according to `Update` activities
* Records `Announce` activities in `shares`
* Marks a follower-followed relationship in `follows` as accepted, when the followed user sends an `Accept` activity
* Adds a new row to `follows` when a remote user sends a `Follow` activity to a local user
* ...```
βββββββββββββββββ
βββββββββββββββββββ β outbox.Mover β
β gemini.Listener β β outbox.Poller β
ββββββββββ¬βββββββββ β fed.Syncer β
ββββββββββ΄ββββββββββ βββββ¬ββββββ¬ββββββ ββββββββββββββββ
βββββββββββββ€ front.Handler ββββββββΌββββββ ββββ€ fed.Listener ββββ
β ββ¬βββββββββ¬ββββββββ¬β β ββ β βββββββ¬βββββββββ β
βββββ΄ββββ ββββββββ΄ββ ββββββ΄βββββ ββ΄ββββββββ΄β βββ΄β΄βββββ΄ββ ββββββ΄βββββ β
β notes β β shares β β persons β β follows β β outbox β β inbox β β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ β
βobject β βnote β βactor β βfollower β βactivity β βactivity β β
βauthor β βby β β... β βfollowed β βsender β βsender β β
β... β β... β β β β... β β... β β... β β
βββββ¬ββββ βββββ¬βββββ ββββββ¬βββββ ββββββ¬βββ¬ββ ββ¬ββββββββ°β ββββββββ¬βββ β
β β βββββββββ΄βββββββ β ββ΄βββββ΄ββββββ β βββββββ΄ββββββββ β
β β β fed.Resolver β β β fed.Queue β βββββ₯ inbox.Queue β β
β β βββββββββ¬βββββββ β βββββββββββββ βββ¬ββ¬ββ¬ββββββββ β
β β β βββββββββββββββββββββββ β β β
β βββββββββββββΌββββββββββββββββββββββββββββββββββββ β β
βββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββ
```Sometimes, a received or newly created local [Activity](https://pkg.go.dev/github.com/dimkr/tootik/ap#Activity) is forwarded to the followers of a local user:
* When a remote user replies in a thread started by a local user, the received [Activity](https://pkg.go.dev/github.com/dimkr/tootik/ap#Activity) is inserted into `outbox` and forwarded to all followers of the local user.
* When a user creates a new post, edits a post or deletes a post in a local community, the [Activity](https://pkg.go.dev/github.com/dimkr/tootik/ap#Activity) is inserted into `outbox` and forwarded to all community members.```
βββββββββββββββββ
βββββββββββββββββββ β outbox.Mover β
β gemini.Listener β β outbox.Poller β
ββββββββββ¬βββββββββ β fed.Syncer β
ββββββββββ΄ββββββββββ βββββ¬ββββββ¬ββββββ ββββββββββββββββ
βββββββββββββ€ front.Handler ββββββββΌββββββ ββββ€ fed.Listener ββββ
β ββ¬βββββββββ¬ββββββββ¬β β ββ β βββββββ¬βββββββββ β
βββββ΄ββββ ββββββββ΄ββ ββββββ΄βββββ ββ΄ββββββββ΄β βββ΄β΄βββββ΄ββ ββββββ΄βββββ β
β notes β β shares β β persons β β follows β β outbox β β inbox β β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ β
βobject β βnote β βactor β βfollower β βactivity β βactivity β β
βauthor β βby β β... β βfollowed β βsender β βsender β β
β... β β... β β β β... β β... β β... β β
βββββ¬ββββ βββββ¬βββββ ββββββ¬βββββ ββββββ¬βββ¬ββ ββ¬ββββββββ¬β ββββββββ¬βββ β
β β βββββββββ΄βββββββ β ββ΄βββββ΄ββββββ β βββββββ΄ββββββββ β
β β β fed.Resolver β β β fed.Queue β βββββ€ inbox.Queue β β
β β βββββββββ¬ββ°βββββ β βββββββββββββ βββ¬ββ¬ββ¬ββ°ββββββ β
β β β β βββββββββββββββββββββββ β β β β
β βββββββββββββΌββββββββββββββββββββββββββββββββββββ β β β
βββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββ β β
βββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββ
```To display details like the user's name and speed up the verification of future incoming replies, [inbox.Queue](https://pkg.go.dev/github.com/dimkr/tootik/inbox#Queue) uses [Resolver](https://pkg.go.dev/github.com/dimkr/tootik/fed#Resolver) to fetch the [Actor](https://pkg.go.dev/github.com/dimkr/tootik/ap#Actor) objects of mentioned users (if needed).
## More Documentation
* [Setup guide](SETUP.md)
* [Frontend](front/README.md)
* [Migrations](migrations/README.md)
* [Compatibility](FEDERATION.md)## Credits and Legal Information
tootik is free and unencumbered software released under the terms of the [Apache License Version 2.0](https://www.apache.org/licenses/LICENSE-2.0); see LICENSE for the license text.
The ASCII art logo at the top was made using [FIGlet](http://www.figlet.org/).