Skip to content

Instantly share code, notes, and snippets.

@notconfusing
Created January 8, 2019 17:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save notconfusing/460d6ffb6682439ebe6b70b78e7759af to your computer and use it in GitHub Desktop.
Save notconfusing/460d6ffb6682439ebe6b70b78e7759af to your computer and use it in GitHub Desktop.
Send a "thanks" on Wikipedia via OAUTH
# -*- coding: utf-8 -*-
"""Example Flask application which can authenticate the user via OAuth, and send a thank
see for the https://phabricator.wikimedia.org/source/tool-my-first-flask-oauth-tool/ for more of the flask OAUTH details
This file focuses on what's necessary to thank via OAUTH using the mediawiki API."""
import flask
import mwoauth
import os
import werkzeug.contrib.fixers
import yaml
import mwapi
from requests_oauthlib import OAuth1
# Create the Flask application
app = flask.Flask(__name__)
# Add the ProxyFix middleware which reads X-Forwarded-* headers
app.wsgi_app = werkzeug.contrib.fixers.ProxyFix(app.wsgi_app)
# Load configuration from YAML file(s).
__dir__ = os.path.dirname(__file__)
app.config.update(
yaml.safe_load(open(os.path.join(__dir__, 'default_config.yaml'))))
@app.route('/thank')
def thank():
"""Thank an edit. """
"""There are 3 different tokens to get straight here:
1. The consumer token which verifies the application
2. The access token which verifies the user login
3. The CSRF token which verifies the intent to send a thank.
"""
# Construct an auth object with the consumer and access tokens
consumer_token = mwoauth.ConsumerToken(
app.config['CONSUMER_KEY'], app.config['CONSUMER_SECRET'])
access_token = flask.session['access_token']
# This copied from:
# https://github.com/mediawiki-utilities/python-mwapi/blob/master/demo_mwoauth.py
auth1 = OAuth1(consumer_token.key,
client_secret=consumer_token.secret,
resource_owner_key=access_token['key'],
resource_owner_secret=access_token['secret'])
# Construct an mwapi session. Nothing special here.
# In general should probably be done outside of the route function, here for simplicity.
session = mwapi.Session(
host="https://en.wikipedia.org",
user_agent="Gratitude prototyping session - max@civilservant.io")
# Get the CSRF token
csrf_response = session.get(action='query', meta='tokens', format='json', type='csrf', auth=auth1)
csrf_token = csrf_response['query']['tokens']['csrftoken']
rev_id_to_thank = 847954967 #You want to change this unless you really like me creating an account.
# Now, accessing the API on behalf of a user
thank_response = session.post(action='thank', rev = rev_id_to_thank, token=csrf_token, source='app', auth=auth1)
print(thank_response) # you can make sure it workede
# Looks like:
# {'result': {'success': 1, 'recipient': 'Maximilianklein(CS)'}}
return flask.redirect(flask.url_for('index'))
### End of thanking code ####
@app.route('/')
def index():
"""Application landing page."""
username = flask.session.get('username', None)
return flask.render_template('index.html', username=username)
@app.route('/login')
def login():
"""Initiate an OAuth login.
Call the MediaWiki server to get request secrets and then redirect the
user to the MediaWiki server to sign the request.
"""
consumer_token = mwoauth.ConsumerToken(
app.config['CONSUMER_KEY'], app.config['CONSUMER_SECRET'])
try:
redirect, request_token = mwoauth.initiate(
app.config['OAUTH_MWURI'], consumer_token)
except Exception:
app.logger.exception('mwoauth.initiate failed')
return flask.redirect(flask.url_for('index'))
else:
flask.session['request_token'] = dict(zip(
request_token._fields, request_token))
return flask.redirect(redirect)
@app.route('/oauth-callback')
def oauth_callback():
"""OAuth handshake callback."""
# if 'request_token' not in flask.session:
# flask.flash(u'OAuth callback failed. Are cookies disabled?')
# return flask.redirect(flask.url_for('index'))
consumer_token = mwoauth.ConsumerToken(
app.config['CONSUMER_KEY'], app.config['CONSUMER_SECRET'])
access_token = mwoauth.complete(
app.config['OAUTH_MWURI'],
consumer_token,
mwoauth.RequestToken(**flask.session['request_token']),
flask.request.query_string)
identity = mwoauth.identify(
app.config['OAUTH_MWURI'], consumer_token, access_token)
print(f'Identity {identity}')
flask.session['access_token'] = dict(zip(
access_token._fields, access_token))
flask.session['username'] = identity['username']
return flask.redirect(flask.url_for('index'))
(flask.url_for('index'))
# This file derived the Tool Labs Flask + OAuth WSGI tutorial
#
# Copyright (C) 2017 Bryan Davis and contributors
# Copyright (C) 2019 Max Klein
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment