[WIP] Continue migration

This commit is contained in:
Thomas Sileo 2018-06-16 22:33:51 +02:00
parent d9362adb25
commit 4e669620bc
3 changed files with 46 additions and 8 deletions

View file

@ -20,6 +20,8 @@ from config import USERNAME
from little_boxes import activitypub as ap from little_boxes import activitypub as ap
from little_boxes.backend import Backend from little_boxes.backend import Backend
from little_boxes.collection import parse_collection as ap_parse_collection from little_boxes.collection import parse_collection as ap_parse_collection
from little_boxes.errors import Error
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -41,6 +43,15 @@ def _to_list(data: Union[List[Any], Any]) -> List[Any]:
return [data] return [data]
def ensure_it_is_me(f):
"""Method decorator used to track the events fired during tests."""
def wrapper(*args, **kwargs):
if args[1].id != MY_PERSON.id:
raise Error('unexpected actor')
return f(*args, **kwargs)
return wrapper
class MicroblogPubBackend(Backend): class MicroblogPubBackend(Backend):
def user_agent(self) -> str: def user_agent(self) -> str:
return USER_AGENT return USER_AGENT
@ -51,6 +62,7 @@ class MicroblogPubBackend(Backend):
def activity_url(self, obj_id): def activity_url(self, obj_id):
return f"{BASE_URL}/outbox/{obj_id}" return f"{BASE_URL}/outbox/{obj_id}"
@ensure_it_is_me
def outbox_new(self, as_actor: ap.Person, activity: ap.BaseActivity) -> None: def outbox_new(self, as_actor: ap.Person, activity: ap.BaseActivity) -> None:
DB.outbox.insert_one( DB.outbox.insert_one(
{ {
@ -61,6 +73,7 @@ class MicroblogPubBackend(Backend):
} }
) )
@ensure_it_is_me
def outbox_is_blocked(self, as_actor: ap.Person, actor_id: str) -> bool: def outbox_is_blocked(self, as_actor: ap.Person, actor_id: str) -> bool:
return bool( return bool(
DB.outbox.find_one( DB.outbox.find_one(
@ -73,11 +86,14 @@ class MicroblogPubBackend(Backend):
) )
def fetch_iri(self, iri: str) -> ap.ObjectType: def fetch_iri(self, iri: str) -> ap.ObjectType:
pass # FIXME(tsileo): implements caching
return super().fetch_iri(iri)
@ensure_it_is_me
def inbox_check_duplicate(self, as_actor: ap.Person, iri: str) -> bool: def inbox_check_duplicate(self, as_actor: ap.Person, iri: str) -> bool:
return bool(DB.inbox.find_one({"remote_id": iri})) return bool(DB.inbox.find_one({"remote_id": iri}))
@ensure_it_is_me
def inbox_new(self, as_actor: ap.Person, activity: ap.BaseActivity) -> None: def inbox_new(self, as_actor: ap.Person, activity: ap.BaseActivity) -> None:
DB.inbox.insert_one( DB.inbox.insert_one(
{ {
@ -88,28 +104,34 @@ class MicroblogPubBackend(Backend):
} }
) )
@ensure_it_is_me
def post_to_remote_inbox(self, as_actor: ap.Person, payload: str, to: str) -> None: def post_to_remote_inbox(self, as_actor: ap.Person, payload: str, to: str) -> None:
tasks.post_to_inbox.delay(payload, to) tasks.post_to_inbox.delay(payload, to)
@ensure_it_is_me
def new_follower(self, as_actor: ap.Person, follow: ap.Follow) -> None: def new_follower(self, as_actor: ap.Person, follow: ap.Follow) -> None:
remote_actor = follow.get_actor().id remote_actor = follow.get_actor().id
if DB.followers.find({"remote_actor": remote_actor}).count() == 0: if DB.followers.find({"remote_actor": remote_actor}).count() == 0:
DB.followers.insert_one({"remote_actor": remote_actor}) DB.followers.insert_one({"remote_actor": remote_actor})
@ensure_it_is_me
def undo_new_follower(self, as_actor: ap.Person, follow: ap.Follow) -> None: def undo_new_follower(self, as_actor: ap.Person, follow: ap.Follow) -> None:
# TODO(tsileo): update the follow to set undo # TODO(tsileo): update the follow to set undo
DB.followers.delete_one({"remote_actor": follow.get_actor().id}) DB.followers.delete_one({"remote_actor": follow.get_actor().id})
@ensure_it_is_me
def undo_new_following(self, as_actor: ap.Person, follow: ap.Follow) -> None: def undo_new_following(self, as_actor: ap.Person, follow: ap.Follow) -> None:
# TODO(tsileo): update the follow to set undo # TODO(tsileo): update the follow to set undo
DB.following.delete_one({"remote_actor": follow.get_object().id}) DB.following.delete_one({"remote_actor": follow.get_object().id})
@ensure_it_is_me
def new_following(self, as_actor: ap.Person, follow: ap.Follow) -> None: def new_following(self, as_actor: ap.Person, follow: ap.Follow) -> None:
remote_actor = follow.get_actor().id remote_actor = follow.get_actor().id
if DB.following.find({"remote_actor": remote_actor}).count() == 0: if DB.following.find({"remote_actor": remote_actor}).count() == 0:
DB.following.insert_one({"remote_actor": remote_actor}) DB.following.insert_one({"remote_actor": remote_actor})
@ensure_it_is_me
def inbox_like(self, as_actor: ap.Person, like: ap.Like) -> None: def inbox_like(self, as_actor: ap.Person, like: ap.Like) -> None:
obj = like.get_object() obj = like.get_object()
# Update the meta counter if the object is published by the server # Update the meta counter if the object is published by the server
@ -117,6 +139,7 @@ class MicroblogPubBackend(Backend):
{"activity.object.id": obj.id}, {"$inc": {"meta.count_like": 1}} {"activity.object.id": obj.id}, {"$inc": {"meta.count_like": 1}}
) )
@ensure_it_is_me
def inbox_undo_like(self, as_actor: ap.Person, like: ap.Like) -> None: def inbox_undo_like(self, as_actor: ap.Person, like: ap.Like) -> None:
obj = like.get_object() obj = like.get_object()
# Update the meta counter if the object is published by the server # Update the meta counter if the object is published by the server
@ -124,6 +147,7 @@ class MicroblogPubBackend(Backend):
{"activity.object.id": obj.id}, {"$inc": {"meta.count_like": -1}} {"activity.object.id": obj.id}, {"$inc": {"meta.count_like": -1}}
) )
@ensure_it_is_me
def outobx_like(self, as_actor: ap.Person, like: ap.Like) -> None: def outobx_like(self, as_actor: ap.Person, like: ap.Like) -> None:
obj = like.get_object() obj = like.get_object()
# Unlikely, but an actor can like it's own post # Unlikely, but an actor can like it's own post
@ -136,6 +160,7 @@ class MicroblogPubBackend(Backend):
{"activity.object.id": obj.id}, {"$set": {"meta.liked": like.id}} {"activity.object.id": obj.id}, {"$set": {"meta.liked": like.id}}
) )
@ensure_it_is_me
def outbox_undo_like(self, as_actor: ap.Person, like: ap.Like) -> None: def outbox_undo_like(self, as_actor: ap.Person, like: ap.Like) -> None:
obj = like.get_object() obj = like.get_object()
# Unlikely, but an actor can like it's own post # Unlikely, but an actor can like it's own post
@ -147,6 +172,7 @@ class MicroblogPubBackend(Backend):
{"activity.object.id": obj.id}, {"$set": {"meta.liked": False}} {"activity.object.id": obj.id}, {"$set": {"meta.liked": False}}
) )
@ensure_it_is_me
def inbox_announce(self, as_actor: ap.Person, announce: ap.Announce) -> None: def inbox_announce(self, as_actor: ap.Person, announce: ap.Announce) -> None:
if isinstance(announce._data["object"], str) and not announce._data[ if isinstance(announce._data["object"], str) and not announce._data[
"object" "object"
@ -166,6 +192,7 @@ class MicroblogPubBackend(Backend):
{"activity.object.id": obj_iri}, {"$inc": {"meta.count_boost": 1}} {"activity.object.id": obj_iri}, {"$inc": {"meta.count_boost": 1}}
) )
@ensure_it_is_me
def inbox_undo_announce(self, as_actor: ap.Person, announce: ap.Announce) -> None: def inbox_undo_announce(self, as_actor: ap.Person, announce: ap.Announce) -> None:
obj = announce.get_object() obj = announce.get_object()
# Update the meta counter if the object is published by the server # Update the meta counter if the object is published by the server
@ -173,18 +200,21 @@ class MicroblogPubBackend(Backend):
{"activity.object.id": obj.id}, {"$inc": {"meta.count_boost": -1}} {"activity.object.id": obj.id}, {"$inc": {"meta.count_boost": -1}}
) )
@ensure_it_is_me
def outbox_announce(self, as_actor: ap.Person, announce: ap.Announce) -> None: def outbox_announce(self, as_actor: ap.Person, announce: ap.Announce) -> None:
obj = announce.get_object() obj = announce.get_object()
DB.inbox.update_one( DB.inbox.update_one(
{"activity.object.id": obj.id}, {"$set": {"meta.boosted": announce.id}} {"activity.object.id": obj.id}, {"$set": {"meta.boosted": announce.id}}
) )
@ensure_it_is_me
def outbox_undo_announce(self, as_actor: ap.Person, announce: ap.Announce) -> None: def outbox_undo_announce(self, as_actor: ap.Person, announce: ap.Announce) -> None:
obj = announce.get_object() obj = announce.get_object()
DB.inbox.update_one( DB.inbox.update_one(
{"activity.object.id": obj.id}, {"$set": {"meta.boosted": False}} {"activity.object.id": obj.id}, {"$set": {"meta.boosted": False}}
) )
@ensure_it_is_me
def inbox_delete(self, as_actor: ap.Person, delete: ap.Delete) -> None: def inbox_delete(self, as_actor: ap.Person, delete: ap.Delete) -> None:
DB.inbox.update_one( DB.inbox.update_one(
{"activity.object.id": delete.get_object().id}, {"activity.object.id": delete.get_object().id},
@ -197,12 +227,14 @@ class MicroblogPubBackend(Backend):
# TODO(tsileo): also purge the cache if it's a reply of a published activity # TODO(tsileo): also purge the cache if it's a reply of a published activity
@ensure_it_is_me
def outbox_delete(self, as_actor: ap.Person, delete: ap.Delete) -> None: def outbox_delete(self, as_actor: ap.Person, delete: ap.Delete) -> None:
DB.outbox.update_one( DB.outbox.update_one(
{"activity.object.id": delete.get_object().id}, {"activity.object.id": delete.get_object().id},
{"$set": {"meta.deleted": True}}, {"$set": {"meta.deleted": True}},
) )
@ensure_it_is_me
def inbox_update(self, as_actor: ap.Person, update: ap.Update) -> None: def inbox_update(self, as_actor: ap.Person, update: ap.Update) -> None:
obj = update.get_object() obj = update.get_object()
if obj.ACTIVITY_TYPE == ap.ActivityType.NOTE: if obj.ACTIVITY_TYPE == ap.ActivityType.NOTE:
@ -214,6 +246,7 @@ class MicroblogPubBackend(Backend):
# FIXME(tsileo): handle update actor amd inbox_update_note/inbox_update_actor # FIXME(tsileo): handle update actor amd inbox_update_note/inbox_update_actor
@ensure_it_is_me
def outbox_update(self, as_actor: ap.Person, update: ap.Update) -> None: def outbox_update(self, as_actor: ap.Person, update: ap.Update) -> None:
obj = update._data["object"] obj = update._data["object"]

10
app.py
View file

@ -38,6 +38,7 @@ from werkzeug.utils import secure_filename
import activitypub import activitypub
import config import config
from activitypub import embed_collection from activitypub import embed_collection
from activitypub import MY_PERSON
from config import ACTOR_SERVICE from config import ACTOR_SERVICE
from config import ADMIN_API_KEY from config import ADMIN_API_KEY
from config import BASE_URL from config import BASE_URL
@ -55,6 +56,7 @@ from config import USERNAME
from config import VERSION from config import VERSION
from config import _drop_db from config import _drop_db
from config import custom_cache_purge_hook from config import custom_cache_purge_hook
from little_boxes import activitypub as ap
from little_boxes.activitypub import ActivityType from little_boxes.activitypub import ActivityType
from little_boxes.activitypub import clean_activity from little_boxes.activitypub import clean_activity
from little_boxes.errors import BadActivityError from little_boxes.errors import BadActivityError
@ -88,6 +90,8 @@ else:
SIG_AUTH = HTTPSigAuth(KEY) SIG_AUTH = HTTPSigAuth(KEY)
OUTBOX = ap.Outbox(MY_PERSON)
def verify_pass(pwd): def verify_pass(pwd):
return bcrypt.verify(pwd, PASS) return bcrypt.verify(pwd, PASS)
@ -377,8 +381,9 @@ def authorize_follow():
if DB.following.find({"remote_actor": actor}).count() > 0: if DB.following.find({"remote_actor": actor}).count() > 0:
return redirect("/following") return redirect("/following")
follow = activitypub.Follow(object=actor) follow = activitypub.Follow(actor=MY_PERSON, object=actor)
follow.post_to_outbox() OUTBOX.post(follow)
return redirect("/following") return redirect("/following")
@ -400,6 +405,7 @@ def u2f_register():
####### #######
# Activity pub routes # Activity pub routes
# FIXME(tsileo); continue here
@app.route("/") @app.route("/")

View file

@ -9,18 +9,17 @@ from requests.exceptions import HTTPError
from config import DB from config import DB
from config import HEADERS from config import HEADERS
from config import ID
from config import KEY from config import KEY
from config import USER_AGENT from config import USER_AGENT
from utils.httpsig import HTTPSigAuth from little_boxes.httpsig import HTTPSigAuth
from utils.linked_data_sig import generate_signature from little_boxes.linked_data_sig import generate_signature
from utils.opengraph import fetch_og_metadata from utils.opengraph import fetch_og_metadata
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
app = Celery( app = Celery(
"tasks", broker=os.getenv("MICROBLOGPUB_AMQP_BROKER", "pyamqp://guest@localhost//") "tasks", broker=os.getenv("MICROBLOGPUB_AMQP_BROKER", "pyamqp://guest@localhost//")
) )
SigAuth = HTTPSigAuth(ID + "#main-key", KEY.privkey) SigAuth = HTTPSigAuth(KEY)
@app.task(bind=True, max_retries=12) @app.task(bind=True, max_retries=12)
@ -29,7 +28,7 @@ def post_to_inbox(self, payload: str, to: str) -> None:
log.info("payload=%s", payload) log.info("payload=%s", payload)
log.info("generating sig") log.info("generating sig")
signed_payload = json.loads(payload) signed_payload = json.loads(payload)
generate_signature(signed_payload, KEY.privkey) generate_signature(signed_payload, KEY)
log.info("to=%s", to) log.info("to=%s", to)
resp = requests.post( resp = requests.post(
to, to,