replace encrypted cookies with proper session tokens
This commit is contained in:
parent
4c134b75f5
commit
7c38270223
|
@ -13,18 +13,6 @@ only postgresql with psycopg2 driver is officially supported
|
|||
"""
|
||||
SQLALCHEMY_DATABASE_URI='postgresql+psycopg2:///forget'
|
||||
|
||||
"""
|
||||
SECRET KEY
|
||||
|
||||
this key is used to encrypt session cookies
|
||||
you can generate a random key by running
|
||||
openssl rand -base64 102 | tr -d "\n"; echo
|
||||
or if you don't have openssl installed
|
||||
cat /dev/random | head -c 102 | base64 | tr -d "\n"; echo
|
||||
the latter might take a while if your system entropy is low, give it time
|
||||
"""
|
||||
SECRET_KEY='change me!'
|
||||
|
||||
"""
|
||||
TWITTER CREDENTIALS
|
||||
|
||||
|
@ -35,7 +23,7 @@ TWITTER_CONSUMER_KEY='vdsvdsvds'
|
|||
TWITTER_CONSUMER_SECRET='hjklhjklhjkl'
|
||||
|
||||
"""
|
||||
blablabl
|
||||
this will be necessary so we can tell twitter where to redirect
|
||||
"""
|
||||
SERVER_NAME="localhost:5000"
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: c3faafd828ad
|
||||
Revises:
|
||||
Create Date: 2017-07-27 01:16:34.114238
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'c3faafd828ad'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('accounts',
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
|
||||
sa.Column('remote_id', sa.String(), nullable=False),
|
||||
sa.Column('remote_display_name', sa.String(), nullable=True),
|
||||
sa.Column('remote_avatar_url', sa.String(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('remote_id', name=op.f('pk_accounts'))
|
||||
)
|
||||
op.create_table('oauth_tokens',
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
|
||||
sa.Column('token', sa.String(), nullable=False),
|
||||
sa.Column('token_secret', sa.String(), nullable=False),
|
||||
sa.Column('remote_id', sa.String(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['remote_id'], ['accounts.remote_id'], name=op.f('fk_oauth_tokens_remote_id_accounts')),
|
||||
sa.PrimaryKeyConstraint('token', name=op.f('pk_oauth_tokens'))
|
||||
)
|
||||
op.create_table('sessions',
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
|
||||
sa.Column('id', sa.String(), nullable=False),
|
||||
sa.Column('remote_id', sa.String(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['remote_id'], ['accounts.remote_id'], name=op.f('fk_sessions_remote_id_accounts')),
|
||||
sa.PrimaryKeyConstraint('id', name=op.f('pk_sessions'))
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table('sessions')
|
||||
op.drop_table('oauth_tokens')
|
||||
op.drop_table('accounts')
|
||||
# ### end Alembic commands ###
|
8
model.py
8
model.py
|
@ -3,6 +3,7 @@ from datetime import datetime
|
|||
from app import db
|
||||
|
||||
from twitter import Twitter, OAuth
|
||||
import secrets
|
||||
|
||||
class TimestampMixin(object):
|
||||
created_at = db.Column(db.DateTime, server_default=db.func.now())
|
||||
|
@ -34,3 +35,10 @@ class OAuthToken(db.Model, TimestampMixin):
|
|||
remote_id = db.Column(db.String, db.ForeignKey('accounts.remote_id'))
|
||||
account = db.relationship(Account)
|
||||
|
||||
class Session(db.Model, TimestampMixin):
|
||||
__tablename__ = 'sessions'
|
||||
|
||||
id = db.Column(db.String, primary_key=True, default=lambda: secrets.token_urlsafe())
|
||||
|
||||
remote_id = db.Column(db.String, db.ForeignKey('accounts.remote_id'))
|
||||
account = db.relationship(Account, lazy='joined')
|
||||
|
|
39
routes.py
39
routes.py
|
@ -1,18 +1,27 @@
|
|||
from app import app
|
||||
from flask import render_template, session, url_for, redirect, request
|
||||
from flask import render_template, url_for, redirect, request, g, Response
|
||||
from datetime import datetime
|
||||
import lib.twitter
|
||||
from model import Account
|
||||
from model import Account, Session
|
||||
from app import db
|
||||
|
||||
@app.before_request
|
||||
def load_viewer():
|
||||
g.viewer = None
|
||||
sid = request.cookies.get('forget_sid', None)
|
||||
if sid:
|
||||
g.viewer = Session.query.get(sid)
|
||||
|
||||
@app.after_request
|
||||
def touch_viewer(resp):
|
||||
if g.viewer:
|
||||
g.viewer.touch()
|
||||
db.session.commit()
|
||||
return resp
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
viewer = None
|
||||
if 'remote_id' in session:
|
||||
viewer = Account.query.get(session['remote_id'])
|
||||
viewer.touch()
|
||||
db.session.commit()
|
||||
return render_template('index.html', viewer = viewer)
|
||||
return render_template('index.html')
|
||||
|
||||
@app.route('/login/twitter')
|
||||
def twitter_login_step1():
|
||||
|
@ -26,12 +35,16 @@ def twitter_login_step2():
|
|||
oauth_token = request.args['oauth_token']
|
||||
oauth_verifier = request.args['oauth_verifier']
|
||||
token = lib.twitter.receive_verifier(oauth_token, oauth_verifier, **app.config.get_namespace("TWITTER_"))
|
||||
session['remote_id'] = token.remote_id
|
||||
return redirect(url_for('index'))
|
||||
session = Session(remote_id = token.remote_id)
|
||||
db.session.add(session)
|
||||
db.session.commit()
|
||||
resp = Response(status=301, headers={"location": url_for('index')})
|
||||
resp.set_cookie('forget_sid', session.id)
|
||||
return resp
|
||||
|
||||
@app.route('/logout')
|
||||
def logout():
|
||||
keys = list(session.keys())
|
||||
for key in keys:
|
||||
del session[key]
|
||||
if(g.viewer):
|
||||
db.session.delete(g.viewer)
|
||||
db.session.commit()
|
||||
return redirect(url_for('index'))
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
{% if viewer %}
|
||||
{% if g.viewer %}
|
||||
<p>Hello,
|
||||
<img src="{{viewer.remote_avatar_url}}"/>
|
||||
{{viewer.remote_display_name}}! <a href="/logout">Log out</a></p>
|
||||
<p><code>{{session}}</code></p>
|
||||
<p><code>{{viewer}}</code></p>
|
||||
<img src="{{g.viewer.account.remote_avatar_url}}"/>
|
||||
{{g.viewer.account.remote_display_name}}! <a href="/logout">Log out</a></p>
|
||||
{% else %}
|
||||
<p>Hello, stranger! <a href="/login/twitter">Log in with Twitter</a></p>
|
||||
{% endif %}
|
||||
|
|
Loading…
Reference in New Issue