From 7c3827022317f2ccd68146e05500e22a3aa106b9 Mon Sep 17 00:00:00 2001 From: codl Date: Thu, 27 Jul 2017 01:17:28 +0200 Subject: [PATCH] replace encrypted cookies with proper session tokens --- config.example.py | 14 +------- migrations/versions/c3faafd828ad_.py | 54 ++++++++++++++++++++++++++++ model.py | 8 +++++ routes.py | 39 +++++++++++++------- templates/index.html | 8 ++--- 5 files changed, 92 insertions(+), 31 deletions(-) create mode 100644 migrations/versions/c3faafd828ad_.py diff --git a/config.example.py b/config.example.py index d9519f0..6d4333c 100644 --- a/config.example.py +++ b/config.example.py @@ -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" diff --git a/migrations/versions/c3faafd828ad_.py b/migrations/versions/c3faafd828ad_.py new file mode 100644 index 0000000..d97b7e5 --- /dev/null +++ b/migrations/versions/c3faafd828ad_.py @@ -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 ### diff --git a/model.py b/model.py index 971e8e7..672e211 100644 --- a/model.py +++ b/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') diff --git a/routes.py b/routes.py index 509fb56..b6120aa 100644 --- a/routes.py +++ b/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')) diff --git a/templates/index.html b/templates/index.html index 7c9ab64..838f99b 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,9 +1,7 @@ -{% if viewer %} +{% if g.viewer %}

Hello, - -{{viewer.remote_display_name}}! Log out

-

{{session}}

-

{{viewer}}

+ +{{g.viewer.account.remote_display_name}}! Log out

{% else %}

Hello, stranger! Log in with Twitter

{% endif %}