54 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			54 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import functools
 | 
						|
import time
 | 
						|
from flask import request, current_app, session
 | 
						|
from flask_restx import abort
 | 
						|
from sqlalchemy.sql import and_
 | 
						|
 | 
						|
from CTFd.models import Challenges
 | 
						|
from CTFd.utils.user import is_admin, get_current_user
 | 
						|
from .utils.cache import CacheProvider
 | 
						|
 | 
						|
 | 
						|
def challenge_visible(func):
 | 
						|
    @functools.wraps(func)
 | 
						|
    def _challenge_visible(*args, **kwargs):
 | 
						|
        challenge_id = request.args.get('challenge_id')
 | 
						|
        if is_admin():
 | 
						|
            if not Challenges.query.filter(
 | 
						|
                Challenges.id == challenge_id
 | 
						|
            ).first():
 | 
						|
                abort(404, 'no such challenge', success=False)
 | 
						|
        else:
 | 
						|
            if not Challenges.query.filter(
 | 
						|
                Challenges.id == challenge_id,
 | 
						|
                and_(Challenges.state != "hidden", Challenges.state != "locked"),
 | 
						|
            ).first():
 | 
						|
                abort(403, 'challenge not visible', success=False)
 | 
						|
        return func(*args, **kwargs)
 | 
						|
 | 
						|
    return _challenge_visible
 | 
						|
 | 
						|
 | 
						|
def frequency_limited(func):
 | 
						|
    @functools.wraps(func)
 | 
						|
    def _frequency_limited(*args, **kwargs):
 | 
						|
        if is_admin():
 | 
						|
            return func(*args, **kwargs)
 | 
						|
        redis_util = CacheProvider(app=current_app, user_id=get_current_user().id)
 | 
						|
        if not redis_util.acquire_lock():
 | 
						|
            abort(403, 'Request Too Fast!', success=False)
 | 
						|
            # last request was unsuccessful. this is for protection.
 | 
						|
 | 
						|
        if "limit" not in session:
 | 
						|
            session["limit"] = int(time.time())
 | 
						|
        else:
 | 
						|
            if int(time.time()) - session["limit"] < 60:
 | 
						|
                abort(403, 'Frequency limit, You should wait at least 1 min.', success=False)
 | 
						|
        session["limit"] = int(time.time())
 | 
						|
 | 
						|
        result = func(*args, **kwargs)
 | 
						|
        redis_util.release_lock()  # if any exception is raised, lock will not be released
 | 
						|
        return result
 | 
						|
 | 
						|
    return _frequency_limited
 |