initial commit
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
env/
 | 
			
		||||
							
								
								
									
										1
									
								
								.tool-versions
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.tool-versions
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
python 3.11.5
 | 
			
		||||
							
								
								
									
										119
									
								
								misskey_scripting.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								misskey_scripting.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
#!/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")
 | 
			
		||||
							
								
								
									
										1
									
								
								requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								requirements.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
Requests
 | 
			
		||||
		Reference in New Issue
	
	Block a user