#!/usr/bin/python3 import json import requests # Change these configs TOKEN = "misskey-api-token" INSTANCE = "https://your-instance.com" def post(path, body): """Sends a post request to the Misskey instance.""" return requests.post( f"{INSTANCE}/api{path}", headers={ "Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json", }, data=json.dumps(body), timeout=10, ) def fetch_notes(user_id, until_id=None): """Fetches all notes from a user.""" if until_id: notes = post( "/users/notes", { "userId": user_id, "withFiles": False, "withReplies": True, "withChannelNotes": True, "limit": 100, "untilId": until_id }, ) else: notes = post( "/users/notes", { "userId": user_id, "withFiles": False, "withReplies": True, "withChannelNotes": True, "limit": 100 }, ) return notes.json() def fetch_users(target_instance, until_id=None): """Gets all users for a given Misskey instance.""" if until_id: users = post( "/federation/users", {"limit": 100, "host": target_instance, "untilId": until_id}, ) else: users = post("/federation/users", {"limit": 100, "host": target_instance}) return users.json() def destroy(target_instance): """Destroys all accounts on the given Misskey instance.""" users = fetch_users(target_instance) while users: for user in users: destroy_notes(user['id']) r1 = post("/admin/delete-account", {"userId": user['id']}) r2 = post("/admin/delete-all-files-of-a-user", {"userId": user['id']}) if r1.status_code == 204 and r2.status_code == 204: print(f"Deleted @{user['username']}@{user['host']}") else: print(f"Failed to delete @{user['username']}@{user['host']}!!!!!") users = fetch_users(target_instance, users[-1]['id']) def destroy_notes(user_id): """Destroys all accounts on the given Misskey instance.""" notes = fetch_notes(user_id) while notes: for note in notes: r = post("/notes/delete", {"noteId": note['id']}) if r.status_code == 204: print(f"Deleted {print_name(note)}: {print_note(note)}") else: print(f"Could not delete {print_name(note)}: {print_note(note)}") notes = fetch_notes(user_id, notes[-1]['id']) def print_note(note): if note.get('renote') and note['renote'].get('reactions'): return "Reaction" elif note.get('renote'): return f"Renote {print_note(note['renote'])}" elif note.get('files') or note.get('fileIds'): return "File" elif note.get('reactions'): return "Reaction" else: if note['text'] is None: print(note) return truncate_text(note['text']) def print_name(note): return f"@{note['user']['username']}@{note['user']['host']}" def truncate_text(text): if text is None: return "None" else: return text[:75].replace("\n", " ") destroy("instance-to-destroy.com")