def login(): username = '' password = '' next_url = '' login_error = '' next_url_default = internal_url_for('browse') if request.method == 'POST': try: # Get parameters username = request.form.get('username', '') password = request.form.get('password', '') next_url = request.form.get('next', '') if not password: login_error = 'You must enter your password' if not username: login_error = 'You must enter your username' if not login_error: # Log in user = authenticate_user(username, password, data_engine, logger) if user is not None: if user.status == User.STATUS_ACTIVE: # Success log_in(user) return redirect(next_url or next_url_default) else: login_error = 'Sorry, your account is disabled.' else: login_error = '''Sorry, your username and password were not recognised. Please try again.''' # Slow down scripted attacks logger.warn('Incorrect login for username ' + username) sleep(1) except Exception as e: if not log_security_error(e, request): logger.error('Error performing login: '******'DEBUG']: raise login_error = 'Sorry, an error occurred. Please try again later.' else: # If already logged in, go to the default page if logged_in(): next_url = request.args.get('next', '') return redirect(next_url or next_url_default) # Not logged in, or unsuccessful login return render_template( 'login.html', username=username, next=next_url, err_msg=login_error )
def edit(): # Get parameters src = request.args.get('src', '') embed = request.args.get('embed', '') try: # Check parameters if src == '': raise ValueError('No filename was specified.') db_img = auto_sync_file(src, data_engine, task_engine) if not db_img or db_img.status == Image.STATUS_DELETED: raise DoesNotExistError(src + ' does not exist') # Require edit permission or file admin permissions_engine.ensure_folder_permitted( db_img.folder, FolderPermission.ACCESS_EDIT, get_session_user() ) return render_template( 'details_edit.html', embed=embed, src=src, db_info=db_img ) except Exception as e: log_security_error(e, request) if app.config['DEBUG']: raise return render_template( 'details_edit.html', embed=embed, src=src, err_msg='The file details cannot be viewed: ' + str(e) )
def folder_browse(): from_path = request.args.get('path', '') show_files = request.args.get('show_files', '') embed = request.args.get('embed', '') msg = request.args.get('msg', '') if from_path == '': from_path = os.path.sep db_session = data_engine.db_get_session() db_committed = False try: # This also checks for path existence folder_list = get_directory_listing(from_path, True) # Auto-populate the folders database db_folder = auto_sync_folder( from_path, data_engine, task_engine, _db_session=db_session ) db_session.commit() db_committed = True # Should never happen if db_folder is None: raise DoesNotExistError(from_path) # Require view permission or file admin permissions_engine.ensure_folder_permitted( db_folder, FolderPermission.ACCESS_VIEW, get_session_user() ) return render_template( 'folder_list.html', formats=image_engine.get_image_formats(), embed=embed, msg=msg, name=filepath_filename(from_path), path=from_path, pathsep=os.path.sep, parent_path=filepath_parent(from_path), folder_list=folder_list, show_files=show_files, db_info=db_folder, db_parent_info=db_folder.parent, STATUS_ACTIVE=Folder.STATUS_ACTIVE ) except Exception as e: log_security_error(e, request) if app.config['DEBUG']: raise return render_template( 'folder_list.html', embed=embed, msg=msg, name=filepath_filename(from_path), path=from_path, err_msg='This folder cannot be viewed: ' + str(e) ) finally: try: if not db_committed: db_session.rollback() finally: db_session.close()
def details(): # Get parameters src = request.args.get('src', '') reset = request.args.get('reset', None) src_path = '' try: # Check parameters if src == '': raise ValueError('No filename was specified.') if reset is not None: reset = parse_boolean(reset) file_disk_info = None file_image_info = None file_geo_info = None db_img = None db_history = None db_image_stats = None (src_path, src_filename) = os.path.split(src) # Require view permission or file admin permissions_engine.ensure_folder_permitted( src_path, FolderPermission.ACCESS_VIEW, get_session_user() ) # Get file info from disk file_disk_info = get_file_info(src) if file_disk_info: # Get EXIF info file_image_info = image_engine.get_image_properties(src, True) # Get geo location if we have the relevant profile fields file_geo_info = get_exif_geo_position(file_image_info) # Reset image if requested, then remove the reset from the URL if reset and file_disk_info: image_engine.reset_image(ImageAttrs(src)) return redirect(internal_url_for('details', src=src)) # Get database info db_session = data_engine.db_get_session() db_commit = False try: db_img = auto_sync_file(src, data_engine, task_engine, _db_session=db_session) if db_img: # Trigger lazy load of history db_history = db_img.history # Get stats stats_day = data_engine.summarise_image_stats( datetime.utcnow() - timedelta(days=1), datetime.utcnow(), db_img.id, _db_session=db_session ) stats_month = data_engine.summarise_image_stats( datetime.utcnow() - timedelta(days=30), datetime.utcnow(), db_img.id, _db_session=db_session ) stats_day = stats_day[0] if len(stats_day) > 0 else \ (0, 0, 0, 0, 0, 0, 0, 0) stats_month = stats_month[0] if len(stats_month) > 0 else \ (0, 0, 0, 0, 0, 0, 0, 0) db_image_stats = { 'day': { 'requests': stats_day[1], 'views': stats_day[2], 'cached_views': stats_day[3], 'downloads': stats_day[4], 'bytes': stats_day[5], 'seconds': stats_day[6], 'max_seconds': stats_day[7] }, 'month': { 'requests': stats_month[1], 'views': stats_month[2], 'cached_views': stats_month[3], 'downloads': stats_month[4], 'bytes': stats_month[5], 'seconds': stats_month[6], 'max_seconds': stats_month[7] } } db_commit = True finally: try: if db_commit: db_session.commit() else: db_session.rollback() finally: db_session.close() return render_template( 'details.html', src=src, path=src_path, filename=src_filename, file_info=file_disk_info, image_info=file_image_info, geo_info=file_geo_info, db_info=db_img, db_history=db_history, db_stats=db_image_stats, STATUS_ACTIVE=Image.STATUS_ACTIVE, ACTION_DELETED=ImageHistory.ACTION_DELETED, ACTION_CREATED=ImageHistory.ACTION_CREATED, ACTION_REPLACED=ImageHistory.ACTION_REPLACED, ACTION_EDITED=ImageHistory.ACTION_EDITED, ACTION_MOVED=ImageHistory.ACTION_MOVED, pathsep=os.path.sep, timezone=get_timezone_code() ) except Exception as e: log_security_error(e, request) if app.config['DEBUG']: raise return render_template( 'details.html', src=src, path=src_path, err_msg='This file cannot be viewed: ' + str(e) )
def browse(): from_path = request.args.get('path', '') if from_path == '': from_path = os.path.sep # #2475 Default this in case of error in get_directory_listing() directory_info = DirectoryInfo(from_path) db_session = data_engine.db_get_session() db_committed = False try: directory_info = get_directory_listing(from_path, True) # Auto-populate the folders database db_folder = auto_sync_folder( from_path, data_engine, task_engine, _db_session=db_session ) db_session.commit() db_committed = True if db_folder is not None: # Require view permission or file admin permissions_engine.ensure_folder_permitted( db_folder, FolderPermission.ACCESS_VIEW, get_session_user() ) # Remember last path for the Browse and Upload menus if directory_info.exists() and db_folder: session['last_browse_path'] = from_path return render_template( 'list.html', formats=image_engine.get_image_formats(), pathsep=os.path.sep, timezone=get_timezone_code(), directory_info=directory_info, folder_name=filepath_filename(from_path), db_info=db_folder, db_parent_info=db_folder.parent if db_folder else None, STATUS_ACTIVE=Folder.STATUS_ACTIVE ) except Exception as e: log_security_error(e, request) if app.config['DEBUG']: raise return render_template( 'list.html', directory_info=directory_info, err_msg='This folder cannot be viewed: ' + str(e) ) finally: try: if not db_committed: db_session.rollback() finally: db_session.close()
def image(): logger.debug(request.method + ' ' + request.url) try: logged_in = session_logged_in() allow_uncache = app.config['BENCHMARKING'] or app.config['DEBUG'] args = request.args # Get URL parameters for the image src = args.get('src', '') page = args.get('page', None) iformat = args.get('format', None) template = args.get('tmp', None) width = args.get('width', None) height = args.get('height', None) halign = args.get('halign', None) valign = args.get('valign', None) autosizefit = args.get('autosizefit', None) rotation = args.get('angle', None) flip = args.get('flip', None) top = args.get('top', None) left = args.get('left', None) bottom = args.get('bottom', None) right = args.get('right', None) autocropfit = args.get('autocropfit', None) fill = args.get('fill', None) quality = args.get('quality', None) sharpen = args.get('sharpen', None) ov_src = args.get('overlay', None) ov_size = args.get('ovsize', None) ov_opacity = args.get('ovopacity', None) ov_pos = args.get('ovpos', None) icc_profile = args.get('icc', None) icc_intent = args.get('intent', None) icc_bpc = args.get('bpc', None) colorspace = args.get('colorspace', None) strip = args.get('strip', None) dpi = args.get('dpi', None) tile = args.get('tile', None) # Get URL parameters for handling options attach = args.get('attach', None) xref = args.get('xref', None) stats = args.get('stats', None) # Get protected admin/internal parameters cache = args.get('cache', '1') if logged_in or allow_uncache else '1' recache = args.get('recache', None) if allow_uncache else None # eRez compatibility mode src = erez_params_compat(src) # Tweak strings as necessary and convert non-string parameters # to the correct data types try: # Image options if page is not None: page = parse_int(page) if iformat is not None: iformat = iformat.lower() if template is not None: template = template.lower() if width is not None: width = parse_int(width) if height is not None: height = parse_int(height) if halign is not None: halign = halign.lower() if valign is not None: valign = valign.lower() if autosizefit is not None: autosizefit = parse_boolean(autosizefit) if rotation is not None: rotation = parse_float(rotation) if flip is not None: flip = flip.lower() if top is not None: top = parse_float(top) if left is not None: left = parse_float(left) if bottom is not None: bottom = parse_float(bottom) if right is not None: right = parse_float(right) if autocropfit is not None: autocropfit = parse_boolean(autocropfit) if fill is not None: fill = parse_colour(fill) if quality is not None: quality = parse_int(quality) if sharpen is not None: sharpen = parse_int(sharpen) if ov_size is not None: ov_size = parse_float(ov_size) if ov_pos is not None: ov_pos = ov_pos.lower() if ov_opacity is not None: ov_opacity = parse_float(ov_opacity) if icc_profile is not None: icc_profile = icc_profile.lower() if icc_intent is not None: icc_intent = icc_intent.lower() if icc_bpc is not None: icc_bpc = parse_boolean(icc_bpc) if colorspace is not None: colorspace = colorspace.lower() if strip is not None: strip = parse_boolean(strip) if dpi is not None: dpi = parse_int(dpi) if tile is not None: tile = parse_tile_spec(tile) # Handling options if attach is not None: attach = parse_boolean(attach) if xref is not None: validate_string(xref, 0, 1024) if stats is not None: stats = parse_boolean(stats) # Admin/internal options if cache is not None: cache = parse_boolean(cache) if recache is not None: recache = parse_boolean(recache) except (ValueError, TypeError) as e: raise httpexc.BadRequest(unicode(e)) # Package and validate the parameters try: # #2694 Enforce public image limits - perform easy parameter checks if not logged_in: width, height, autosizefit = _public_image_limits_pre_image_checks( width, height, autosizefit, tile, template ) # Store and normalise all the parameters image_attrs = ImageAttrs(src, -1, page, iformat, template, width, height, halign, valign, rotation, flip, top, left, bottom, right, autocropfit, autosizefit, fill, quality, sharpen, ov_src, ov_size, ov_pos, ov_opacity, icc_profile, icc_intent, icc_bpc, colorspace, strip, dpi, tile) image_engine.finalise_image_attrs(image_attrs) except ValueError as e: raise httpexc.BadRequest(unicode(e)) # Get/create the database ID (from cache, validating path on create) image_id = data_engine.get_or_create_image_id( image_attrs.filename(), return_deleted=False, on_create=on_image_db_create_anon_history ) if (image_id == 0): raise DoesNotExistError() # Deleted elif (image_id < 0): raise DBError('Failed to add image to database') image_attrs.set_database_id(image_id) # Require view permission or file admin permissions_engine.ensure_folder_permitted( image_attrs.folder_path(), FolderPermission.ACCESS_VIEW, get_session_user() ) # Ditto for overlays if ov_src: permissions_engine.ensure_folder_permitted( filepath_parent(ov_src), FolderPermission.ACCESS_VIEW, get_session_user() ) # v1.17 If this is a conditional request with an ETag, see if we can just return a 304 if 'If-None-Match' in request.headers and not recache: etag_valid, modified_time = _etag_is_valid( image_attrs, request.headers['If-None-Match'], False ) if etag_valid: # Success HTTP 304 return make_304_response(image_attrs, False, modified_time) # Get the requested image data image_wrapper = image_engine.get_image( image_attrs, 'refresh' if recache else cache ) if (image_wrapper is None): raise DoesNotExistError() # #2694 Enforce public image limits - check the dimensions # of images that passed the initial parameter checks if not logged_in: try: _public_image_limits_post_image_checks( image_attrs.width(), image_attrs.height(), image_attrs.template(), image_wrapper.data(), image_wrapper.attrs().format() ) except ValueError as e: raise httpexc.BadRequest(unicode(e)) # As for the pre-check # Success HTTP 200 return make_image_response(image_wrapper, False, stats, attach, xref) except httpexc.HTTPException: # Pass through HTTP 4xx and 5xx raise except ServerTooBusyError: logger.warn(u'503 Too busy for ' + request.url) raise httpexc.ServiceUnavailable() except ImageError as e: logger.warn(u'415 Invalid image file \'' + src + '\' : ' + unicode(e)) raise httpexc.UnsupportedMediaType(unicode(e)) except SecurityError as e: if app.config['DEBUG']: raise log_security_error(e, request) raise httpexc.Forbidden() except DoesNotExistError as e: # First time around the ID will be set. Next time around it # won't but we should check whether the disk file now exists. if image_attrs.database_id() > 0 or path_exists(image_attrs.filename(), require_file=True): image_engine.reset_image(image_attrs) logger.warn(u'404 Not found: ' + unicode(e)) raise httpexc.NotFound(unicode(e)) except Exception as e: if app.config['DEBUG']: raise logger.error(u'500 Error for ' + request.url + '\n' + unicode(e)) raise httpexc.InternalServerError(unicode(e))
def original(): logger.debug('GET ' + request.url) try: # Get URL parameters for the image src = request.args.get('src', '') # Get URL parameters for handling options attach = request.args.get('attach', None) xref = request.args.get('xref', None) stats = request.args.get('stats', None) # Validate the parameters try: if attach is not None: attach = parse_boolean(attach) if xref is not None: validate_string(xref, 0, 1024) if stats is not None: stats = parse_boolean(stats) image_attrs = ImageAttrs(src) image_attrs.validate() except ValueError as e: raise httpexc.BadRequest(unicode(e)) # Get/create the database ID (from cache, validating path on create) image_id = data_engine.get_or_create_image_id( image_attrs.filename(), return_deleted=False, on_create=on_image_db_create_anon_history ) if (image_id == 0): raise DoesNotExistError() # Deleted elif (image_id < 0): raise DBError('Failed to add image to database') image_attrs.set_database_id(image_id) # Require download permission or file admin permissions_engine.ensure_folder_permitted( image_attrs.folder_path(), FolderPermission.ACCESS_DOWNLOAD, get_session_user() ) # v1.17 If this is a conditional request with an ETag, see if we can just return a 304 if 'If-None-Match' in request.headers: etag_valid, modified_time = _etag_is_valid( image_attrs, request.headers['If-None-Match'], True ) if etag_valid: # Success HTTP 304 return make_304_response(image_attrs, True, modified_time) # Read the image file image_wrapper = image_engine.get_image_original( image_attrs ) if (image_wrapper is None): raise DoesNotExistError() # Success HTTP 200 return make_image_response(image_wrapper, True, stats, attach, xref) except httpexc.HTTPException: # Pass through HTTP 4xx and 5xx raise except ServerTooBusyError: logger.warn(u'503 Too busy for ' + request.url) raise httpexc.ServiceUnavailable() except ImageError as e: logger.warn(u'415 Invalid image file \'' + src + '\' : ' + unicode(e)) raise httpexc.UnsupportedMediaType(unicode(e)) except SecurityError as e: if app.config['DEBUG']: raise log_security_error(e, request) raise httpexc.Forbidden() except DoesNotExistError as e: # First time around the ID will be set. Next time around it # won't but we should check whether the disk file now exists. if image_attrs.database_id() > 0 or path_exists(image_attrs.filename(), require_file=True): image_engine.reset_image(image_attrs) logger.warn(u'404 Not found: ' + src) raise httpexc.NotFound(src) except Exception as e: if app.config['DEBUG']: raise logger.error(u'500 Error for ' + request.url + '\n' + unicode(e)) raise httpexc.InternalServerError(unicode(e))