Example #1
0
def on_error(error):
    if not isinstance(error, ApiError):
        print(error)
        print(traceback.print_exc())
        if isinstance(error, HTTPException):
            if 300 <= error.code and error.code < 400:
                return ApiRedirect(error.headers['location'], code=error.code)

            metadata = getattr(error, 'data', None)
            if metadata is not None:
                if 'message' in metadata:
                    metadata['errors'] = metadata.pop('message')
            error = ApiError(status=error.code, metadata=metadata)
        else:
            error = ApiError(str(error), 500)
    return error.response
Example #2
0
def fetch_mimetype_types(mtype):
    mtype = MimetypeType.get_or_none(id=mtype)
    if mtype is None:
        raise ApiError('Unknown Type', status=404)

    mimetypes = Mimetype.select().where(Mimetype.type == mtype)
    extensions = MimetypeExtension.select()
    group = prefetch(mimetypes, extensions)
    return ApiResponse([x.to_dict() for x in group])
Example #3
0
def fetch_me_file_count(args):
    if args.authorization is None and args.fingerprint is None:
        raise ApiError(status=401)

    if args.mimetype is not None and args.type is not None:
        raise ApiError('Choose Mimetype or Type, not both')

    mtype = None
    if args.type is not None:
        mtype = MimetypeType.get_or_none(id=args.type)
        if mtype is None:
            raise ApiError(metadata={'errors': {'type': 'Invalid Type'}})

    mimetype = None
    if args.mimetype is not None:
        mimetype = Mimetype.get_or_none(id=args.mimetype)
        if mimetype is None:
            raise ApiError(
                metadata={'errors': {
                    'mimetype': 'Invalid Mimetype'
                }})

    if args.authorization is not None:
        user = helpers.get_user(args.authorization)
        query = File.select().where(File.user == user)
    else:
        query = File.select().where(File.fingerprint == args.fingerprint)

    if mtype is not None:
        query = (query.join(Mimetype,
                            JOIN.RIGHT_OUTER,
                            on=(Mimetype.id == File.mimetype)).join(
                                MimetypeType,
                                JOIN.RIGHT_OUTER,
                                on=(MimetypeType.id == Mimetype.type)).where(
                                    MimetypeType.id == mtype).switch(File))

    if mimetype is not None:
        query = query.where(File.mimetype == mimetype)

    return ApiResponse({'count': query.count()})
Example #4
0
def put_mimetype(args, mtype, subtype, user):
    raise ApiError(status=403)

    mtype = mtype.lower()
    subtype = subtype.lower()

    if MimetypeType.get_or_none(id=mtype) is None:
        raise ApiError('Unknown Type', status=404)

    defaults = {'type': mtype}
    if args.flags is not None:
        defaults['flags'] = args.flags

    mimetype = Mimetype.get_or_none(id='{}/{}'.format(mtype, subtype))
    if mimetype is None:
        mimetype = Mimetype.create(
            id='{}/{}'.format(mtype, subtype),
            flags=args.flags or 0,
            type=mtype,
        )
    else:
        if args.flags is not None:
            mimetype.flags = args.flags
            mimetype.save()

    if args.extension is not None:
        extension = MimetypeExtension.get_or_none(mimetype=mimetype,
                                                  extension=args.extension)
        if extension is None:
            extension = MimetypeExtension.create(
                mimetype=mimetype,
                extension=args.extension,
                priority=args.priority or 0,
            )
        else:
            if args.priority is not None:
                extension.priority = args.priority
                extension.save()

    return ApiResponse(status=204)
Example #5
0
def get_user(token, allow_user=True, allow_bot=False):
    try:
        parsed = parameters.token_authorization(token)
    except:
        raise ApiError(status=401)

    auth_type, user_id, token = parsed
    if auth_type == 'user':
        if not allow_user:
            raise ApiError('Users cannot use this endpoint.', status=401)
        user = User.get_or_none(id=user_id, bot=False)

        min_timestamp = user.last_password_reset.timestamp() - UserToken.epoch
        if not UserToken.validate(token, min_timestamp):
            raise ApiError(status=401)
    elif auth_type == 'bot':
        if not allow_bot:
            raise ApiError('Bots cannot use this endpoint.', status=401)
        raise ApiError('Bots are not supported currently.', status=401)
    else:
        raise ApiError(status=401)
    return user
Example #6
0
def put_type(mtype, user):
    raise ApiError(status=403)

    mtype = MimetypeType.get_or_create(id=mtype.lower())
    return ApiResponse(status=204)
Example #7
0
def fetch_mimetype(mtype, subtype):
    mimetype = Mimetype.get_or_none(id='{}/{}'.format(mtype, subtype))
    if mimetype is None:
        raise ApiError('Unknown Mimetype', status=404)
    return ApiResponse(mimetype.to_dict())
Example #8
0
def fetch_files(args):
    if args.authorization is None and args.fingerprint is None:
        raise ApiError(status=401)

    if args.after is not None and args.before is not None:
        raise ApiError('Choose between before or after, not both')

    if args.mimetype is not None and args.type is not None:
        raise ApiError('Choose Mimetype or Type, not both')

    mtype = None
    if args.type is not None:
        mtype = MimetypeType.get_or_none(id=args.type)
        if mtype is None:
            raise ApiError(metadata={'errors': {'type': 'Invalid Type'}})

    mimetype = None
    if args.mimetype is not None:
        mimetype = Mimetype.get_or_none(id=args.mimetype)
        if mimetype is None:
            raise ApiError(
                metadata={'errors': {
                    'mimetype': 'Invalid Mimetype'
                }})

    files = (File.select(File, FileHash).join(FileHash).switch(File).order_by(
        File.id.desc()).limit(args.limit))
    total = File.select(fn.COUNT(File.id).alias('count'))

    if args.authorization is not None:
        user = helpers.get_user(args.authorization)
        files = files.where(File.user == user)
        total = total.where(File.user == user)
    else:
        files = files.where(File.fingerprint == args.fingerprint)
        total = total.where(File.fingerprint == args.fingerprint)

    if mtype is not None:
        files = (files.join(Mimetype,
                            JOIN.RIGHT_OUTER,
                            on=(Mimetype.id == File.mimetype)).join(
                                MimetypeType,
                                JOIN.RIGHT_OUTER,
                                on=(MimetypeType.id == Mimetype.type)).where(
                                    MimetypeType.id == mtype).switch(File))
        total = (total.join(Mimetype,
                            JOIN.RIGHT_OUTER,
                            on=(Mimetype.id == File.mimetype)).join(
                                MimetypeType,
                                JOIN.RIGHT_OUTER,
                                on=(MimetypeType.id == Mimetype.type)).where(
                                    MimetypeType.id == mtype).switch(File))

    if mimetype is not None:
        files = files.where(File.mimetype == mimetype)
        total = total.where(File.mimetype == mimetype)

    if args.after is not None:
        files = files.where(File.id > args.after)
    elif args.before is not None:
        files = files.where(File.id < args.before)

    return ApiResponse({
        'total': total.scalar(),
        'files': [x.to_dict() for x in files],
    })
Example #9
0
def create_file(args):
    fingerprint = user = None
    if args.authorization is not None:
        try:
            user = helpers.get_user(args.authorization)
        except:
            raise ApiError('Invalid Authentication')

    if args.fingerprint is not None and user is None:
        fingerprint = args.fingerprint

    min_vanity = max_vanity = args.vanity.count('/')
    for part in args.vanity.split('/'):
        minv, maxv = parse_vanity_part(part)
        min_vanity += minv
        max_vanity += maxv

    if min_vanity < MIN_VANITY_LENGTH or MAX_VANITY_LENGTH < max_vanity:
        raise ApiError(
            'Vanity has to be at least or in between {} and {} characters long'
            .format(MIN_VANITY_LENGTH, MAX_VANITY_LENGTH))

    fextension = None
    if args.type == 'multipart':
        storage = next(request.files.values(), None)
        if storage is None:
            raise ApiError('A file must be uploaded')
        if args.filename is None:
            args.filename = storage.filename
        else:
            # get original extension from uploaded file
            # just incase we generate filename in future
            if '.' in storage.filename:
                fextension = storage.filename.split('.')[-1]
        mimetype = storage.mimetype
        stream = storage.stream
        stream.seek(0, 2)
        fsize = stream.tell()
        stream.seek(0)
    elif args.type == 'raw':
        mimetype = request.mimetype
        stream = request.stream
        fsize = request.content_length
    else:
        raise ApiError('Invalid Upload Type')

    #check filesize

    fname = None
    if args.filename is None:
        fname = [generate_vanity()]
    else:
        fname = args.filename.split('.')

    if 1 < len(fname):
        # do we want to use the original filename's extension all the time?
        if fextension is None:
            fextension = fname.pop(-1)
        elif fextension.lower() == fname[-1].lower():
            fextension = fname.pop(-1)

    mime = Mimetype.get_or_none(id=mimetype)
    if mime is None:
        if fextension is None:
            raise InvalidMimetype()
        mextension = MimetypeExtension.get_or_none(
            extension=fextension.lower())
        if mextension is None:
            raise InvalidMimetype()
        # mime = mextension.mime
        mimetype = mextension.mimetype_id
    else:
        # use extension to determine filetype
        if mime.id == 'application/octet-stream':
            if fextension is not None:
                mextension = MimetypeExtension.get_or_none(
                    extension=fextension.lower())
                if mextension is not None:
                    mimetype = mextension.mimetype_id
    # check flags

    if fextension is not None:
        mextension = MimetypeExtension.get_or_none(
            mimetype=mimetype, extension=fextension.lower())
        # keep extension incase its not found
        if mextension is None:
            fname.append(fextension)
            fextension = None
        else:
            # set it to the stored version, just this or fextension.lower()
            fextension = mextension.extension

    if fextension is None:
        mextension = (MimetypeExtension.select().where(
            MimetypeExtension.mimetype == mimetype).order_by(
                MimetypeExtension.priority.desc()).limit(1).execute())
        if mextension:
            fextension = mextension[0].extension
        else:
            if mimetype.endswith('+json'):
                fextension = 'json'
            elif mimetype.endswith('+xml'):
                fextension = 'xml'

    fname = '.'.join(fname)[:256]  # just incase they send a huge text lol
    while '{random}' in fname:
        fname = fname.replace('{random}', generate_vanity(), 1)
    fname = re.sub(FILENAME_REGEX, '_', fname[:128])

    # we read the filedata now to get the hashes of it
    fdata = stream.read(fsize)

    hblake2b = hashlib.blake2b(fdata).hexdigest()
    hmd5 = hashlib.md5(fdata).hexdigest()
    hsha1 = hashlib.sha1(fdata).hexdigest()

    fid = Snowflake.generate()
    fhash = FileHash.get_or_none(blake2b=hblake2b, md5=hmd5, sha1=hsha1)
    if fhash is None:
        fhash = FileHash.create(
            id=Snowflake.generate(),
            blake2b=hblake2b,
            md5=hmd5,
            sha1=hsha1,
            size=fsize,
        )
        # upload it now
        bucket = current_app.gcs.get_bucket(current_app.config.storage_bucket)
        blob = bucket.blob('files/{}'.format(fhash.id))
        blob.upload_from_string(fdata,
                                content_type='application/octet-stream',
                                predefined_acl='publicRead')

    unique = False
    while not unique:
        fvanity = generate_vanity(args.vanity)
        unique = bool(File.get_or_none(vanity=fvanity) is None)

    fobj = File.create(
        id=fid,
        vanity=fvanity,
        mimetype=mimetype,
        extension=fextension,
        filename=fname,
        hash=fhash,
        user=user,
        fingerprint=fingerprint,
    )
    return ApiResponse(fobj.to_dict())