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
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])
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()})
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)
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
def put_type(mtype, user): raise ApiError(status=403) mtype = MimetypeType.get_or_create(id=mtype.lower()) return ApiResponse(status=204)
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())
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], })
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())