diff --git a/libforget/misskey.py b/libforget/misskey.py index 7a156df..e8440b7 100644 --- a/libforget/misskey.py +++ b/libforget/misskey.py @@ -1,5 +1,5 @@ from app import db, sentry -from model import MisskeyApp, MisskeyInstance, Account, OAuthToken +from model import MisskeyApp, MisskeyInstance, Account, OAuthToken, Post from uuid import uuid4 from hashlib import sha256 from libforget.exceptions import TemporaryError, PermanentError @@ -61,16 +61,10 @@ def receive_token(token, app): session = make_session() if app.miauth: - r = session.get('{}://{}/api/miauth/{}/check'.format(app.protocol, app.instance, token)) + r = session.post('{}://{}/api/miauth/{}/check'.format(app.protocol, app.instance, token)) r.raise_for_status() token = r.json()['token'] - - acc = account_from_user(r.json()['user']) - acc = db.session.merge(acc) - token = OAuthToken(token = r.json()['token']) - token = db.session.merge(token) - token.account = acc else: r = session.post('{}://{}/api/auth/session/userkey'.format(app.protocol, app.instance), json = { 'appSecret': app.client_secret, @@ -80,7 +74,7 @@ def receive_token(token, app): token = sha256(r.json()['accessToken'].encode('utf-8') + app.client_secret.encode('utf-8')).hexdigest() - acc = account_from_user(r.json()['user']) + acc = account_from_user(r.json()['user'], app.instance) acc = db.session.merge(acc) token = OAuthToken(token = token) token = db.session.merge(token) @@ -89,52 +83,43 @@ def receive_token(token, app): return token def check_auth(account, app, session): - if app.miauth: - r = session.get('{}://{}/api/miauth/{}/check'.format(app.protocol, app.instance, account.token)) + # there is no explicit check, we can only try getting user info + r = session.post('{}://{}/api/i'.format(app.protocol, app.instance), json = {'i': account.tokens[0].token}) - if r.status_code != 200: - raise TemporaryError("{} {}".format(r.status_code, r.body)) + if r.status_code != 200: + raise TemporaryError("{} {}".format(r.status_code, r.text)) - if not r.json()['ok']: - if sentry: - sentry.captureMessage( - 'Misskey auth revoked or incorrect', - extra=locals()) - db.session.delete(token) - db.session.commit() - raise PermanentError("Misskey auth revoked") - else: - # there is no such check for legacy auth, instead we check if we can - # get the user info - r = session.post('{}://{}/api/i'.format(app.protocol, app.instance), json = {'i': account.token}) + if r.json()['isSuspended']: + # this is technically a temporary error, but like for twitter + # its handled as permanent to not make useless API calls + raise PermanentError("Misskey account suspended") - if r.status_code != 200: - raise TemporaryError("{} {}".format(r.status_code, r.body)) - - if r.json()['isSuspended']: - # this is technically a temporary error, but like for twitter - # its handled as permanent to not make useless API calls - raise PermanentError("Misskey account suspended") - -def account_from_user(user): +def account_from_user(user, host): return Account( - misskey_instance=user['host'], + # in objects that get returned from misskey, the local host is + # set to None + misskey_instance=host, misskey_id=user['id'], - screen_name='{}@{}'.format(user['username'], user['host']), - display_name=obj['name'], - avatar_url=obj['avatarUrl'], - reported_post_count=obj['notesCount'], + screen_name='{}@{}'.format(user['username'], host), + display_name=user['name'], + avatar_url=user['avatarUrl'], + # the notes count is not always included, especially not when + # fetching posts. in that case assume its not needed + reported_post_count=user.get('notesCount', None), ) -def post_from_api_object(obj): +def post_from_api_object(obj, host): return Post( - misskey_instance=user['host'], - misskey_id=user['id'], - favourite=obj['myReaction'] is not None, + # in objects that get returned from misskey, the local host is + # set to None + misskey_instance=host, + misskey_id=obj['id'], + favourite=('myReaction' in obj + and bool(obj['myReaction'])), has_media=('fileIds' in obj and bool(obj['fileIds'])), created_at=obj['createdAt'], - author_id=account_from_user(obj['user']).id, + author_id=account_from_user(obj['user'], host).id, direct=obj['visibility'] == 'specified', is_reblog=obj['renoteId'] is not None, ) @@ -143,22 +128,24 @@ def fetch_posts(acc, max_id, since_id): app = MisskeyApp.query.get(acc.misskey_instance) session = make_session() check_auth(acc, app, session) - if not verify_credentials(acc, app): - raise PermanentError() - try: - kwargs = dict(limit=40) - if max_id: - kwargs['untilId'] = max_id - if since_id: - kwargs['sinceId'] = since_id - notes = session.post('{}://{}/api/users/notes'.format(app.protocol, app.misskey_instance), json=kwargs) - notes.raise_for_status() + kwargs = dict( + limit=40, + userId=acc.misskey_id, + # for some reason the token is needed so misskey also sends `myReaction` + i=acc.tokens[0].token + ) + if max_id: + kwargs['untilId'] = max_id + if since_id: + kwargs['sinceId'] = since_id - return [post_from_api_object(status) for note in notes.json()] + notes = session.post('{}://{}/api/users/notes'.format(app.protocol, app.instance), json=kwargs) - except Exception as e: - raise TemporaryError(e) + if notes.status_code != 200: + raise TemporaryError('{} {}'.format(notes.status_code, notes.text)) + + return [post_from_api_object(note, app.instance) for note in notes.json()] def refresh_posts(posts): @@ -171,7 +158,8 @@ def refresh_posts(posts): with db.session.no_autoflush: for post in posts: print('Refreshing {}'.format(post)) - r = session.post('{}://{}/api/notes/show'.format(app.protocol, app.misskey_instance), json={ + r = session.post('{}://{}/api/notes/show'.format(app.protocol, app.instance), json={ + 'i': acc.tokens[0].token, 'noteId': post.misskey_id }) if r.status_code != 200: @@ -181,14 +169,15 @@ def refresh_posts(posts): continue except Exception as e: raise TemporaryError(e) - raise TemporaryError('{} {}'.format(r.status_code, r.body)) + raise TemporaryError('{} {}'.format(r.status_code, r.text)) - new_post = db.session.merge(post_from_api_object(r.json())) + new_post = db.session.merge(post_from_api_object(r.json(), app.instance)) new_post.touch() new_posts.append(new_post) return new_posts def delete(post): + acc = post.author app = MisskeyApp.query.get(post.misskey_instance) session = make_session() if not app: @@ -196,12 +185,13 @@ def delete(post): # so use a permanent error raise PermanentError("instance not registered for delete") - r = session.post('{}://{}/api/notes/delete'.format(app.protocol, app.misskey_instance), json = { + r = session.post('{}://{}/api/notes/delete'.format(app.protocol, app.instance), json = { + 'i': acc.tokens[0].token, 'noteId': post.misskey_id }) if r.status_code != 204: - raise TemporaryError("{} {}".format(r.status_code, r.body)) + raise TemporaryError("{} {}".format(r.status_code, r.text)) db.session.delete(post) diff --git a/routes/__init__.py b/routes/__init__.py index 32a8dc2..dd23f56 100644 --- a/routes/__init__.py +++ b/routes/__init__.py @@ -7,7 +7,7 @@ import libforget.misskey from libforget.auth import require_auth, csrf,\ get_viewer from libforget.session import make_session -from model import Session, TwitterArchive, MastodonApp +from model import Session, TwitterArchive, MastodonApp, MisskeyApp from app import app, db, sentry, imgproxy import tasks from zipfile import BadZipFile @@ -264,7 +264,7 @@ def misskey_login(instance=None): session = make_session() app = libforget.misskey.get_or_create_app( instance_url, - callback_legacy, + callback, url_for('index', _external=True), session) db.session.merge(app) diff --git a/tasks.py b/tasks.py index d26a757..125ecc1 100644 --- a/tasks.py +++ b/tasks.py @@ -2,7 +2,7 @@ from celery import Celery, Task from app import app as flaskapp from app import db from model import Session, Account, TwitterArchive, Post, OAuthToken,\ - MastodonInstance + MastodonInstance, MisskeyInstance import libforget.twitter import libforget.mastodon import libforget.misskey @@ -492,7 +492,7 @@ def update_misskey_instances_popularity(): instance = MisskeyInstance.query.get(acct.misskey_instance) if not instance: instance = MisskeyInstance( - instance=acct.Misskey_instance, popularity=10) + instance=acct.misskey_instance, popularity=10) db.session.add(instance) amount = 0.01 if acct.policy_enabled: