summaryrefslogtreecommitdiff
path: root/talerblog
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2018-01-05 12:00:50 +0100
committerFlorian Dold <florian.dold@gmail.com>2018-01-05 12:00:50 +0100
commit58be785e4181b403f2d74ce7e92cde2784aae455 (patch)
tree3ce08b86fd7d0bcd864dd5689ca386d9cd737912 /talerblog
parentd10579541c10ae122f542f502b1d4c1ae8888ea7 (diff)
downloadblog-58be785e4181b403f2d74ce7e92cde2784aae455.tar.gz
blog-58be785e4181b403f2d74ce7e92cde2784aae455.tar.bz2
blog-58be785e4181b403f2d74ce7e92cde2784aae455.zip
use upcoming backend API
Diffstat (limited to 'talerblog')
-rw-r--r--talerblog/blog/blog.py135
1 files changed, 56 insertions, 79 deletions
diff --git a/talerblog/blog/blog.py b/talerblog/blog/blog.py
index f5677d8..8cb5763 100644
--- a/talerblog/blog/blog.py
+++ b/talerblog/blog/blog.py
@@ -23,6 +23,7 @@ Implement URL handlers and payment logic for the blog merchant.
from urllib.parse import urljoin, quote, parse_qsl
import logging
import os
+import uuid
import base64
import requests
import flask
@@ -33,6 +34,7 @@ from ..helpers import (make_url, \
from ..blog.content import (ARTICLES, \
get_article_file, get_image_file)
+
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
app = flask.Flask(__name__, template_folder=BASE_DIR)
app.debug = True
@@ -47,6 +49,7 @@ ARTICLE_AMOUNT = dict(value=0, fraction=50000000, currency=CURRENCY)
app.config.from_object(__name__)
+
@app.context_processor
def utility_processor():
def url(my_url):
@@ -55,48 +58,40 @@ def utility_processor():
return os.environ.get(name, default)
return dict(url=url, env=env)
+
@app.route("/")
def index():
return flask.render_template("templates/index.html",
merchant_currency=CURRENCY,
articles=ARTICLES.values())
+
@app.route("/javascript")
def javascript_licensing():
return flask.render_template("templates/javascript.html")
+
# Triggers the refund by serving /refund/test?order_id=XY.
# Will be triggered by a "refund button".
-@app.route("/refund", methods=["GET", "POST"])
+@app.route("/refund", methods=["POST"])
def refund():
- if flask.request.method == "POST":
- payed_articles = flask.session["payed_articles"] = flask.session.get("payed_articles", {})
- article_name = flask.request.form.get("article_name")
- LOGGER.info("Looking for article '%s' to refund" % article_name)
- order_id = payed_articles.get(article_name)
- if not order_id:
- return flask.jsonify(dict(error="Aborting refund: article not payed")), 401
- resp = requests.post(urljoin(BACKEND_URL, "refund"),
- json=dict(order_id=order_id,
- refund=ARTICLE_AMOUNT,
- reason="Demo reimbursement",
- instance=INSTANCE))
- if resp.status_code != 200:
- return backend_error(resp)
- payed_articles[article_name] = "__refunded"
- response = flask.make_response()
- response.headers["X-Taler-Refund-Url"] = make_url("/refund", ("order_id", order_id))
- return response, 402
-
- order_id = expect_parameter("order_id", False)
+ article_name = flask.request.form.get("article_name")
+ if not article_name:
+ return flask.jsonify(dict(error="No article_name found in form")), 400
+ LOGGER.info("Looking for %s to refund" % article_name)
+ order_id = payed_articles.get(article_name)
if not order_id:
- LOGGER.error("Missing parameter 'order_id'")
- return flask.jsonify(dict(error="Missing parameter 'order_id'")), 400
- resp = requests.get(urljoin(BACKEND_URL, "refund"),
- params=dict(order_id=order_id, instance=INSTANCE))
+ return flask.jsonify(dict(error="Aborting refund: article not payed")), 401
+ resp = requests.post(urljoin(BACKEND_URL, "refund"),
+ json=dict(order_id=order_id,
+ refund=ARTICLE_AMOUNT,
+ reason="Demo reimbursement",
+ instance=INSTANCE))
if resp.status_code != 200:
return backend_error(resp)
- return flask.jsonify(resp.json()), resp.status_code
+ if pay_status.get("refund_redirect_url"):
+ return flask.redirect(pay_status["refund_redirect_url"])
+ flask.abort(500)
@app.route("/generate-contract", methods=["GET"])
@@ -134,24 +129,46 @@ def generate_contract():
return flask.jsonify(**proposal_resp)
-@app.route("/cc-payment/<name>")
-def cc_payment(name):
- return flask.render_template("templates/cc-payment.html",
- article_name=name)
-
@app.route("/essay/<name>")
@app.route("/essay/<name>/data/<data>")
def article(name, data=None):
- LOGGER.info("processing %s" % name)
- payed_articles = flask.session.get("payed_articles", {})
- if payed_articles.get(name, "") == "__refunded":
+ # We use an explicit session ID so that each payment (or payment replay) is
+ # bound to a browser. This forces re-play and prevents sharing the article
+ # by just sharing the URL.
+ session_id = flask.session.get("uid")
+ if not session_id:
+ session_id = flask.session["uid"] = uuid.uuid4()
+
+ pay_params = dict(
+ instance=INSTANCE,
+ contract_url=make_url("/generate-contract", ("article_name", name)),
+ session_id=session_id,
+ session_sig=requests.args.get("session_sig"),
+ order_id=requests.args.get("order_id"),
+ # URL that the browser will navigate to after the user has paid (or
+ # proved they already paid) with this session
+ confirm_url = make_url("/essay/" + name,
+ ("order_id", "${order_id}"),
+ ("session_sig", "${session_sig}"))
+ )
+
+ resp = requests.get(urljoin(BACKEND_URL, "check-payment"), params=pay_params)
+ if resp.status_code != 200:
+ return backend_error(resp)
+
+ pay_status = resp.json()
+
+ if pay_status.get("payment_redirect_url"):
+ return flask.redirect(pay_status["payment_redirect_url"])
+
+ if pay_status.get("refunded"):
return flask.render_template("templates/article_refunded.html", article_name=name)
- if name in payed_articles:
- article_info = ARTICLES[name]
- if article_info is None:
+ if pay_status.get("paid"):
+ articleInfo = ARTICLES[name]
+ if articleInfo is None:
flask.abort(500)
if data is not None:
if data in article_info.extra_files:
@@ -161,45 +178,5 @@ def article(name, data=None):
article_file=get_article_file(article_info),
article_name=name)
- contract_url = make_url("/generate-contract",
- ("article_name", name))
- response = flask.make_response(
- flask.render_template("templates/fallback.html"), 402)
- response.headers["X-Taler-Contract-Url"] = contract_url
- response.headers["X-Taler-Contract-Query"] = "fulfillment_url"
- # Useless (?) header, as X-Taler-Contract-Url takes always (?) precedence
- # over X-Offer-Url. This one might only be useful if the contract retrieval
- # goes wrong.
- response.headers["X-Taler-Offer-Url"] = make_url("/essay/" + quote(name))
- return response
-
-
-@app.route("/pay", methods=["POST"])
-def pay():
- deposit_permission = flask.request.get_json()
- if deposit_permission is None:
- return flask.jsonify(error="no json in body"), 400
- resp = requests.post(urljoin(BACKEND_URL, "pay"),
- json=deposit_permission)
- if resp.status_code != 200:
- return backend_error(resp)
- proposal_data = resp.json()["contract_terms"]
- article_name = proposal_data["extra"]["article_name"]
- payed_articles = flask.session["payed_articles"] = flask.session.get("payed_articles", {})
-
- try:
- resp.json()["refund_permissions"].pop()
- # we had some refunds on the article purchase already!
- LOGGER.info("Article %s was refunded, before /pay" % article_name)
- payed_articles[article_name] = "__refunded"
- return flask.jsonify(resp.json()), 200
- except IndexError:
- pass
-
- if not deposit_permission["order_id"]:
- LOGGER.error("order_id missing from deposit_permission!")
- return flask.jsonify(dict(error="internal error: ask for refund!")), 500
- if article_name not in payed_articles:
- LOGGER.info("Article %s goes in state" % article_name)
- payed_articles[article_name] = deposit_permission["order_id"]
- return flask.jsonify(resp.json()), 200
+ # no pay_redirect but article not paid, this should never happen!
+ flask.abort(500)