Пример #1
0
def outbox_activity_shares(item_id):
    # TODO(tsileo): handle Tombstone
    if not is_api_request():
        abort(404)
    data = DB.outbox.find_one({'id': item_id, 'meta.deleted': False})
    if not data:
        abort(404)
    obj = activitypub.parse_activity(data['activity'])
    if obj.type_enum != ActivityType.CREATE:
        abort(404)

    q = {
        'meta.undo':
        False,
        'type':
        ActivityType.ANNOUNCE.value,
        '$or': [{
            'activity.object.id': obj.get_object().id
        }, {
            'activity.object': obj.get_object().id
        }],
    }

    return jsonify(**activitypub.build_ordered_collection(
        DB.inbox,
        q=q,
        cursor=request.args.get('cursor'),
        map_func=lambda doc: doc['activity'],
        col_name=f'outbox/{item_id}/shares',
        first_page=request.args.get('page') == 'first',
    ))
Пример #2
0
def outbox_detail(item_id):
    doc = DB.outbox.find_one({'id': item_id})
    if doc['meta'].get('deleted', False):
        obj = activitypub.parse_activity(doc['activity'])
        resp = jsonify(**obj.get_object().get_tombstone())
        resp.status_code = 410
        return resp
    return jsonify(**activity_from_doc(doc))
Пример #3
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
Пример #4
0
def api_undo():
    oid = _user_api_arg('id')
    doc = DB.outbox.find_one({'$or': [{'id': oid}, {'remote_id': oid}]})
    if not doc:
        raise ActivityNotFoundError(f'cannot found {oid}')

    obj = activitypub.parse_activity(doc.get('activity'))
    # FIXME(tsileo): detect already undo-ed and make this API call idempotent
    undo = obj.build_undo()
    undo.post_to_outbox()

    return _user_api_response(activity=undo.id)
Пример #5
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)
Пример #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, )
Пример #7
0
def outbox():
    if request.method == 'GET':
        if not is_api_request():
            abort(404)
        # TODO(tsileo): filter the outbox if not authenticated
        # FIXME(tsileo): filter deleted, add query support for build_ordered_collection
        q = {
            'meta.deleted': False,
            #'type': {'$in': [ActivityType.CREATE.value, ActivityType.ANNOUNCE.value]},
        }
        return jsonify(**activitypub.build_ordered_collection(
            DB.outbox,
            q=q,
            cursor=request.args.get('cursor'),
            map_func=lambda doc: activity_from_doc(doc),
        ))

    # Handle POST request
    try:
        _api_required()
    except BadSignature:
        abort(401)

    data = request.get_json(force=True)
    print(data)
    activity = activitypub.parse_activity(data)

    if activity.type_enum == ActivityType.NOTE:
        activity = activity.build_create()

    activity.post_to_outbox()

    # Purge the cache if a custom hook is set, as new content was published
    custom_cache_purge_hook()

    return Response(status=201, headers={'Location': activity.id})
Пример #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)