Exemplo n.º 1
0
def access_token(request):
    """ Provides an access token based on a valid verifier and request token """
    data = request.headers

    parsed_tokens = decode_authorization_header(data)

    if parsed_tokens == dict() or "oauth_token" not in parsed_tokens:
        error = "Missing required parameter."
        return json_response({"error": error}, status=400)

    request.resource_owner_key = parsed_tokens["oauth_consumer_key"]
    request.oauth_token = parsed_tokens["oauth_token"]
    request_validator = GMGRequestValidator(data)

    # Check that the verifier is valid
    verifier_valid = request_validator.validate_verifier(
        token=request.oauth_token,
        verifier=parsed_tokens["oauth_verifier"]
    )
    if not verifier_valid:
        error = "Verifier code or token incorrect"
        return json_response({"error": error}, status=401)

    av = AccessTokenEndpoint(request_validator)
    tokens = av.create_access_token(request, {})
    return form_response(tokens)
Exemplo n.º 2
0
def authorize(request, client):
    # TODO: Get rid of the JSON responses in this view, it's called by the
    # user-agent, not the client.
    user_client_relation = OAuthUserClient.query.filter(
        (OAuthUserClient.user == request.user)
        & (OAuthUserClient.client == client))

    if user_client_relation.filter(
            OAuthUserClient.state == u'approved').count():
        redirect_uri = None

        if client.type == u'public':
            if not client.redirect_uri:
                return json_response(
                    {
                        'status':
                        400,
                        'errors': [
                            u'Public clients should have a redirect_uri pre-set.'
                        ]
                    },
                    _disable_cors=True)

            redirect_uri = client.redirect_uri

        if client.type == u'confidential':
            redirect_uri = request.GET.get('redirect_uri', client.redirect_uri)
            if not redirect_uri:
                return json_response(
                    {
                        'status': 400,
                        'errors': [u'No redirect_uri supplied!']
                    },
                    _disable_cors=True)

        code = OAuthCode()
        code.user = request.user
        code.client = client
        code.save()

        redirect_uri = ''.join(
            [redirect_uri, '?',
             urlencode({'code': code.code})])

        _log.debug('Redirecting to {0}'.format(redirect_uri))

        return redirect(request, location=redirect_uri)
    else:
        # Show prompt to allow client to access data
        # - on accept: send the user agent back to the redirect_uri with the
        # code parameter
        # - on deny: send the user agent back to the redirect uri with error
        # information
        form = AuthorizationForm(request.form)
        form.client_id.data = client.id
        form.next.data = request.url
        return render_to_response(request, 'oauth/authorize.html', {
            'form': form,
            'client': client
        })
Exemplo n.º 3
0
    def wrapper(request, *args, **kwargs):
        data = request.headers
        authorization = decode_authorization_header(data)

        if authorization == dict():
            error = "Missing required parameter."
            return json_response({"error": error}, status=400)


        request_validator = GMGRequestValidator()
        resource_endpoint = ResourceEndpoint(request_validator)
        valid, r = resource_endpoint.validate_protected_resource_request(
                uri=request.url,
                http_method=request.method,
                body=request.data,
                headers=dict(request.headers),
                )

        if not valid:
            error = "Invalid oauth prarameter."
            return json_response({"error": error}, status=400)

        # Fill user if not already
        token = authorization[u"oauth_token"]
        request.access_token = AccessToken.query.filter_by(token=token).first()
        if request.access_token is not None and request.user is None:
            user_id = request.access_token.actor
            request.user = LocalUser.query.filter_by(id=user_id).first()

        return controller(request, *args, **kwargs)
Exemplo n.º 4
0
    def wrapper(request, *args, **kwargs):
        data = request.headers
        authorization = decode_authorization_header(data)

        if authorization == dict():
            error = "Missing required parameter."
            return json_response({"error": error}, status=400)

        request_validator = GMGRequestValidator()
        resource_endpoint = ResourceEndpoint(request_validator)
        valid, r = resource_endpoint.validate_protected_resource_request(
            uri=request.url,
            http_method=request.method,
            body=request.data,
            headers=dict(request.headers),
        )

        if not valid:
            error = "Invalid oauth prarameter."
            return json_response({"error": error}, status=400)

        # Fill user if not already
        token = authorization[u"oauth_token"]
        request.access_token = AccessToken.query.filter_by(token=token).first()
        if request.access_token is not None and request.user is None:
            user_id = request.access_token.actor
            request.user = LocalUser.query.filter_by(id=user_id).first()

        return controller(request, *args, **kwargs)
def authorize(request, client):
    # TODO: Get rid of the JSON responses in this view, it's called by the
    # user-agent, not the client.
    user_client_relation = OAuthUserClient.query.filter(
            (OAuthUserClient.user == request.user)
            & (OAuthUserClient.client == client))

    if user_client_relation.filter(OAuthUserClient.state ==
            u'approved').count():
        redirect_uri = None

        if client.type == u'public':
            if not client.redirect_uri:
                return json_response({
                    'status': 400,
                    'errors':
                        [u'Public clients should have a redirect_uri pre-set.']},
                        _disable_cors=True)

            redirect_uri = client.redirect_uri

        if client.type == u'confidential':
            redirect_uri = request.GET.get('redirect_uri', client.redirect_uri)
            if not redirect_uri:
                return json_response({
                    'status': 400,
                    'errors': [u'No redirect_uri supplied!']},
                    _disable_cors=True)

        code = OAuthCode()
        code.user = request.user
        code.client = client
        code.save()

        redirect_uri = ''.join([
            redirect_uri,
            '?',
            urlencode({'code': code.code})])

        _log.debug('Redirecting to {0}'.format(redirect_uri))

        return redirect(request, location=redirect_uri)
    else:
        # Show prompt to allow client to access data
        # - on accept: send the user agent back to the redirect_uri with the
        # code parameter
        # - on deny: send the user agent back to the redirect uri with error
        # information
        form = AuthorizationForm(request.form)
        form.client_id.data = client.id
        form.next.data = request.url
        return render_to_response(
                request,
                'oauth/authorize.html',
                {'form': form,
                'client': client})
Exemplo n.º 6
0
def post_entry(request):
    _log.debug('Posting entry')

    if request.method == 'OPTIONS':
        return json_response({'status': 200})

    if request.method != 'POST':
        _log.debug('Must POST against post_entry')
        raise BadRequest()

    if not check_file_field(request, 'file'):
        _log.debug('File field not found')
        raise BadRequest()

    upload_limit, max_file_size = get_upload_file_limits(request.user)

    callback_url = request.form.get('callback_url')
    if callback_url:
        callback_url = unicode(callback_url)
    try:
        entry = submit_media(mg_app=request.app,
                             user=request.user,
                             submitted_file=request.files['file'],
                             filename=request.files['file'].filename,
                             title=unicode(request.form.get('title')),
                             description=unicode(
                                 request.form.get('description')),
                             license=unicode(request.form.get('license', '')),
                             tags_string=unicode(request.form.get('tags', '')),
                             upload_limit=upload_limit,
                             max_file_size=max_file_size,
                             callback_url=callback_url)

        return json_response(get_entry_serializable(entry, request.urlgen))

    # Handle upload limit issues
    except FileUploadLimit:
        raise BadRequest(_(u'Sorry, the file size is too big.'))
    except UserUploadLimit:
        raise BadRequest(
            _('Sorry, uploading this file will put you over your'
              ' upload limit.'))
    except UserPastUploadLimit:
        raise BadRequest(_('Sorry, you have reached your upload limit.'))

    except Exception as e:
        '''
        This section is intended to catch exceptions raised in
        mediagoblin.media_types
        '''
        if isinstance(e, InvalidFileType) or \
                isinstance(e, FileTypeNotSupported):
            raise BadRequest(unicode(e))
        else:
            raise
Exemplo n.º 7
0
def post_entry(request):
    _log.debug('Posting entry')

    if request.method == 'OPTIONS':
        return json_response({'status': 200})

    if request.method != 'POST':
        _log.debug('Must POST against post_entry')
        raise BadRequest()

    if not check_file_field(request, 'file'):
        _log.debug('File field not found')
        raise BadRequest()

    upload_limit, max_file_size = get_upload_file_limits(request.user)

    callback_url = request.form.get('callback_url')
    if callback_url:
        callback_url = unicode(callback_url)
    try:
        entry = submit_media(
            mg_app=request.app, user=request.user,
            submitted_file=request.files['file'],
            filename=request.files['file'].filename,
            title=unicode(request.form.get('title')),
            description=unicode(request.form.get('description')),
            license=unicode(request.form.get('license', '')),
            upload_limit=upload_limit, max_file_size=max_file_size,
            callback_url=callback_url)

        return json_response(get_entry_serializable(entry, request.urlgen))

    # Handle upload limit issues
    except FileUploadLimit:
        raise BadRequest(
            _(u'Sorry, the file size is too big.'))
    except UserUploadLimit:
        raise BadRequest(
            _('Sorry, uploading this file will put you over your'
              ' upload limit.'))
    except UserPastUploadLimit:
        raise BadRequest(
            _('Sorry, you have reached your upload limit.'))

    except Exception as e:
        '''
        This section is intended to catch exceptions raised in
        mediagoblin.media_types
        '''
        if isinstance(e, InvalidFileType) or \
                isinstance(e, FileTypeNotSupported):
            raise BadRequest(unicode(e))
        else:
            raise
Exemplo n.º 8
0
def post_entry(request):
    _log.debug('Posting entry')

    if request.method == 'OPTIONS':
        return json_response({'status': 200})

    if request.method != 'POST':
        _log.debug('Must POST against post_entry')
        raise BadRequest()

    if not check_file_field(request, 'file'):
        _log.debug('File field not found')
        raise BadRequest()

    media_file = request.files['file']

    media_type, media_manager = sniff_media(media_file)

    entry = new_upload_entry(request.user)
    entry.media_type = unicode(media_type)
    entry.title = unicode(
        request.form.get('title') or splitext(media_file.filename)[0])

    entry.description = unicode(request.form.get('description'))
    entry.license = unicode(request.form.get('license', ''))

    entry.generate_slug()

    # queue appropriately
    queue_file = prepare_queue_task(request.app, entry, media_file.filename)

    with queue_file:
        queue_file.write(request.files['file'].stream.read())

    # Save now so we have this data before kicking off processing
    entry.save()

    if request.form.get('callback_url'):
        metadata = request.db.ProcessingMetaData()
        metadata.media_entry = entry
        metadata.callback_url = unicode(request.form['callback_url'])
        metadata.save()

    # Pass off to processing
    #
    # (... don't change entry after this point to avoid race
    # conditions with changes to the document via processing code)
    feed_url = request.urlgen('mediagoblin.user_pages.atom_feed',
                              qualified=True,
                              user=request.user.username)
    run_process_media(entry, feed_url)

    return json_response(get_entry_serializable(entry, request.urlgen))
Exemplo n.º 9
0
def post_entry(request):
    _log.debug('Posting entry')

    if request.method == 'OPTIONS':
        return json_response({'status': 200})

    if request.method != 'POST':
        _log.debug('Must POST against post_entry')
        raise BadRequest()

    if not check_file_field(request, 'file'):
        _log.debug('File field not found')
        raise BadRequest()

    media_file = request.files['file']

    media_type, media_manager = sniff_media(media_file)

    entry = new_upload_entry(request.user)
    entry.media_type = unicode(media_type)
    entry.title = unicode(request.form.get('title')
            or splitext(media_file.filename)[0])

    entry.description = unicode(request.form.get('description'))
    entry.license = unicode(request.form.get('license', ''))

    entry.generate_slug()

    # queue appropriately
    queue_file = prepare_queue_task(request.app, entry, media_file.filename)

    with queue_file:
        queue_file.write(request.files['file'].stream.read())

    # Save now so we have this data before kicking off processing
    entry.save()

    if request.form.get('callback_url'):
        metadata = request.db.ProcessingMetaData()
        metadata.media_entry = entry
        metadata.callback_url = unicode(request.form['callback_url'])
        metadata.save()

    # Pass off to processing
    #
    # (... don't change entry after this point to avoid race
    # conditions with changes to the document via processing code)
    feed_url = request.urlgen(
        'mediagoblin.user_pages.atom_feed',
        qualified=True, user=request.user.username)
    run_process_media(entry, feed_url)

    return json_response(get_entry_serializable(entry, request.urlgen))
Exemplo n.º 10
0
def object_comments(request):
    """ Looks up for the comments on a object """
    public_id = request.urlgen(
        "mediagoblin.api.object",
        object_type=request.matchdict["object_type"],
        id=request.matchdict["id"],
        qualified=True
    )
    media = MediaEntry.query.filter_by(public_id=public_id).first()
    if media is None:
        return json_error("Can't find '{0}' with ID '{1}'".format(
            request.matchdict["object_type"],
            request.matchdict["id"]
        ), 404)

    comments = media.serialize(request)
    comments = comments.get("replies", {
        "totalItems": 0,
        "items": [],
        "url": request.urlgen(
            "mediagoblin.api.object.comments",
            object_type=media.object_type,
            id=media.id,
            qualified=True
        )
    })

    comments["displayName"] = "Replies to {0}".format(comments["url"])
    comments["links"] = {
        "first": comments["url"],
        "self": comments["url"],
    }
    return json_response(comments)
Exemplo n.º 11
0
def object_endpoint(request):
    """ Lookup for a object type """
    object_type = request.matchdict["object_type"]
    try:
        object_id = request.matchdict["id"]
    except ValueError:
        error = "Invalid object ID '{0}' for '{1}'".format(
            request.matchdict["id"],
            object_type
        )
        return json_error(error)

    if object_type not in ["image"]:
        # not sure why this is 404, maybe ask evan. Maybe 400?
        return json_error(
            "Unknown type: {0}".format(object_type),
            status=404
        )

    public_id = request.urlgen(
        "mediagoblin.api.object",
        object_type=object_type,
        id=object_id,
        qualified=True
    )

    media = MediaEntry.query.filter_by(public_id=public_id).first()
    if media is None:
        return json_error(
            "Can't find '{0}' with ID '{1}'".format(object_type, object_id),
            status=404
        )

    return json_response(media.serialize(request))
Exemplo n.º 12
0
        def wrapper(request, *args, **kwargs):
            if not request.user.has_privilege(privilege_name):
                error = "User '{}' needs '{}' privilege".format(
                    request.user.username, privilege_name)
                return json_response({"error": error}, status=403)

            return controller(request, *args, **kwargs)
Exemplo n.º 13
0
def object_endpoint(request):
    """ Lookup for a object type """
    object_type = request.matchdict["object_type"]
    try:
        object_id = request.matchdict["id"]
    except ValueError:
        error = "Invalid object ID '{0}' for '{1}'".format(
            request.matchdict["id"], object_type)
        return json_error(error)

    if object_type not in ["image"]:
        # not sure why this is 404, maybe ask evan. Maybe 400?
        return json_error("Unknown type: {0}".format(object_type), status=404)

    public_id = request.urlgen("mediagoblin.api.object",
                               object_type=object_type,
                               id=object_id,
                               qualified=True)

    media = MediaEntry.query.filter_by(public_id=public_id).first()
    if media is None:
        return json_error("Can't find '{0}' with ID '{1}'".format(
            object_type, object_id),
                          status=404)

    return json_response(media.serialize(request))
Exemplo n.º 14
0
def object_comments(request):
    """ Looks up for the comments on a object """
    media = object(request, raw_obj=True)
    response = media
    if isinstance(response, MediaEntry):
        comments = response.serialize(request)
        comments = comments.get("replies", {
            "totalItems": 0,
            "items": [],
            "url": request.urlgen(
                "mediagoblin.federation.object.comments",
                objectType=media.objectType,
                uuid=media.id,
                qualified=True
            )
        })

        comments["displayName"] = "Replies to {0}".format(comments["url"])
        comments["links"] = {
            "first": comments["url"],
            "self": comments["url"],
        }
        response = json_response(comments)

    return response
Exemplo n.º 15
0
def host_meta(request):
    """
    This provides the host-meta URL information that is outlined
    in RFC6415. By default this should provide XRD+XML however
    if the client accepts JSON we will provide that over XRD+XML.
    The 'Accept' header is used to decude this.

    A client should use this endpoint to determine what URLs to
    use for OAuth endpoints.
    """

    links = [
        {
            "rel":
            "lrdd",
            "type":
            "application/json",
            "href":
            request.urlgen("mediagoblin.webfinger.well-known.webfinger",
                           qualified=True)
        },
        {
            "rel":
            "registration_endpoint",
            "href":
            request.urlgen("mediagoblin.oauth.client_register",
                           qualified=True),
        },
        {
            "rel":
            "http://apinamespace.org/oauth/request_token",
            "href":
            request.urlgen("mediagoblin.oauth.request_token", qualified=True),
        },
        {
            "rel": "http://apinamespace.org/oauth/authorize",
            "href": request.urlgen("mediagoblin.oauth.authorize",
                                   qualified=True),
        },
        {
            "rel":
            "http://apinamespace.org/oauth/access_token",
            "href":
            request.urlgen("mediagoblin.oauth.access_token", qualified=True),
        },
        {
            "rel": "http://apinamespace.org/activitypub/whoami",
            "href": request.urlgen("mediagoblin.webfinger.whoami",
                                   qualified=True),
        },
    ]

    if "application/json" in request.accept_mimetypes:
        return json_response({"links": links})

    # provide XML+XRD
    return render_to_response(request,
                              "mediagoblin/api/host-meta.xml",
                              {"links": links},
                              mimetype="application/xrd+xml")
Exemplo n.º 16
0
def object_comments(request):
    """ Looks up for the comments on a object """
    public_id = request.urlgen("mediagoblin.api.object",
                               object_type=request.matchdict["object_type"],
                               id=request.matchdict["id"],
                               qualified=True)
    media = MediaEntry.query.filter_by(public_id=public_id).first()
    if media is None:
        return json_error(
            "Can't find '{0}' with ID '{1}'".format(
                request.matchdict["object_type"], request.matchdict["id"]),
            404)

    comments = media.serialize(request)
    comments = comments.get(
        "replies", {
            "totalItems":
            0,
            "items": [],
            "url":
            request.urlgen("mediagoblin.api.object.comments",
                           object_type=media.object_type,
                           id=media.id,
                           qualified=True)
        })

    comments["displayName"] = "Replies to {0}".format(comments["url"])
    comments["links"] = {
        "first": comments["url"],
        "self": comments["url"],
    }
    return json_response(comments)
Exemplo n.º 17
0
def host_meta(request):
    """ /.well-known/host-meta - provide URLs to resources """
    links = []

    links.append({
        "ref": "registration_endpoint",
        "href": request.urlgen(
            "mediagoblin.oauth.client_register",
            qualified=True
        ),
    })
    links.append({
        "ref": "http://apinamespace.org/oauth/request_token",
        "href": request.urlgen(
            "mediagoblin.oauth.request_token",
            qualified=True
        ),
    })
    links.append({
        "ref": "http://apinamespace.org/oauth/authorize",
        "href": request.urlgen(
            "mediagoblin.oauth.authorize",
            qualified=True
        ),
    })
    links.append({
        "ref": "http://apinamespace.org/oauth/access_token",
        "href": request.urlgen(
            "mediagoblin.oauth.access_token",
            qualified=True
        ),
    })

    return json_response({"links": links})
Exemplo n.º 18
0
def object(request, raw_obj=False):
    """ Lookup for a object type """
    object_type = request.matchdict["objectType"]
    try:
        object_id = int(request.matchdict["id"])
    except ValueError:
        error = "Invalid object ID '{0}' for '{1}'".format(
            request.matchdict["id"],
            object_type
        )
        return json_error(error)

    if object_type not in ["image"]:
        # not sure why this is 404, maybe ask evan. Maybe 400?
        return json_error(
            "Unknown type: {0}".format(object_type),
            status=404
        )

    media = MediaEntry.query.filter_by(id=object_id).first()
    if media is None:
        error = "Can't find '{0}' with ID '{1}'".format(
            object_type,
            object_id
        )
        return json_error(
            "Can't find '{0}' with ID '{1}'".format(object_type, object_id),
            status=404
        )

    if raw_obj:
        return media

    return json_response(media.serialize(request))
Exemplo n.º 19
0
def request_token(request):
    """ Returns request token """
    try:
        data = decode_request(request)
    except ValueError:
        error = "Could not decode data."
        return json_response({"error": error}, status=400)

    if data == "":
        error = "Unknown Content-Type"
        return json_response({"error": error}, status=400)

    if not data and request.headers:
        data = request.headers

    data = dict(data) # mutableifying

    authorization = decode_authorization_header(data)

    if authorization == dict() or u"oauth_consumer_key" not in authorization:
        error = "Missing required parameter."
        return json_response({"error": error}, status=400)

    # check the client_id
    client_id = authorization[u"oauth_consumer_key"]
    client = Client.query.filter_by(id=client_id).first()

    if client == None:
        # client_id is invalid
        error = "Invalid client_id"
        return json_response({"error": error}, status=400)

   # make request token and return to client
    request_validator = GMGRequestValidator(authorization)
    rv = RequestTokenEndpoint(request_validator)
    tokens = rv.create_request_token(request, authorization)

    # store the nonce & timestamp before we return back
    nonce = authorization[u"oauth_nonce"]
    timestamp = authorization[u"oauth_timestamp"]
    timestamp = datetime.datetime.fromtimestamp(float(timestamp))

    nc = NonceTimestamp(nonce=nonce, timestamp=timestamp)
    nc.save()

    return form_response(tokens)
Exemplo n.º 20
0
    def wrapper(request, *args, **kw):
        if not request.GET.get('client_id'):
            return json_response({
                'status': 400,
                'errors': [u'No client identifier in URL']},
                _disable_cors=True)

        client = OAuthClient.query.filter(
                OAuthClient.identifier == request.GET.get('client_id')).first()

        if not client:
            return json_response({
                'status': 400,
                'errors': [u'No such client identifier']},
                _disable_cors=True)

        return controller(request, client)
Exemplo n.º 21
0
def request_token(request):
    """ Returns request token """
    try:
        data = decode_request(request)
    except ValueError:
        error = "Could not decode data."
        return json_response({"error": error}, status=400)

    if data == "":
        error = "Unknown Content-Type"
        return json_response({"error": error}, status=400)

    if not data and request.headers:
        data = request.headers

    data = dict(data)  # mutableifying

    authorization = decode_authorization_header(data)

    if authorization == dict() or u"oauth_consumer_key" not in authorization:
        error = "Missing required parameter."
        return json_response({"error": error}, status=400)

    # check the client_id
    client_id = authorization[u"oauth_consumer_key"]
    client = Client.query.filter_by(id=client_id).first()

    if client == None:
        # client_id is invalid
        error = "Invalid client_id"
        return json_response({"error": error}, status=400)

# make request token and return to client
    request_validator = GMGRequestValidator(authorization)
    rv = RequestTokenEndpoint(request_validator)
    tokens = rv.create_request_token(request, authorization)

    # store the nonce & timestamp before we return back
    nonce = authorization[u"oauth_nonce"]
    timestamp = authorization[u"oauth_timestamp"]
    timestamp = datetime.datetime.fromtimestamp(float(timestamp))

    nc = NonceTimestamp(nonce=nonce, timestamp=timestamp)
    nc.save()

    return form_response(tokens)
Exemplo n.º 22
0
        def wrapper(request, *args, **kwargs):
            if not request.user.has_privilege(privilege_name):
                error = "User '{0}' needs '{1}' privilege".format(
                    request.user.username,
                    privilege_name
                )
                return json_response({"error": error}, status=403)

            return controller(request, *args, **kwargs)
Exemplo n.º 23
0
def profile_endpoint(request):
    """ This is /api/user/<username>/profile - This will give profile info """
    user, user_profile = get_profile(request)

    if user is None:
        username = request.matchdict["username"]
        return json_error("No such 'user' with username '{0}'".format(username), status=404)

    # user profiles are public so return information
    return json_response(user_profile)
