replace encrypted cookies with proper session tokens

This commit is contained in:
codl 2017-07-27 01:17:28 +02:00
parent 4c134b75f5
commit 7c38270223
No known key found for this signature in database
GPG Key ID: 6CD7C8891ED1233A
5 changed files with 92 additions and 31 deletions

View File

@ -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"

View File

@ -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 ###

View File

@ -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')

View File

@ -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'))

View File

@ -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 %}