Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import secrets
- from datetime import datetime, timedelta
- from typing import Optional
- from flask import flash
- from flask_login import UserMixin
- from flask_sqlalchemy import SQLAlchemy
- from itsdangerous.url_safe import URLSafeTimedSerializer
- from sqlalchemy import ForeignKey, Integer, String
- from sqlalchemy.orm import Mapped, mapped_column, relationship
- from app.auth.models import User
- db = SQLAlchemy()
- # class/db in password reset token route
- class RouteToken(UserMixin, db.Model):
- '''
- One to One relationship between 1 table.
- The One relationship is User and the other 1 relationship is route_token.
- '''
- # The difference between token and emailed_token is that token is used in a route and emailed_token is used in a form
- id: Mapped[int] = mapped_column(primary_key=True)
- # Here is the token in the route like '.../rfjh9qoj#HH#F'
- token: Mapped[Optional[str]] = mapped_column(String())
- # The columns below store the token from short 6 char token before inputted in the form
- emailed_token: Mapped[Optional[str]] = mapped_column(String())
- time_token_expired: Mapped[Optional[datetime]] = mapped_column(index=True)
- attempts_token_tried: Mapped[int] = mapped_column(Integer, default=0)
- # The "One" relationship/connection between the User table + FK.
- fk_user_id: Mapped["int"] = mapped_column(ForeignKey('user.id'))
- rel_user_routetoken: Mapped["User"] = relationship(back_populates='rel_route_token')
- # The 3 methods below are added to the columns email_token + time_token_expired + attempts_token_tried in the User and RouteToken table.
- # And the 3 methods are used in the function send_registration_token_email + send_password_reset_token_email that sends an email.
- # This method contains the token in the email
- def create_emailed_token_db(self):
- '''create the 6 char token for the form and add it to the db'''
- created_emailed_token = secrets.token_hex(3)
- self.emailed_token = created_emailed_token
- db.session.commit()
- def count_attempts_token_tried(self):
- self.attempts_token_tried += 1
- db.session.commit()
- # flash(user_db.attempts_token_tried ) # remove after testing.
- # now is added because of pytest + now represents the current time
- def create_time_token_db(self, now):
- '''create the time the token lasts/expires and add it to the db'''
- current_time = now
- # add time_token_expired
- thirty_min = timedelta(minutes=30)
- current_time_plus_30_minutes = current_time + thirty_min
- self.time_token_expired = current_time_plus_30_minutes
- db.session.commit()
- # add description of methods here
- # now is added because of pytest + now represents the current time
- def check_expired_token(self, now):
- '''
- The method checks 2 things. It checks if the token has exceeded 30 min and the maximum emails has not been exceeded.
- If the time has exceeded 30 min or it has not exceeded 5 emails it makes the token received in the email as 0 and makes the time of the token lasts to 0.
- This happens because I want a new token and a I have 30 min to use the new token.
- '''
- time_token_expired_db = self.time_token_expired
- current_time = now
- # current 12:00
- # expired token 12 33
- # ex token created at 9:33pm and token expires at 9:30pm.
- # Wait until the token expires to let the user get more emails.
- # needed "attempts_token_tried_db <= 5"?
- if current_time > time_token_expired_db and self.attempts_token_tried <= 5:
- # should I just create a new function for pytest?
- self.emailed_token = None
- self.time_token_expired = None
- db.session.commit()
- # only works during pytest
- print('check_expired_token, success')
- flash('Your token has expired. Please click resend email for a new email.')
- # now is added because of pytest + now represents the current time
- # is this secure?
- def wait_max_thirty_min_for_new_token(self, now):
- '''
- Wait a max of 30 min before getting the last emailed token.
- This only happens when creating the last token.
- '''
- time_token_expired_db = self.time_token_expired
- # executes at 9:00 <= 9:30pm
- current_time = now
- if self.attempts_token_tried >= 5 and current_time <= time_token_expired_db:
- # only works duringb pytest
- print('wait_max_thirty_min_for_new_token, success')
- # create times for the created token + expired token
- # better wording.
- flash('You have requested to many tokens. Please wait 30 minutes for a new token from when you recieved youe last token.')
- # is this secure?
- return 'will redirect to email_login_confirmation route'
- # now is added because of pytest + now represents the current time
- # is this secure?
- def reset_attempts_token_tried_to_0(route_token_db, now):
- '''
- if the max attempts of the token tried is exceeded + the
- token is expired reset the attwempts_token_tried to 0.
- '''
- # why doesn't work
- time_token_expired_db = route_token_db.time_token_expired
- # executes at 9:00 <= 9:30pm
- current_time = now
- if route_token_db.attempts_token_tried >= 5 and current_time >= time_token_expired_db:
- # should I just create a new function for pytest?
- route_token_db.emailed_token = None
- route_token_db.time_token_expired = None
- route_token_db.attempts_token_tried = 0
- db.session.commit()
- # change to print
- flash('You have waited long enough for a new a token. Please login again and you will be sent a email with instructions before you can login.')
- # redirect to login so I won't redirect /resend_token/<username_db> click on the link and a email is sent automatically.
- # is this secure?
- return 'going to redirect to login'
- def __repr__(self):
- return '<User {}>'.format(self.username)
- # Creates the token for the route for example .../route_token = .../485748tyhtg5
- @staticmethod
- def create_route_token(user_db):
- '''Uses "user_db" for the User's id'''
- SECRET_KEY = 'temp_secret_key'
- serializer = URLSafeTimedSerializer(SECRET_KEY)
- # random number
- data_to_serialize = {'user_id': user_db.id}
- print(f'data_to_serialize={data_to_serialize['user_id']}')
- # 30 minutes
- token = serializer.dumps(data_to_serialize)
- return token
- # check if the token exceeds 30 min and expires
- def check_expired_route_token(self):
- '''
- If the route_token expired make it False else True.
- Uses "user_db" for the User's id
- '''
- SECRET_KEY = 'temp_secret_key'
- serializer = URLSafeTimedSerializer(SECRET_KEY)
- try:
- serializer.loads(self.token, max_age=1800)
- except Exception:
- return False
- print('The token works')
- return True
- def __repr__(self):
- return '<User {}>'.format(self.email)
Advertisement
Add Comment
Please, Sign In to add comment