From 5f20eab3f1d6be88ae2642d9d24a45456a87cd4f Mon Sep 17 00:00:00 2001 From: Thomas Sileo Date: Thu, 1 Sep 2022 20:42:20 +0200 Subject: [PATCH] More work towards support moving/deleting instance --- Makefile | 4 +++ app/activitypub.py | 4 +++ app/config.py | 2 ++ app/main.py | 1 + app/webfinger.py | 6 +++- docs/user_guide.md | 81 ++++++++++++++++++++++++++++++++++++++++++++++ tasks.py | 29 +++++++++++++++++ 7 files changed, 126 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d5e5b6c..de85ec5 100644 --- a/Makefile +++ b/Makefile @@ -17,3 +17,7 @@ update: .PHONY: prune-old-data prune-old-data: -docker run --volume `pwd`/data:/app/data --volume `pwd`/app/static:/app/app/static microblogpub/microblogpub inv prune-old-data + +.PHONY: webfinger +webfinger: + -docker run --volume `pwd`/data:/app/data --volume `pwd`/app/static:/app/app/static microblogpub/microblogpub inv webfinger $(account) diff --git a/app/activitypub.py b/app/activitypub.py index eb72b2f..6f174fd 100644 --- a/app/activitypub.py +++ b/app/activitypub.py @@ -9,6 +9,7 @@ from loguru import logger from markdown import markdown from app import config +from app.config import ALSO_KNOWN_AS from app.config import AP_CONTENT_TYPE # noqa: F401 from app.httpsig import auth from app.key import get_pubkey_as_pem @@ -126,6 +127,9 @@ ME = { "tag": _LOCAL_ACTOR_TAGS, } +if ALSO_KNOWN_AS: + ME["alsoKnownAs"] = [ALSO_KNOWN_AS] + class NotAnObjectError(Exception): def __init__(self, url: str, resp: httpx.Response | None = None) -> None: diff --git a/app/config.py b/app/config.py index 4c1fe1f..c5f80e6 100644 --- a/app/config.py +++ b/app/config.py @@ -87,6 +87,7 @@ class Config(pydantic.BaseModel): blocked_servers: list[_BlockedServer] = [] custom_footer: str | None = None emoji: str | None = None + also_known_as: str | None = None inbox_retention_days: int = 15 @@ -135,6 +136,7 @@ if CONFIG.privacy_replace: PRIVACY_REPLACE = {pr.domain: pr.replace_by for pr in CONFIG.privacy_replace} BLOCKED_SERVERS = {blocked_server.hostname for blocked_server in CONFIG.blocked_servers} +ALSO_KNOWN_AS = CONFIG.also_known_as INBOX_RETENTION_DAYS = CONFIG.inbox_retention_days CUSTOM_FOOTER = ( diff --git a/app/main.py b/app/main.py index fe4f9ec..ea357ab 100644 --- a/app/main.py +++ b/app/main.py @@ -251,6 +251,7 @@ async def index( page: int | None = None, ) -> templates.TemplateResponse | ActivityPubResponse: if is_activitypub_requested(request): + return ActivityPubResponse(LOCAL_ACTOR.ap_actor) page = page or 1 diff --git a/app/webfinger.py b/app/webfinger.py index 8daf9d0..2858069 100644 --- a/app/webfinger.py +++ b/app/webfinger.py @@ -29,6 +29,7 @@ async def webfinger( is_404 = False + resp: httpx.Response | None = None async with httpx.AsyncClient() as client: for i, proto in enumerate(protos): try: @@ -59,7 +60,10 @@ async def webfinger( if is_404: return None - return resp.json() + if resp: + return resp.json() + else: + return None async def get_remote_follow_template(resource: str) -> str | None: diff --git a/docs/user_guide.md b/docs/user_guide.md index a0b3028..1b300bc 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -235,6 +235,42 @@ All the data generated by the server is located in the `data/` directory: Restoring is as easy as adding your backed up `data/` directory into a fresh deployment. +## Moving from another instance + +If you want to move followers from your existing account, ensure it is supported in your software documentation. + +For [Mastodon you can look at Moving or leaving accounts](https://docs.joinmastodon.org/user/moving/). + +First you need to grab the "ActivityPub actor URL" for your existing account: + +### Python edition + +```bash +# For a Python install +poetry run inv webfinger username@domain.tld +``` + +Edit the config. + +### Docker edition + +```bash +# For a Docker install +make account=username@domain.tld webfinger +``` + +Edit the config. + +#### Edit the config + +And add a reference to your old/existing account in `profile.toml`: + +```toml +also_known_as = "my@old-account.com" +``` + +Restart the server, and you should be able to complete the move from your existing account. + ## Tasks ### Pruning old data @@ -280,3 +316,48 @@ make prune-old-data docker compose up -d rm data/microblogpub.db.bak ``` + +### Moving to another instance + +**This section is just a draft.** + +If you want to migrate to another instance, you have the ability to move your existing followers to your new account. + +Your new account should reference the existing one, refer to your software configuration (for example [Moving or leaving accounts from the Mastodon doc](https://docs.joinmastodon.org/user/moving/)). + +Execute the Move task: + +#### Python edition + +```bash +# For a Python install +poetry run inv move username@domain.tld +``` + +#### Docker edition + +```bash +# For a Docker install +make account=username@domain.tld move +``` + +### Deleting the instance + +**This section is just a draft.** + +You want to delete your instance, you can request other instances to delete your remote profile. +Once deleted, you won't be able to use your instance anymore. + +#### Python edition + +```bash +# For a Python install +poetry run inv self-destruct +``` + +#### Docker edition + +```bash +# For a Docker install +make self-destruct +``` diff --git a/tasks.py b/tasks.py index a2bd6f4..8f6f209 100644 --- a/tasks.py +++ b/tasks.py @@ -190,6 +190,35 @@ def prune_old_data(ctx): asyncio.run(run_prune_old_data()) +@task +def webfinger(ctx, account): + # type: (Context, str) -> None + import traceback + + from loguru import logger + + from app.source import _MENTION_REGEX + from app.webfinger import get_actor_url + + logger.disable("app") + if not account.startswith("@"): + account = f"@{account}" + if not _MENTION_REGEX.match(account): + print(f"Invalid acccount {account}") + return + + print(f"Resolving {account}") + try: + maybe_actor_url = asyncio.run(get_actor_url(account)) + if maybe_actor_url: + print(f"SUCCESS: {maybe_actor_url}") + else: + print(f"ERROR: Failed to resolve {account}") + except Exception as exc: + print(f"ERROR: Failed to resolve {account}") + print("".join(traceback.format_exception(exc))) + + @task def yunohost_config( ctx,