Exemplo n.º 24
0
def post_entry(request):
    _log.debug('Posting entry')

    if request.method == 'OPTIONS':
        return json_response({'status': 200})

    if request.method != 'POST':
        _log.debug('Must POST against post_entry')
        raise BadRequest()

    if not check_file_field(request, 'file'):
        _log.debug('File field not found')
        raise BadRequest()

    callback_url = request.form.get('callback_url')
    if callback_url:
        callback_url = six.text_type(callback_url)
    try:
        entry = submit_media(
            mg_app=request.app, user=request.user,
            submitted_file=request.files['file'],
            filename=request.files['file'].filename,
            title=six.text_type(request.form.get('title')),
            description=six.text_type(request.form.get('description')),
            license=six.text_type(request.form.get('license', '')),
            tags_string=six.text_type(request.form.get('tags', '')),
            callback_url=callback_url)

        return json_response(get_entry_serializable(entry, request.urlgen))

    # Handle upload limit issues
    except FileUploadLimit:
        raise BadRequest(
            _(u'Sorry, the file size is too big.'))
    except UserUploadLimit:
        raise BadRequest(
            _('Sorry, uploading this file will put you over your'
              ' upload limit.'))
    except UserPastUploadLimit:
        raise BadRequest(
            _('Sorry, you have reached your upload limit.'))
    except FileTypeNotSupported as e:
        raise BadRequest(e)
Exemplo n.º 25
0
def profile_endpoint(request):
    """ This is /api/user/<username>/profile - This will give profile info """
    user, user_profile = get_profile(request)

    if user is None:
        username = request.matchdict["username"]
        return json_error(
            "No such 'user' with username '{0}'".format(username), status=404)

    # user profiles are public so return information
    return json_response(user_profile)
Exemplo n.º 26
0
def user(request):
    """ This is /api/user/<username> - This will get the user """
    user, user_profile = profile(request, raw=True)
    data = {
        "nickname": user.username,
        "updated": user.created.isoformat(),
        "published": user.created.isoformat(),
        "profile": user_profile,
    }

    return json_response(data)
Exemplo n.º 27
0
    def wrapper(request, *args, **kw):
        if not request.GET.get('client_id'):
            return json_response(
                {
                    'status': 400,
                    'errors': [u'No client identifier in URL']
                },
                _disable_cors=True)

        client = OAuthClient.query.filter(
            OAuthClient.identifier == request.GET.get('client_id')).first()

        if not client:
            return json_response(
                {
                    'status': 400,
                    'errors': [u'No such client identifier']
                },
                _disable_cors=True)

        return controller(request, client)
Exemplo n.º 28
0
def api_upload_request(request, file_data, entry):
    """ This handles a image upload request """
    # Use the same kind of method from mediagoblin/submit/views:submit_start
    entry.title = file_data.filename
    entry.generate_slug()

    queue_file = prepare_queue_task(request.app, entry, file_data.filename)
    with queue_file:
        queue_file.write(request.data)

    entry.save()
    return json_response(entry.serialize(request))
Exemplo n.º 29
0
def api_upload_request(request, file_data, entry):
    """ This handles a image upload request """
    # Use the same kind of method from mediagoblin/submit/views:submit_start
    entry.title = file_data.filename
    entry.generate_slug()

    queue_file = prepare_queue_task(request.app, entry, file_data.filename)
    with queue_file:
        queue_file.write(request.data)

    entry.save()
    return json_response(entry.serialize(request))
Exemplo n.º 30
0
def lrdd_lookup(request):
    """
    This is the lrdd endpoint which can lookup a user (or
    other things such as activities). This is as specified by
    RFC6415.

    The cleint must provide a 'resource' as a GET parameter which
    should be the query to be looked up.
    """

    if "resource" not in request.args:
        return json_error("No resource parameter", status=400)

    resource = request.args["resource"]

    if "@" in resource:
        # Lets pull out the username
        resource = resource[5:] if resource.startswith("acct:") else resource
        username, host = resource.split("@", 1)

        # Now lookup the user
        user = LocalUser.query.filter(LocalUser.username==username).first()

        if user is None:
            return json_error(
                "Can't find 'user' with username '{}'".format(username))

        return json_response([
            {
                "rel": "http://webfinger.net/rel/profile-page",
                "href": user.url_for_self(request.urlgen),
                "type": "text/html"
            },
            {
                "rel": "self",
                "href": request.urlgen(
                    "mediagoblin.api.user",
                    username=user.username,
                    qualified=True
                )
            },
            {
                "rel": "activity-outbox",
                "href": request.urlgen(
                    "mediagoblin.api.feed",
                    username=user.username,
                    qualified=True
                )
            }
        ])
    else:
        return json_error("Unrecognized resource parameter", status=404)
Exemplo n.º 31
0
def lrdd_lookup(request):
    """
    This is the lrdd endpoint which can lookup a user (or
    other things such as activities). This is as specified by
    RFC6415.

    The cleint must provide a 'resource' as a GET parameter which
    should be the query to be looked up.
    """

    if "resource" not in request.args:
        return json_error("No resource parameter", status=400)

    resource = request.args["resource"]

    if "@" in resource:
        # Lets pull out the username
        resource = resource[5:] if resource.startswith("acct:") else resource
        username, host = resource.split("@", 1)

        # Now lookup the user
        user = LocalUser.query.filter(LocalUser.username==username).first()

        if user is None:
            return json_error(
                "Can't find 'user' with username '{0}'".format(username))

        return json_response([
            {
                "rel": "http://webfinger.net/rel/profile-page",
                "href": user.url_for_self(request.urlgen),
                "type": "text/html"
            },
            {
                "rel": "self",
                "href": request.urlgen(
                    "mediagoblin.api.user",
                    username=user.username,
                    qualified=True
                )
            },
            {
                "rel": "activity-outbox",
                "href": request.urlgen(
                    "mediagoblin.api.feed",
                    username=user.username,
                    qualified=True
                )
            }
        ])
    else:
        return json_error("Unrecognized resource parameter", status=404)
Exemplo n.º 32
0
def api_add_to_feed(request, entry):
    """ Add media to Feed """
    if entry.title:
        entry.generate_slug()

    feed_url = request.urlgen(
        'mediagoblin.user_pages.atom_feed',
        qualified=True, user=request.user.username
    )

    run_process_media(entry, feed_url)
    add_comment_subscription(request.user, entry)
    return json_response(entry.serialize(request))
Exemplo n.º 33
0
    def wrapper(request, *args, **kwargs):
        data = request.headers
        authorization = decode_authorization_header(data)

        if authorization == dict():
            error = "Missing required parameter."
            return json_response({"error": error}, status=400)

        request_validator = GMGRequestValidator()
        resource_endpoint = ResourceEndpoint(request_validator)
        valid, request = resource_endpoint.validate_protected_resource_request(
            uri=request.url,
            http_method=request.method,
            body=request.get_data(),
            headers=dict(request.headers),
        )

        if not valid:
            error = "Invalid oauth prarameter."
            return json_response({"error": error}, status=400)

        return controller(request, *args, **kwargs)
Exemplo n.º 34
0
    def wrapper(request, *args, **kwargs):
        data = request.headers
        authorization = decode_authorization_header(data)

        if authorization == dict():
            error = "Missing required parameter."
            return json_response({"error": error}, status=400)


        request_validator = GMGRequestValidator()
        resource_endpoint = ResourceEndpoint(request_validator)
        valid, request = resource_endpoint.validate_protected_resource_request(
                uri=request.url,
                http_method=request.method,
                body=request.get_data(),
                headers=dict(request.headers),
                )

        if not valid:
            error = "Invalid oauth prarameter."
            return json_response({"error": error}, status=400)

        return controller(request, *args, **kwargs)
Exemplo n.º 35
0
def api_upload_request(request, file_data, entry):
    """ This handles a image upload request """
    # Use the same kind of method from mediagoblin/submit/views:submit_start
    entry.title = file_data.filename

    # This will be set later but currently we just don't have enough information
    entry.slug = None

    queue_file = prepare_queue_task(request.app, entry, file_data.filename)
    with queue_file:
        queue_file.write(request.data)

    entry.save()
    return json_response(entry.serialize(request))
Exemplo n.º 36
0
def upload_handler(request):
	if request.GET.get('url') and request.GET.get('title') and request.user:
		upload_limit, max_file_size = get_upload_file_limits(request.user)
		try:
			f = urlopen(request.GET.get('url'))
			fname = request.GET.get('url')[request.GET.get('url').rfind('/')+1:]
			tmpfile = tempfile.NamedTemporaryFile()
			tmpfile.write(f.read)
			tmpfile.flush()
			local_file = open(tmpfile.name, "r")
			try:
				entry = submit_media(
					mg_app = request.app, user=request.user,
					submitted_file=local_file, filename=fname,
					title=request.GET.get('title'))
				entryinfo = get_entry_serializable(entry, request.urlgen)
				os.unlink(f.name)
				return json_response({'status':200, 'permalink':entryinfo['permalink']})
			except FileUploadLimit:
				return json_reponse({'status':400, 'error':'Past File size Upload Limit'})
			except UserUploadLimit:
				return json_response({'status':400, 'error':'Past User upload limit'})
			except UserPastUploadLimit:
				return json_response({'status':400, 'error':'Past upload limit'})
			except Exception as e:
				return json_response({'status':400, 'error':'Unspecified error'})

		except HTTPError as e:
			print("HTTP Error:", e.code, url)
			return json_response({'status':400, 'error':'unspecifice httperror'})
		except URLError as e:
			print("URL Error:", e.reason, url)
			return json_response({'status':400, 'error':'unspecified url error'})
	else:
		if not request.GET.get('url'):
			return json_response({'status':400, 'error':'No URL specified [GET, url]'})
		elif not request.GET.get('title'):
			return json_response({'status':400, 'error':'No title specified [GET, title]'})
		elif not request.user:
			return json_response({'status':401, 'error':'No user found'});
		else:
			return json_reponse({'status':400, 'error':'Unknown Error Occured'})
Exemplo n.º 37
0
def api_add_to_feed(request, entry):
    """ Add media to Feed """
    feed_url = request.urlgen(
        'mediagoblin.user_pages.atom_feed',
        qualified=True, user=request.user.username
    )

    add_comment_subscription(request.user, entry)

    # Create activity
    create_activity("post", entry, entry.uploader)
    entry.save()
    run_process_media(entry, feed_url)

    return json_response(entry.serialize(request))
Exemplo n.º 38
0
def access_token(request):
    """ Provides an access token based on a valid verifier and request token """
    data = request.headers

    parsed_tokens = decode_authorization_header(data)

    if parsed_tokens == dict() or "oauth_token" not in parsed_tokens:
        error = "Missing required parameter."
        return json_response({"error": error}, status=400)

    request.resource_owner_key = parsed_tokens["oauth_consumer_key"]
    request.oauth_token = parsed_tokens["oauth_token"]
    request_validator = GMGRequestValidator(data)

    # Check that the verifier is valid
    verifier_valid = request_validator.validate_verifier(
        token=request.oauth_token, verifier=parsed_tokens["oauth_verifier"])
    if not verifier_valid:
        error = "Verifier code or token incorrect"
        return json_response({"error": error}, status=401)

    av = AccessTokenEndpoint(request_validator)
    tokens = av.create_access_token(request, {})
    return form_response(tokens)
Exemplo n.º 39
0
def api_add_to_feed(request, entry):
    """ Add media to Feed """
    if entry.title:
        # Shame we have to do this here but we didn't have the data in
        # api_upload_request as no filename is usually specified.
        entry.slug = None
        entry.generate_slug()

    feed_url = request.urlgen(
        'mediagoblin.user_pages.atom_feed',
        qualified=True, user=request.user.username)

    run_process_media(entry, feed_url)
    add_comment_subscription(request.user, entry)
    return json_response(entry.serialize(request))
Exemplo n.º 40
0
def user_endpoint(request):
    """ This is /api/user/<username> - This will get the user """
    user, user_profile = get_profile(request)

    if user is None:
        username = request.matchdict["username"]
        return json_error(
            "No such 'user' with username '{0}'".format(username), status=404)

    return json_response({
        "nickname": user.username,
        "updated": user.created.isoformat(),
        "published": user.created.isoformat(),
        "profile": user_profile,
    })
Exemplo n.º 41
0
def api_add_to_feed(request, entry):
    """ Add media to Feed """
    if entry.title:
        # Shame we have to do this here but we didn't have the data in
        # api_upload_request as no filename is usually specified.
        entry.slug = None
        entry.generate_slug()

    feed_url = request.urlgen('mediagoblin.user_pages.atom_feed',
                              qualified=True,
                              user=request.user.username)

    run_process_media(entry, feed_url)
    add_comment_subscription(request.user, entry)
    return json_response(entry.serialize(request))
Exemplo n.º 42
0
def access_token(request):
    """ Provides an access token based on a valid verifier and request token """
    data = request.headers

    parsed_tokens = decode_authorization_header(data)

    if parsed_tokens == dict() or "oauth_token" not in parsed_tokens:
        error = "Missing required parameter."
        return json_response({"error": error}, status=400)

    request.oauth_token = parsed_tokens["oauth_token"]
    request_validator = GMGRequestValidator(data)
    av = AccessTokenEndpoint(request_validator)
    tokens = av.create_access_token(request, {})
    return form_response(tokens)
Exemplo n.º 43
0
def oembed_with_media(request, media, maxheight=None, maxwidth=None, **kwargs):
    response = {}

    if media.media_type == IMAGE_MEDIA_TYPE:
        response['type'] = u'photo'
    elif media.media_type == VIDEO_MEDIA_TYPE:
        response['type'] = u'video'
    else:
        NotImplemented()

    response['version'] = u'1.0'
    media_dict = get_entry_serializable(media, request.urlgen)
    response['title'] = media.title
    response['author_name'] = media_dict['user']
    response['author_url'] = media_dict['user_permalink']
    response['provider_name'] = u'MediaGoblin'
    response['provider_url'] = request.host_url

    if media.media_type == IMAGE_MEDIA_TYPE:
        response['url'] = media_dict['media_files']['medium']
        response['height'] = media.get_file_metadata('medium', 'height')
        response['width'] = media.get_file_metadata('medium', 'width')

        if ((maxheight and response['height'] > maxheight) or
                (maxwidth and response['width'] > maxwidth)):
            response['url'] = media_dict['media_files']['thumb']
            response['height'] = media.get_file_metadata('thumb', 'height')
            response['width'] = media.get_file_metadata('thumb', 'width')

    elif media.media_type == VIDEO_MEDIA_TYPE:
        video_url = media_dict['media_files']['webm_video']

        response['width'], response['height'] = media.get_file_metadata(
            'webm_video', 'medium_size')

        if maxheight:
            response['height'] = maxheight
        if maxwidth:
            response['width'] = maxwidth

        response['html'] = (u'<video width="{0}" height="{1}" controls>'
                            '  <source src="{2}" type="video/webm">'
                            '   Your browser does not support the video tag.'
                            '</video>').format(response['width'],
                                               response['height'],
                                               video_url)

    return json_response(response, _disable_cors=True)
Exemplo n.º 44
0
def profile(request, raw=False):
    """ This is /api/user/<username>/profile - This will give profile info """
    user = request.matchdict["username"]
    requested_user = User.query.filter_by(username=user).first()

    if user is None:
        return json_error(
            "No such 'user' with id '{0}'".format(user),
            status=404
        )

    if raw:
        return (requested_user.username, requested_user.serialize(request))

    # user profiles are public so return information
    return json_response(requested_user.serialize(request))
Exemplo n.º 45
0
def user_endpoint(request):
    """ This is /api/user/<username> - This will get the user """
    user, user_profile = get_profile(request)

    if user is None:
        username = request.matchdict["username"]
        return json_error("No such 'user' with username '{0}'".format(username), status=404)

    return json_response(
        {
            "nickname": user.username,
            "updated": user.created.isoformat(),
            "published": user.created.isoformat(),
            "profile": user_profile,
        }
    )
Exemplo n.º 46
0
def access_token(request):
    """ Provides an access token based on a valid verifier and request token """ 
    data = request.headers

    parsed_tokens = decode_authorization_header(data)    

    if parsed_tokens == dict() or "oauth_token" not in parsed_tokens:
        error = "Missing required parameter."
        return json_response({"error": error}, status=400)


    request.oauth_token = parsed_tokens["oauth_token"]
    request_validator = GMGRequestValidator(data)
    av = AccessTokenEndpoint(request_validator)
    tokens = av.create_access_token(request, {})
    return form_response(tokens)
