A self-hosted, single-user, ActivityPub powered microblog.
Branch: amd64
Clone or download
Pull request Compare This branch is 70 commits ahead of tsileo:master.
Latest commit ab87158 Feb 15, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
config Initial import May 18, 2018
data Add persistency to RabbitMQ via Docker May 21, 2018
sass fix older-link position Jan 30, 2019
static fix bleeding shadow Feb 2, 2019
templates make 500 look nicer Feb 15, 2019
tests Lower the delay in the federation tests Jul 29, 2018
utils fix url_for Jan 29, 2019
.dockerignore Tests tests tests and bugfixes May 28, 2018
.env Tweak docker-compose to allow starting multiple instances May 21, 2018
.gitignore progressive web app Jan 29, 2019
.isort.cfg Formatting Jul 20, 2018
.travis.yml Fix CI Sep 1, 2018
Dockerfile use quay.io/bashell/alpine-python:3 for amd64 branch Feb 12, 2019
LICENSE Initial import May 18, 2018
Makefile docker image for deploy on arm64 Jan 29, 2019
README.md Document the new pin/unpin API endpoint Jul 22, 2018
activitypub.py replace print() with app.logger.debug Jan 29, 2019
admin.py fix url_for Jan 29, 2019
api.py serve uploaded file via CDN if available Jan 29, 2019
app.py make 500 look nicer Feb 15, 2019
config.py get similarity threshold from config Jan 30, 2019
dev-requirements.txt Switch to Little boxes, fixes tsileo#1 (tsileo#8) Jun 18, 2018
docker-compose-dev.yml Improve caching Sep 3, 2018
docker-compose-tests.yml Bugfixes Jul 29, 2018
docker-compose.yml User API cleanup Jun 1, 2018
feeds.py feeds separation Jan 29, 2019
filters.py do not translate if cached detected lang in NO_TRANSLATE Jan 30, 2019
indieauth.py enable IndieAuth Jan 29, 2019
migrations.py migrations separation Jan 29, 2019
requirements.txt use updated langdetect Jan 30, 2019
run.sh change gunicorn log level to info Jan 29, 2019
setup.cfg Initial import May 18, 2018
tasks.py Bugfix cache invalidation Sep 5, 2018

README.md

microblog.pub

microblog.pub

Build Status #microblog.pub on Matrix License

A self-hosted, single-user, ActivityPub powered microblog.

Still in early development.

Features

  • Implements a basic ActivityPub server (with federation)
    • Compatible with Mastodon and others (Pleroma, Hubzilla...)
    • Also implements a remote follow compatible with Mastodon instances
  • Exposes your outbox as a basic microblog
  • Implements IndieAuth endpoints (authorization and token endpoint)
    • U2F support
    • You can use your ActivityPub identity to login to other websites/app
  • Comes with an admin UI with notifications and the stream of people you follow
  • Allows you to attach files to your notes
    • Privacy-aware image upload endpoint that strip EXIF meta data before storing the file
  • No JavaScript, that's it. Even the admin UI is pure HTML/CSS
  • Easy to customize (the theme is written Sass)
    • mobile-friendly theme
    • with dark and light version
  • Microformats aware (exports h-feed, h-entry, h-cards, ...)
  • Exports RSS/Atom/JSON feeds
    • You stream/timeline is also available in an (authenticated) JSON feed
  • Comes with a tiny HTTP API to help posting new content and and read your inbox/notifications
  • Easy to "cache" (the external/public-facing microblog part)
    • With a good setup, cached content can be served most of the time
    • You can setup a "purge" hook to let you invalidate cache when the microblog was updated
  • Deployable with Docker (Docker compose for everything: dev, test and deployment)
  • Focused on testing

ActivityPub

microblog.pub implements an ActivityPub server, it implements both the client to server API and the federated server to server API.

Activities are verified using HTTP Signatures or by fetching the content on the remote server directly.

Running your instance

Installation

$ git clone https://github.com/tsileo/microblog.pub
$ cd microblog.pub
$ pip install -r requirements.txt
$ make css
$ cp -r config/me.sample.yml config/me.yml

Configuration

$ make password
Password: <enter a password; nothing will show on screen>
$2b$12$iW497g...

Edit config/me.yml to add the above-generated password, like so:

username: 'username'
name: 'Your Name'
icon_url: 'https://you-avatar-url'
domain: 'your-domain.tld'
summary: 'your summary'
https: true
pass: $2b$12$iW497g...

Deployment

Note: some of the docker yml files use version 3 of docker-compose.

$ docker-compose up -d

Development

The most convenient way to hack on microblog.pub is to run the server locally, and run

# One-time setup
$ pip install -r requirements.txt
# Start the Celery worker, RabbitMQ and MongoDB
$ docker-compose -f docker-compose-dev.yml up -d
# Run the server locally
$ FLASK_DEBUG=1 MICROBLOGPUB_DEBUG=1 FLASK_APP=app.py flask run -p 5005 --with-threads

API

Your admin API key can be found at config/admin_api_key.key.

ActivityPub API

GET /

Returns the actor profile, with links to all the "standard" collections.

GET /tags/:tag

Special collection that reference notes with the given tag.

GET /stream

Special collection that returns the stream/inbox as displayed in the UI.

User API

The user API is used by the admin UI (and requires a CSRF token when used with a regular user session), but it can also be accessed with an API key.

All the examples are using HTTPie.

POST /api/note/delete{?id}

Deletes the given note id (the note must from the instance outbox).

Answers a 201 (Created) status code.

You can pass the id via JSON, form data or query argument.

Example

$ http POST https://microblog.pub/api/note/delete Authorization:'Bearer <token>' id=http://microblob.pub/outbox/<note_id>/activity

Response

{
    "activity": "https://microblog.pub/outbox/<delete_id>"
}

POST /api/note/pin{?id}

Adds the given note id (the note must from the instance outbox) to the featured collection (and pins it on the homepage).

Answers a 201 (Created) status code.

You can pass the id via JSON, form data or query argument.

Example

$ http POST https://microblog.pub/api/note/pin Authorization:'Bearer <token>' id=http://microblob.pub/outbox/<note_id>/activity

Response

{
    "pinned": true
}

POST /api/note/unpin{?id}

Removes the given note id (the note must from the instance outbox) from the featured collection (and un-pins it).

Answers a 201 (Created) status code.

You can pass the id via JSON, form data or query argument.

Example

$ http POST https://microblog.pub/api/note/unpin Authorization:'Bearer <token>' id=http://microblob.pub/outbox/<note_id>/activity

Response

{
    "pinned": false
}

POST /api/like{?id}

Likes the given activity.

Answers a 201 (Created) status code.

You can pass the id via JSON, form data or query argument.

Example

$ http POST https://microblog.pub/api/like Authorization:'Bearer <token>' id=http://activity-iri.tld

Response

{
    "activity": "https://microblog.pub/outbox/<like_id>"
}

POST /api/boost{?id}

Boosts/Announces the given activity.

Answers a 201 (Created) status code.

You can pass the id via JSON, form data or query argument.

Example

$ http POST https://microblog.pub/api/boost Authorization:'Bearer <token>' id=http://activity-iri.tld

Response

{
    "activity": "https://microblog.pub/outbox/<announce_id>"
}

POST /api/block{?actor}

Blocks the given actor, all activities from this actor will be dropped after that.

Answers a 201 (Created) status code.

You can pass the id via JSON, form data or query argument.

Example

$ http POST https://microblog.pub/api/block Authorization:'Bearer <token>' actor=http://actor-iri.tld/

Response

{
    "activity": "https://microblog.pub/outbox/<block_id>"
}

POST /api/follow{?actor}

Follows the given actor.

Answers a 201 (Created) status code.

You can pass the id via JSON, form data or query argument.

Example

$ http POST https://microblog.pub/api/follow Authorization:'Bearer <token>' actor=http://actor-iri.tld/

Response

{
    "activity": "https://microblog.pub/outbox/<follow_id>"
}

POST /api/new_note{?content,reply}

Creates a new note. reply is the IRI of the "replied" note if any.

Answers a 201 (Created) status code.

You can pass the content and reply via JSON, form data or query argument.

Example

$ http POST https://microblog.pub/api/new_note Authorization:'Bearer <token>' content=hello

Response

{
    "activity": "https://microblog.pub/outbox/<create_id>"
}

GET /api/stream

Example

$ http GET https://microblog.pub/api/stream Authorization:'Bearer <token>'

Response

Contributions

PRs are welcome, please open an issue to start a discussion before your start any work.