Created
January 8, 2019 17:26
-
-
Save notconfusing/460d6ffb6682439ebe6b70b78e7759af to your computer and use it in GitHub Desktop.
Send a "thanks" on Wikipedia via OAUTH
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- 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 - [email protected]") | |
# 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