Exemplo n.º 47
0
def api_upload_request(request, file_data, entry):
    """ This handles a image upload request """
    # Use the same kind of method from mediagoblin/submit/views:submit_start
    entry.title = file_data.filename

    # This will be set later but currently we just don't have enough information
    entry.slug = None

    # This is a MUST.
    entry.get_public_id(request.urlgen)

    queue_file = prepare_queue_task(request.app, entry, file_data.filename)
    with queue_file:
        queue_file.write(request.data)

    entry.save()
    return json_response(entry.serialize(request))
Exemplo n.º 48
0
def get_entries(request):
    entries = request.db.MediaEntry.query

    # TODO: Make it possible to fetch unprocessed media, or media in-processing
    entries = entries.filter_by(state=u'processed')

    # TODO: Add sort order customization
    entries = entries.order_by(request.db.MediaEntry.created.desc())

    # TODO: Fetch default and upper limit from config
    entries = entries.limit(int(request.GET.get('limit') or 10))

    entries_serializable = []

    for entry in entries:
        entries_serializable.append(get_entry_serializable(entry, request.urlgen))

    return json_response(entries_serializable)
Exemplo n.º 49
0
def get_entries(request):
    entries = request.db.MediaEntry.query

    # TODO: Make it possible to fetch unprocessed media, or media in-processing
    entries = entries.filter_by(state=u'processed')

    # TODO: Add sort order customization
    entries = entries.order_by(request.db.MediaEntry.created.desc())

    # TODO: Fetch default and upper limit from config
    entries = entries.limit(int(request.GET.get('limit') or 10))

    entries_serializable = []

    for entry in entries:
        entries_serializable.append(get_entry_serializable(entry, request.urlgen))

    return json_response(entries_serializable)
Exemplo n.º 50
0
def host_meta(request):
    """
    This provides the host-meta URL information that is outlined
    in RFC6415. By default this should provide XRD+XML however
    if the client accepts JSON we will provide that over XRD+XML.
    The 'Accept' header is used to decude this.

    A client should use this endpoint to determine what URLs to
    use for OAuth endpoints.
    """

    links = [
        {
            "rel": "lrdd",
            "type": "application/json",
            "href": request.urlgen("mediagoblin.webfinger.well-known.webfinger", qualified=True),
        },
        {"rel": "registration_endpoint", "href": request.urlgen("mediagoblin.oauth.client_register", qualified=True)},
        {
            "rel": "http://apinamespace.org/oauth/request_token",
            "href": request.urlgen("mediagoblin.oauth.request_token", qualified=True),
        },
        {
            "rel": "http://apinamespace.org/oauth/authorize",
            "href": request.urlgen("mediagoblin.oauth.authorize", qualified=True),
        },
        {
            "rel": "http://apinamespace.org/oauth/access_token",
            "href": request.urlgen("mediagoblin.oauth.access_token", qualified=True),
        },
        {
            "rel": "http://apinamespace.org/activitypub/whoami",
            "href": request.urlgen("mediagoblin.webfinger.whoami", qualified=True),
        },
    ]

    if "application/json" in request.accept_mimetypes:
        return json_response({"links": links})

    # provide XML+XRD
    return render_to_response(
        request, "mediagoblin/api/host-meta.xml", {"links": links}, mimetype="application/xrd+xml"
    )
Exemplo n.º 51
0
def feed_endpoint(request, outbox=None):
    """ Handles the user's outbox - /api/user/<username>/feed """
    username = request.matchdict["username"]
    requested_user = LocalUser.query.filter(
        LocalUser.username == username).first()

    # check if the user exists
    if requested_user is None:
        return json_error("No such 'user' with id '{0}'".format(username), 404)

    if request.data:
        data = json.loads(request.data.decode())
    else:
        data = {"verb": None, "object": {}}

    if request.method in ["POST", "PUT"]:
        # Validate that the activity is valid
        if "verb" not in data or "object" not in data:
            return json_error("Invalid activity provided.")

        # Check that the verb is valid
        if data["verb"] not in ["post", "update", "delete"]:
            return json_error("Verb not yet implemented", 501)

        # We need to check that the user they're posting to is
        # the person that they are.
        if requested_user.id != request.user.id:
            return json_error("Not able to post to another users feed.",
                              status=403)

        # Handle new posts
        if data["verb"] == "post":
            obj = data.get("object", None)
            if obj is None:
                return json_error("Could not find 'object' element.")

            if obj.get("objectType", None) == "comment":
                # post a comment
                if not request.user.has_privilege(u'commenter'):
                    return json_error(
                        "Privilege 'commenter' required to comment.",
                        status=403)

                comment = TextComment(actor=request.user.id)
                comment.unserialize(data["object"], request)
                comment.save()

                # Create activity for comment
                generator = create_generator(request)
                activity = create_activity(verb="post",
                                           actor=request.user,
                                           obj=comment,
                                           target=comment.get_reply_to(),
                                           generator=generator)

                return json_response(activity.serialize(request))

            elif obj.get("objectType", None) == "image":
                # Posting an image to the feed
                media_id = extract_url_arguments(
                    url=data["object"]["id"], urlmap=request.app.url_map)["id"]

                # Build public_id
                public_id = request.urlgen("mediagoblin.api.object",
                                           object_type=obj["objectType"],
                                           id=media_id,
                                           qualified=True)

                media = MediaEntry.query.filter_by(public_id=public_id).first()

                if media is None:
                    return json_response(
                        "No such 'image' with id '{0}'".format(media_id),
                        status=404)

                if media.actor != request.user.id:
                    return json_error(
                        "Privilege 'commenter' required to comment.",
                        status=403)

                if not media.unserialize(data["object"]):
                    return json_error(
                        "Invalid 'image' with id '{0}'".format(media_id))

                # Add location if one exists
                if "location" in data:
                    Location.create(data["location"], self)

                media.save()
                activity = api_add_to_feed(request, media)

                return json_response(activity.serialize(request))

            elif obj.get("objectType", None) is None:
                # They need to tell us what type of object they're giving us.
                return json_error("No objectType specified.")
            else:
                # Oh no! We don't know about this type of object (yet)
                object_type = obj.get("objectType", None)
                return json_error(
                    "Unknown object type '{0}'.".format(object_type))

        # Updating existing objects
        if data["verb"] == "update":
            # Check we've got a valid object
            obj = data.get("object", None)

            if obj is None:
                return json_error("Could not find 'object' element.")

            if "objectType" not in obj:
                return json_error("No objectType specified.")

            if "id" not in obj:
                return json_error("Object ID has not been specified.")

            obj_id = extract_url_arguments(url=obj["id"],
                                           urlmap=request.app.url_map)["id"]

            public_id = request.urlgen("mediagoblin.api.object",
                                       object_type=obj["objectType"],
                                       id=obj_id,
                                       qualified=True)

            # Now try and find object
            if obj["objectType"] == "comment":
                if not request.user.has_privilege(u'commenter'):
                    return json_error(
                        "Privilege 'commenter' required to comment.",
                        status=403)

                comment = TextComment.query.filter_by(
                    public_id=public_id).first()
                if comment is None:
                    return json_error(
                        "No such 'comment' with id '{0}'.".format(obj_id))

                # Check that the person trying to update the comment is
                # the author of the comment.
                if comment.actor != request.user.id:
                    return json_error(
                        "Only author of comment is able to update comment.",
                        status=403)

                if not comment.unserialize(data["object"], request):
                    return json_error("Invalid 'comment' with id '{0}'".format(
                        obj["id"]))

                comment.save()

                # Create an update activity
                generator = create_generator(request)
                activity = create_activity(verb="update",
                                           actor=request.user,
                                           obj=comment,
                                           generator=generator)

                return json_response(activity.serialize(request))

            elif obj["objectType"] == "image":
                image = MediaEntry.query.filter_by(public_id=public_id).first()
                if image is None:
                    return json_error(
                        "No such 'image' with the id '{0}'.".format(obj["id"]))

                # Check that the person trying to update the comment is
                # the author of the comment.
                if image.actor != request.user.id:
                    return json_error(
                        "Only uploader of image is able to update image.",
                        status=403)

                if not image.unserialize(obj):
                    return json_error(
                        "Invalid 'image' with id '{0}'".format(obj_id))
                image.generate_slug()
                image.save()

                # Create an update activity
                generator = create_generator(request)
                activity = create_activity(verb="update",
                                           actor=request.user,
                                           obj=image,
                                           generator=generator)

                return json_response(activity.serialize(request))
            elif obj["objectType"] == "person":
                # check this is the same user
                if "id" not in obj or obj["id"] != requested_user.id:
                    return json_error("Incorrect user id, unable to update")

                requested_user.unserialize(obj)
                requested_user.save()

                generator = create_generator(request)
                activity = create_activity(verb="update",
                                           actor=request.user,
                                           obj=requested_user,
                                           generator=generator)

                return json_response(activity.serialize(request))

        elif data["verb"] == "delete":
            obj = data.get("object", None)
            if obj is None:
                return json_error("Could not find 'object' element.")

            if "objectType" not in obj:
                return json_error("No objectType specified.")

            if "id" not in obj:
                return json_error("Object ID has not been specified.")

            # Parse out the object ID
            obj_id = extract_url_arguments(url=obj["id"],
                                           urlmap=request.app.url_map)["id"]

            public_id = request.urlgen("mediagoblin.api.object",
                                       object_type=obj["objectType"],
                                       id=obj_id,
                                       qualified=True)

            if obj.get("objectType", None) == "comment":
                # Find the comment asked for
                comment = TextComment.query.filter_by(
                    public_id=public_id, actor=request.user.id).first()

                if comment is None:
                    return json_error(
                        "No such 'comment' with id '{0}'.".format(obj_id))

                # Make a delete activity
                generator = create_generator(request)
                activity = create_activity(verb="delete",
                                           actor=request.user,
                                           obj=comment,
                                           generator=generator)

                # Unfortunately this has to be done while hard deletion exists
                context = activity.serialize(request)

                # now we can delete the comment
                comment.delete()

                return json_response(context)

            if obj.get("objectType", None) == "image":
                # Find the image
                entry = MediaEntry.query.filter_by(
                    public_id=public_id, actor=request.user.id).first()

                if entry is None:
                    return json_error(
                        "No such 'image' with id '{0}'.".format(obj_id))

                # Make the delete activity
                generator = create_generator(request)
                activity = create_activity(verb="delete",
                                           actor=request.user,
                                           obj=entry,
                                           generator=generator)

                # This is because we have hard deletion
                context = activity.serialize(request)

                # Now we can delete the image
                entry.delete()

                return json_response(context)

    elif request.method != "GET":
        return json_error("Unsupported HTTP method {0}".format(request.method),
                          status=501)

    feed = {
        "displayName":
        "Activities by {user}@{host}".format(user=request.user.username,
                                             host=request.host),
        "objectTypes": ["activity"],
        "url":
        request.base_url,
        "links": {
            "self": {
                "href": request.url
            }
        },
        "author":
        request.user.serialize(request),
        "items": [],
    }

    # Create outbox
    if outbox is None:
        outbox = Activity.query.filter_by(actor=requested_user.id)
    else:
        outbox = outbox.filter_by(actor=requested_user.id)

    # We want the newest things at the top (issue: #1055)
    outbox = outbox.order_by(Activity.published.desc())

    # Limit by the "count" (default: 20)
    limit = request.args.get("count", 20)

    try:
        limit = int(limit)
    except ValueError:
        limit = 20

    # The upper most limit should be 200
    limit = limit if limit < 200 else 200

    # apply the limit
    outbox = outbox.limit(limit)

    # Offset (default: no offset - first <count>  result)
    offset = request.args.get("offset", 0)
    try:
        offset = int(offset)
    except ValueError:
        offset = 0
    outbox = outbox.offset(offset)

    # Build feed.
    for activity in outbox:
        try:
            feed["items"].append(activity.serialize(request))
        except AttributeError:
            # This occurs because of how we hard-deletion and the object
            # no longer existing anymore. We want to keep the Activity
            # in case someone wishes to look it up but we shouldn't display
            # it in the feed.
            pass
    feed["totalItems"] = len(feed["items"])

    return json_response(feed)
Exemplo n.º 52
0
def client_register(request):
    """ Endpoint for client registration """
    try:
        data = decode_request(request)
    except ValueError:
        error = "Could not decode data."
        return json_response({"error": error}, status=400)

    if data is "":
        error = "Unknown Content-Type"
        return json_response({"error": error}, status=400)

    if "type" not in data:
        error = "No registration type provided."
        return json_response({"error": error}, status=400)
    if data.get("application_type", None) not in CLIENT_TYPES:
        error = "Unknown application_type."
        return json_response({"error": error}, status=400)

    client_type = data["type"]

    if client_type == "client_update":
        # updating a client
        if "client_id" not in data:
            error = "client_id is requried to update."
            return json_response({"error": error}, status=400)
        elif "client_secret" not in data:
            error = "client_secret is required to update."
            return json_response({"error": error}, status=400)

        client = Client.query.filter_by(id=data["client_id"],
                                        secret=data["client_secret"]).first()

        if client is None:
            error = "Unauthorized."
            return json_response({"error": error}, status=403)

        client.application_name = data.get("application_name",
                                           client.application_name)

        client.application_type = data.get("application_type",
                                           client.application_type)

        app_name = ("application_type", client.application_name)
        if app_name in CLIENT_TYPES:
            client.application_name = app_name

    elif client_type == "client_associate":
        # registering
        if "client_id" in data:
            error = "Only set client_id for update."
            return json_response({"error": error}, status=400)
        elif "access_token" in data:
            error = "access_token not needed for registration."
            return json_response({"error": error}, status=400)
        elif "client_secret" in data:
            error = "Only set client_secret for update."
            return json_response({"error": error}, status=400)

        # generate the client_id and client_secret
        client_id = random_string(22, UNICODE_ASCII_CHARACTER_SET)
        client_secret = random_string(43, UNICODE_ASCII_CHARACTER_SET)
        expirey = 0  # for now, lets not have it expire
        expirey_db = None if expirey == 0 else expirey
        application_type = data["application_type"]

        # save it
        client = Client(
            id=client_id,
            secret=client_secret,
            expirey=expirey_db,
            application_type=application_type,
        )

    else:
        error = "Invalid registration type"
        return json_response({"error": error}, status=400)

    logo_uri = data.get("logo_uri", client.logo_url)
    if logo_uri is not None and not validate_url(logo_uri):
        error = "Logo URI {0} is not a valid URI.".format(logo_uri)
        return json_response({"error": error}, status=400)
    else:
        client.logo_url = logo_uri

    client.application_name = data.get("application_name", None)

    contacts = data.get("contacts", None)
    if contacts is not None:
        if not isinstance(contacts, six.text_type):
            error = "Contacts must be a string of space-seporated email addresses."
            return json_response({"error": error}, status=400)

        contacts = contacts.split()
        for contact in contacts:
            if not validate_email(contact):
                # not a valid email
                error = "Email {0} is not a valid email.".format(contact)
                return json_response({"error": error}, status=400)

        client.contacts = contacts

    redirect_uris = data.get("redirect_uris", None)
    if redirect_uris is not None:
        if not isinstance(redirect_uris, six.text_type):
            error = "redirect_uris must be space-seporated URLs."
            return json_response({"error": error}, status=400)

        redirect_uris = redirect_uris.split()

        for uri in redirect_uris:
            if not validate_url(uri):
                # not a valid uri
                error = "URI {0} is not a valid URI".format(uri)
                return json_response({"error": error}, status=400)

        client.redirect_uri = redirect_uris

    client.save()

    expirey = 0 if client.expirey is None else client.expirey

    return json_response({
        "client_id": client.id,
        "client_secret": client.secret,
        "expires_at": expirey,
    })
Exemplo n.º 53
0
def access_token(request):
    '''
    Access token endpoint provides access tokens to any clients that have the
    right grants/credentials
    '''

    client = None
    user = None

    if request.GET.get('code'):
        # Validate the code arg, then get the client object from the db.
        code = OAuthCode.query.filter(OAuthCode.code ==
                request.GET.get('code')).first()

        if not code:
            return json_response({
                'error': 'invalid_request',
                'error_description':
                    'Invalid code.'})

        client = code.client
        user = code.user

    elif request.args.get('refresh_token'):
        # Validate a refresh token, then get the client object from the db.
        refresh_token = OAuthRefreshToken.query.filter(
            OAuthRefreshToken.token ==
            request.args.get('refresh_token')).first()

        if not refresh_token:
            return json_response({
                'error': 'invalid_request',
                'error_description':
                    'Invalid refresh token.'})

        client = refresh_token.client
        user = refresh_token.user

    if client:
        client_identifier = request.GET.get('client_id')

        if not client_identifier:
            return json_response({
                'error': 'invalid_request',
                'error_description':
                    'Missing client_id in request.'})

        if not client_identifier == client.identifier:
            return json_response({
                'error': 'invalid_client',
                'error_description':
                    'Mismatching client credentials.'})

        if client.type == u'confidential':
            client_secret = request.GET.get('client_secret')

            if not client_secret:
                return json_response({
                    'error': 'invalid_request',
                    'error_description':
                        'Missing client_secret in request.'})

            if not client_secret == client.secret:
                return json_response({
                    'error': 'invalid_client',
                    'error_description':
                        'Mismatching client credentials.'})


        access_token_data = create_token(client, user)

        return json_response(access_token_data, _disable_cors=True)

    return json_response({
        'error': 'invalid_request',
        'error_description':
            'Missing `code` or `refresh_token` parameter in request.'})
Exemplo n.º 54
0
def feed(request):
    """ Handles the user's outbox - /api/user/<username>/feed """
    user = request.matchdict["username"]
    requested_user = User.query.filter_by(username=user).first()

    # check if the user exists
    if requested_user is None:
        return json_error("No such 'user' with id '{0}'".format(user), 404)

    if request.data:
        data = json.loads(request.data)
    else:
        data = {"verb": None, "object": {}}

    # We need to check that the user they're posting to is
    # the person that they are.
    if request.method in ["POST", "PUT"] and \
        requested_user.id != request.user.id:
        
        return json_error(
            "Not able to post to another users feed.",
            status=403
        )

    if request.method == "POST" and data["verb"] == "post":
        obj = data.get("object", None)
        if obj is None:
            return json_error("Could not find 'object' element.")

        if obj.get("objectType", None) == "comment":
            # post a comment
            if not request.user.has_privilege(u'commenter'):
                return json_error(
                    "Privilege 'commenter' required to comment.",
                    status=403
                )

            comment = MediaComment(author=request.user.id)
            comment.unserialize(data["object"])
            comment.save()
            data = {"verb": "post", "object": comment.serialize(request)}
            return json_response(data)

        elif obj.get("objectType", None) == "image":
            # Posting an image to the feed
            media_id = int(data["object"]["id"])
            media = MediaEntry.query.filter_by(id=media_id).first()
            if media is None:
                return json_response(
                    "No such 'image' with id '{0}'".format(id=media_id),
                    status=404
                )

            if not media.unserialize(data["object"]):
                return json_error(
                    "Invalid 'image' with id '{0}'".format(media_id)
                )

            media.save()
            api_add_to_feed(request, media)

            return json_response({
                "verb": "post",
                "object": media.serialize(request)
            })

        elif obj.get("objectType", None) is None:
            # They need to tell us what type of object they're giving us.
            return json_error("No objectType specified.")
        else:
            # Oh no! We don't know about this type of object (yet)
            object_type = obj.get("objectType", None)
            return json_error("Unknown object type '{0}'.".format(object_type))

    elif request.method in ["PUT", "POST"] and data["verb"] == "update":
        # Check we've got a valid object
        obj = data.get("object", None)

        if obj is None:
            return json_error("Could not find 'object' element.")

        if "objectType" not in obj:
            return json_error("No objectType specified.")

        if "id" not in obj:
            return json_error("Object ID has not been specified.")

        obj_id = obj["id"]

        # Now try and find object
        if obj["objectType"] == "comment":
            if not request.user.has_privilege(u'commenter'):
                return json_error(
                    "Privilege 'commenter' required to comment.",
                    status=403
                )

            comment = MediaComment.query.filter_by(id=obj_id).first()
            if comment is None:
                return json_error(
                    "No such 'comment' with id '{0}'.".format(obj_id)
                )

            # Check that the person trying to update the comment is
            # the author of the comment.
            if comment.author != request.user.id:
                return json_error(
                    "Only author of comment is able to update comment.",
                    status=403
                )

            if not comment.unserialize(data["object"]):
                return json_error(
                    "Invalid 'comment' with id '{0}'".format(obj_id)
                )

            comment.save()

            activity = {
                "verb": "update",
                "object": comment.serialize(request),
            }
            return json_response(activity)

        elif obj["objectType"] == "image":
            image = MediaEntry.query.filter_by(id=obj_id).first()
            if image is None:
                return json_error(
                    "No such 'image' with the id '{0}'.".format(obj_id)
                )

            # Check that the person trying to update the comment is
            # the author of the comment.
            if image.uploader != request.user.id:
                return json_error(
                    "Only uploader of image is able to update image.",
                    status=403
                )

            if not image.unserialize(obj):
                return json_error(
                    "Invalid 'image' with id '{0}'".format(obj_id)
                )
            image.save()

            activity = {
                "verb": "update",
                "object": image.serialize(request),
            }
            return json_response(activity)

    elif request.method != "GET":
        return json_error(
            "Unsupported HTTP method {0}".format(request.method),
            status=501
        )

    feed_url = request.urlgen(
        "mediagoblin.federation.feed",
        username=request.user.username,
        qualified=True
    )

    feed = {
        "displayName": "Activities by {user}@{host}".format(
            user=request.user.username,
            host=request.host
        ),
        "objectTypes": ["activity"],
        "url": feed_url,
        "links": {
            "first": {
                "href": feed_url,
            },
            "self": {
                "href": request.url,
            },
            "prev": {
                "href": feed_url,
            },
            "next": {
                "href": feed_url,
            }
        },
        "author": request.user.serialize(request),
        "items": [],
    }


    # Look up all the media to put in the feed (this will be changed
    # when we get real feeds/inboxes/outboxes/activites)
    for media in MediaEntry.query.all():
        item = {
            "verb": "post",
            "object": media.serialize(request),
            "actor": request.user.serialize(request),
            "content": "{0} posted a picture".format(request.user.username),
            "id": 1,
        }
        item["updated"] = item["object"]["updated"]
        item["published"] = item["object"]["published"]
        item["url"] = item["object"]["url"]
        feed["items"].append(item)
    feed["totalItems"] = len(feed["items"])

    return json_response(feed)
Exemplo n.º 55
0
def inbox_endpoint(request, inbox=None):
    """ This is the user's inbox

    Currently because we don't have the ability to represent the inbox in the
    database this is not a "real" inbox in the pump.io/Activity streams 1.0
    sense but instead just gives back all the data on the website

    inbox: allows you to pass a query in to limit inbox scope
    """
    username = request.matchdict["username"]
    user = LocalUser.query.filter(LocalUser.username == username).first()

    if user is None:
        return json_error("No such 'user' with id '{0}'".format(username), 404)

    # Only the user who's authorized should be able to read their inbox
    if user.id != request.user.id:
        return json_error(
            "Only '{0}' can read this inbox.".format(user.username), 403)

    if inbox is None:
        inbox = Activity.query

    # Count how many items for the "totalItems" field
    total_items = inbox.count()

    # We want to make a query for all media on the site and then apply GET
    # limits where we can.
    inbox = inbox.order_by(Activity.published.desc())

    # Limit by the "count" (default: 20)
    try:
        limit = int(request.args.get("count", 20))
    except ValueError:
        limit = 20

    # Prevent the count being too big (pump uses 200 so we shall)
    limit = limit if limit <= 200 else 200

    # Apply the limit
    inbox = inbox.limit(limit)

    # Offset (default: no offset - first <count> results)
    inbox = inbox.offset(request.args.get("offset", 0))

    # build the inbox feed
    feed = {
        "displayName": "Activities for {0}".format(user.username),
        "author": user.serialize(request),
        "objectTypes": ["activity"],
        "url": request.base_url,
        "links": {
            "self": {
                "href": request.url
            }
        },
        "items": [],
        "totalItems": total_items,
    }

    for activity in inbox:
        try:
            feed["items"].append(activity.serialize(request))
        except AttributeError:
            # As with the feed endpint this occurs because of how we our
            # hard-deletion method. Some activites might exist where the
            # Activity object and/or target no longer exist, for this case we
            # should just skip them.
            pass

    return json_response(feed)