Exemple #1
0
    def _post_to_outbox(self, obj_id: str, activity: ObjectType, recipients: List[str]) -> None:
        if isinstance(self._data['object'], str):
            # Put the object in the cache
            OBJECT_SERVICE.get(
                self._data['object'],
                reload_cache=True,
                part_of_stream=True,
                announce_published=self._data['published'],
            )

        obj = self.get_object()
        DB.inbox.update_one({'activity.object.id': obj.id}, {'$set': {'meta.boosted': obj_id}})
Exemple #2
0
def _user_api_get_note(from_outbox: bool = False):
    oid = _user_api_arg('id')
    note = activitypub.parse_activity(OBJECT_SERVICE.get(oid),
                                      expected=ActivityType.NOTE)
    if from_outbox and not note.id.startswith(ID):
        raise NotFromOutboxError(
            f'cannot delete {note.id}, id must be owned by the server')

    return note
Exemple #3
0
def new():
    reply_id = None
    content = ''
    if request.args.get('reply'):
        reply = activitypub.parse_activity(
            OBJECT_SERVICE.get(request.args.get('reply')))
        reply_id = reply.id
        actor = reply.get_actor()
        domain = urlparse(actor.id).netloc
        content = f'@{actor.preferredUsername}@{domain} '

    return render_template('new.html', reply=reply_id, content=content)
Exemple #4
0
def index():
    print(request.headers.get('Accept'))
    if is_api_request():
        return jsonify(**ME)

    # FIXME(tsileo): implements pagination, also for the followers/following page
    limit = 50
    q = {
        'type': 'Create',
        'activity.object.type': 'Note',
        'meta.deleted': False,
    }
    c = request.args.get('cursor')
    if c:
        q['_id'] = {'$lt': ObjectId(c)}

    outbox_data = list(
        DB.outbox.find({
            '$or': [q, {
                'type': 'Announce',
                'meta.undo': False
            }]
        },
                       limit=limit).sort('_id', -1))
    cursor = None
    if outbox_data and len(outbox_data) == limit:
        cursor = str(outbox_data[-1]['_id'])

    for data in outbox_data:
        if data['type'] == 'Announce':
            print(data)
            if data['activity']['object'].startswith('http'):
                data['ref'] = {
                    'activity': {
                        'object':
                        OBJECT_SERVICE.get(data['activity']['object'])
                    },
                    'meta': {}
                }

    return render_template(
        'index.html',
        me=ME,
        notes=DB.inbox.find({
            'type': 'Create',
            'activity.object.type': 'Note',
            'meta.deleted': False
        }).count(),
        followers=DB.followers.count(),
        following=DB.following.count(),
        outbox_data=outbox_data,
        cursor=cursor,
    )
Exemple #5
0
    def get_object(self) -> 'BaseActivity':
        if self.__obj:
            return self.__obj
        if isinstance(self._data['object'], dict):
            p = parse_activity(self._data['object'])
        else:
            if self.ACTIVITY_TYPE == ActivityType.FOLLOW:
                p = Person(**ACTOR_SERVICE.get(self._data['object']))
            else:
                obj = OBJECT_SERVICE.get(self._data['object'])
                if ActivityType(obj.get('type')) not in self.ALLOWED_OBJECT_TYPES:
                    raise UnexpectedActivityTypeError(f'invalid object type {obj.get("type")}')

                p = parse_activity(obj)

        self.__obj: BaseActivity = p
        return p
Exemple #6
0
def inbox():
    if request.method == 'GET':
        if not is_api_request():
            abort(404)
        try:
            _api_required()
        except BadSignature:
            abort(404)

        return jsonify(**activitypub.build_ordered_collection(
            DB.inbox,
            q={'meta.deleted': False},
            cursor=request.args.get('cursor'),
            map_func=lambda doc: doc['activity'],
        ))

    data = request.get_json(force=True)
    logger.debug(f'req_headers={request.headers}')
    logger.debug(f'raw_data={data}')
    try:
        if not verify_request(ACTOR_SERVICE):
            raise Exception('failed to verify request')
    except Exception:
        logger.exception(
            'failed to verify request, trying to verify the payload by fetching the remote'
        )
        try:
            data = OBJECT_SERVICE.get(data['id'])
        except Exception:
            logger.exception(f'failed to fetch remote id at {data["id"]}')
            return Response(
                status=422,
                headers={'Content-Type': 'application/json'},
                response=json.dumps({
                    'error':
                    'failed to verify request (using HTTP signatures or fetching the IRI)'
                }),
            )

    activity = activitypub.parse_activity(data)
    logger.debug(f'inbox activity={activity}/{data}')
    activity.process_from_inbox()

    return Response(status=201, )
Exemple #7
0
    def _process_from_inbox(self) -> None:
        if isinstance(self._data['object'], str) and not self._data['object'].startswith('http'):
            # TODO(tsileo): actually drop it without storing it and better logging, also move the check somewhere else
            logger.warn(
                f'received an Annouce referencing an OStatus notice ({self._data["object"]}), dropping the message'
            )
            return
        # Save/cache the object, and make it part of the stream so we can fetch it
        if isinstance(self._data['object'], str):
            raw_obj = OBJECT_SERVICE.get(
                self._data['object'],
                reload_cache=True,
                part_of_stream=True,
                announce_published=self._data['published'],
            )
            obj = parse_activity(raw_obj)
        else:
            obj = self.get_object()

        DB.outbox.update_one({'activity.object.id': obj.id}, {
            '$inc': {'meta.count_boost': 1},
        })
Exemple #8
0
def api_new_note():
    source = _user_api_arg('content')
    if not source:
        raise ValueError('missing content')

    _reply, reply = None, None
    try:
        _reply = _user_api_arg('reply')
    except ValueError:
        pass

    content, tags = parse_markdown(source)
    to = request.args.get('to')
    cc = [ID + '/followers']

    if _reply:
        reply = activitypub.parse_activity(OBJECT_SERVICE.get(_reply))
        cc.append(reply.attributedTo)

    for tag in tags:
        if tag['type'] == 'Mention':
            cc.append(tag['href'])

    note = activitypub.Note(cc=cc,
                            to=[to if to else config.AS_PUBLIC],
                            content=content,
                            tag=tags,
                            source={
                                'mediaType': 'text/markdown',
                                'content': source
                            },
                            inReplyTo=reply.id if reply else None)
    create = note.build_create()
    create.post_to_outbox()

    return _user_api_response(activity=create.id)
Exemple #9
0
 def _get_actual_object(self) -> BaseActivity:
     obj = self.get_object()
     if obj.type_enum == ActivityType.TOMBSTONE:
         obj = parse_activity(OBJECT_SERVICE.get(obj.id))
     return obj