Last active
October 27, 2016 23:29
-
-
Save TySkby/149af7713805fe76f701d73b7e4199e2 to your computer and use it in GitHub Desktop.
Decorator that ensures a function takes at least X seconds to execute
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Simple decorator that prevents a function from finishing faster than a given number of seconds. | |
Useful if you're fairly confident that your function should finish in a certain amount of time, | |
but you want to make the return time constant (eg. to prevent constant-time attacks). | |
For example, if I know that my password reset function always takes about 1 second to execute | |
if the given email address is valid but if the email address is invalid, it usually finishes much faster, | |
I can ensure that it always takes 2 seconds to execute whenever it's called. | |
The usefulness here goes out the window if your function's normal execution time is subject | |
to a lot of jitter. | |
""" | |
def minimum_time(seconds): | |
def decorator(fn): | |
@wraps(fn) | |
def decorated_function(*args, **kwargs): | |
start = time.time() | |
rv = fn(*args, **kwargs) | |
end = time.time() | |
runtime = end - start | |
if runtime < seconds: | |
time.sleep(seconds - runtime) | |
return rv | |
return decorated_function | |
return decorator | |
# Usage: | |
@minimum_time(2) | |
def request_password_reset(email_address): | |
user = get_user_by_email(email_address) | |
if email_address: | |
# Assume this reliably takes around 1 second to finish | |
send_reset_token_to_user(user) | |
return 'Finished! User has been notified if they are indeed a real user.' | |
# This usually takes around 1 second to finish | |
request_password_reset('[email protected]') | |
# This usually finishes much faster because `send_reset_token_to_user` never gets called | |
request_password_reset('[email protected]') | |
# But now they'll always take 2 seconds! (or more, in which case this is less useful...) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment