Skip to content

Commit e8c036b

Browse files
committed
add badsignature flask examples
1 parent bcac792 commit e8c036b

File tree

4 files changed

+246
-1
lines changed

4 files changed

+246
-1
lines changed
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
title: flask.sessions BadSignature code examples
2+
category: page
3+
slug: flask-sessions-badsignature-examples
4+
sortorder: 500021000
5+
toc: False
6+
sidebartitle: flask.sessions BadSignature
7+
meta: Python example code for the BadSignature class from the flask.sessions module of the Flask project.
8+
9+
10+
BadSignature is a class within the flask.sessions module of the Flask project.
11+
12+
13+
## Example 1 from FlaskBB
14+
[FlaskBB](https://github.com/flaskbb/flaskbb)
15+
([project website](https://flaskbb.org/)) is a [Flask](/flask.html)-based
16+
forum web application. The web app allows users to chat in an open
17+
message board or send private messages in plain text or
18+
[Markdown](/markdown.html).
19+
20+
FlaskBB is provided as open source
21+
[under this license](https://github.com/flaskbb/flaskbb/blob/master/LICENSE).
22+
23+
[**FlaskBB / flaskbb / tokens / serializer.py**](https://github.com/flaskbb/flaskbb/blob/master/flaskbb/tokens/serializer.py)
24+
25+
```python
26+
# serializer.py
27+
# -*- coding: utf -*-
28+
"""
29+
flaskbb.tokens.serializer
30+
-------------------------
31+
32+
:copyright: (c) 2018 the FlaskBB Team.
33+
:license: BSD, see LICENSE for more details
34+
"""
35+
36+
from datetime import timedelta
37+
38+
~~from itsdangerous import (BadData, BadSignature, SignatureExpired,
39+
TimedJSONWebSignatureSerializer)
40+
41+
from ..core import tokens
42+
43+
44+
_DEFAULT_EXPIRY = timedelta(hours=1)
45+
46+
47+
class FlaskBBTokenSerializer(tokens.TokenSerializer):
48+
"""
49+
Default token serializer for FlaskBB. Generates JWTs
50+
that are time sensitive. By default they will expire after
51+
1 hour.
52+
53+
It creates tokens from flaskbb.core.tokens.Token instances
54+
and creates instances of that class when loading tokens.
55+
56+
When loading a token, if an error occurs related to the
57+
token itself, a flaskbb.core.tokens.TokenError will be
58+
raised. Exceptions not caused by parsing the token
59+
are simply propagated.
60+
61+
:str secret_key: The secret key used to sign the tokens
62+
:timedelta expiry: Expiration of tokens
63+
64+
65+
## ... source file abbreviated to get to BadSignature examples ...
66+
67+
68+
'op': token.operation,
69+
}
70+
)
71+
72+
def loads(self, raw_token):
73+
"""
74+
Transforms a JWT into a flaskbb.core.tokens.Token.
75+
76+
If a token is invalid due to it being malformed,
77+
tampered with or expired, a flaskbb.core.tokens.TokenError
78+
is raised. Errors not related to token parsing are
79+
simply propagated.
80+
81+
:str raw_token: JWT to be parsed
82+
:returns flaskbb.core.tokens.Token: Parsed token
83+
"""
84+
try:
85+
parsed = self._serializer.loads(raw_token)
86+
except SignatureExpired:
87+
raise tokens.TokenError.expired()
88+
~~ except BadSignature: # pragma: no branch
89+
raise tokens.TokenError.invalid()
90+
# ideally we never end up here as BadSignature should
91+
# catch everything else, however since this is the root
92+
# exception for itsdangerous we'll catch it down and
93+
# and re-raise our own
94+
except BadData: # pragma: no cover
95+
raise tokens.TokenError.bad()
96+
else:
97+
return tokens.Token(user_id=parsed['id'], operation=parsed['op'])
98+
99+
100+
## ... source file continues with no further BadSignature examples...
101+
102+
103+
```
104+
105+
106+
## Example 2 from flask-base
107+
[flask-base](https://github.com/hack4impact/flask-base)
108+
([project documentation](http://hack4impact.github.io/flask-base/))
109+
provides boilerplate code for new [Flask](/flask.html) web apps.
110+
The purpose of the boilerplate is to stitch together disparate
111+
libraries that are commonly used in Flask projects, such as
112+
[Redis](/redis.html) for fast caching and transient data storage,
113+
[SendGrid](https://www.twilio.com/sendgrid) for transactional email,
114+
[SQLAlchemy](/sqlalchemy.html) for persistent data storage through a
115+
[relational database](/databases.html) backend,
116+
[Flask-WTF](https://flask-wtf.readthedocs.io/en/stable/) for form
117+
handling and many others.
118+
119+
flask-base is provided as open source under the
120+
[MIT license](https://github.com/hack4impact/flask-base/blob/master/LICENSE.md).
121+
122+
[**flask-base / app / models / user.py**](https://github.com/hack4impact/flask-base/blob/master/app/models/user.py)
123+
124+
```python
125+
# user.py
126+
from flask import current_app
127+
from flask_login import AnonymousUserMixin, UserMixin
128+
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
129+
~~from itsdangerous import BadSignature, SignatureExpired
130+
from werkzeug.security import check_password_hash, generate_password_hash
131+
132+
from .. import db, login_manager
133+
134+
135+
class Permission:
136+
GENERAL = 0x01
137+
ADMINISTER = 0xff
138+
139+
140+
class Role(db.Model):
141+
__tablename__ = 'roles'
142+
id = db.Column(db.Integer, primary_key=True)
143+
name = db.Column(db.String(64), unique=True)
144+
index = db.Column(db.String(64))
145+
default = db.Column(db.Boolean, default=False, index=True)
146+
permissions = db.Column(db.Integer)
147+
users = db.relationship('User', backref='role', lazy='dynamic')
148+
149+
@staticmethod
150+
def insert_roles():
151+
roles = {
152+
'User': (Permission.GENERAL, 'main', True),
153+
'Administrator': (
154+
155+
156+
## ... source file abbreviated to get to BadSignature examples ...
157+
158+
159+
s = Serializer(current_app.config['SECRET_KEY'], expiration)
160+
return s.dumps({'confirm': self.id})
161+
162+
def generate_email_change_token(self, new_email, expiration=3600):
163+
"""Generate an email change token to email an existing user."""
164+
s = Serializer(current_app.config['SECRET_KEY'], expiration)
165+
return s.dumps({'change_email': self.id, 'new_email': new_email})
166+
167+
def generate_password_reset_token(self, expiration=3600):
168+
"""
169+
Generate a password reset change token to email to an existing user.
170+
"""
171+
s = Serializer(current_app.config['SECRET_KEY'], expiration)
172+
return s.dumps({'reset': self.id})
173+
174+
def confirm_account(self, token):
175+
"""Verify that the provided token is for this user's id."""
176+
s = Serializer(current_app.config['SECRET_KEY'])
177+
try:
178+
data = s.loads(token)
179+
~~ except (BadSignature, SignatureExpired):
180+
return False
181+
if data.get('confirm') != self.id:
182+
return False
183+
self.confirmed = True
184+
db.session.add(self)
185+
db.session.commit()
186+
return True
187+
188+
def change_email(self, token):
189+
"""Verify the new email for this user."""
190+
s = Serializer(current_app.config['SECRET_KEY'])
191+
try:
192+
data = s.loads(token)
193+
~~ except (BadSignature, SignatureExpired):
194+
return False
195+
if data.get('change_email') != self.id:
196+
return False
197+
new_email = data.get('new_email')
198+
if new_email is None:
199+
return False
200+
if self.query.filter_by(email=new_email).first() is not None:
201+
return False
202+
self.email = new_email
203+
db.session.add(self)
204+
db.session.commit()
205+
return True
206+
207+
def reset_password(self, token, new_password):
208+
"""Verify the new password for this user."""
209+
s = Serializer(current_app.config['SECRET_KEY'])
210+
try:
211+
data = s.loads(token)
212+
~~ except (BadSignature, SignatureExpired):
213+
return False
214+
if data.get('reset') != self.id:
215+
return False
216+
self.password = new_password
217+
db.session.add(self)
218+
db.session.commit()
219+
return True
220+
221+
@staticmethod
222+
def generate_fake(count=100, **kwargs):
223+
"""Generate a number of fake users for testing."""
224+
from sqlalchemy.exc import IntegrityError
225+
from random import seed, choice
226+
from faker import Faker
227+
228+
fake = Faker()
229+
roles = Role.query.all()
230+
231+
seed()
232+
for i in range(count):
233+
u = User(
234+
first_name=fake.first_name(),
235+
last_name=fake.last_name(),
236+
email=fake.email(),
237+
238+
239+
## ... source file continues with no further BadSignature examples...
240+
241+
242+
```
243+

content/pages/examples/flask/flask-sessions-sessioninterface.markdown

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
title: flask.sessions SessionInterface code examples
22
category: page
33
slug: flask-sessions-sessioninterface-examples
4-
sortorder: 500021000
4+
sortorder: 500021001
55
toc: False
66
sidebartitle: flask.sessions SessionInterface
77
meta: Python example code for the SessionInterface class from the flask.sessions module of the Flask project.

content/pages/meta/00-change-log.markdown

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ on GitHub.
2020
* flask.ctx [has_app_context](/flask-ctx-has-app-context-examples.html) and
2121
[has_request_context](/flask-ctx-has-request-context-examples.html)
2222
* flask.globals [current_app](/flask-globals-current-app-examples.html)
23+
* flask.sessions [BadSignature](/flask-sessions-badsignature-examples.html)
2324

2425
### May
2526
* Added new example code pages for Flask modules:

theme/templates/code-examples/flask.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ <h4 class="bp">flask.json.tag
3939
<h4 class="bp">flask.logging
4040
</h4>
4141
<h4 class="bp">flask.sessions
42+
<a href="/flask-sessions-badsignature-examples.html">BadSignature</a>,
4243
<a href="/flask-sessions-sessioninterface-examples.html">SessionInterface</a>
4344
</h4>
4445
<h4 class="bp">flask.signals

0 commit comments

Comments
 (0)