import binascii import json import requests from decouple import config from flask import Flask, request from flask_restful import Resource, Api from pyotp import TOTP from config import etcd_client as client, logging, APP_PORT from stripe_utils import StripeUtils app = Flask(__name__) api = Api(app) def check_otp(name, realm, token): try: data = { "auth_name": config("AUTH_NAME", ""), "auth_token": TOTP(config("AUTH_SEED", "")).now(), "auth_realm": config("AUTH_REALM", ""), "name": name, "realm": realm, "token": token, } except binascii.Error: return 400 response = requests.post( "{OTP_SERVER}{OTP_VERIFY_ENDPOINT}".format( OTP_SERVER=config("OTP_SERVER", ""), OTP_VERIFY_ENDPOINT=config("OTP_VERIFY_ENDPOINT", "verify/"), ), data=data, ) return response.status_code class ListProducts(Resource): @staticmethod def get(): products = client.get_prefix("/v1/products/", value_in_json=False) prod_dict = {} for p in products: prod_dict[p.key] = json.loads(p.value) logging.debug("Products = {}".format(prod_dict)) return prod_dict, 200 class AddProduct(Resource): @staticmethod def post(): data = request.json logging.debug("Got data: {}".format(str(data))) otp_response = check_otp(data["name"], data["realm"], data["token"]) if otp_response != 200: return {"message": "Wrong Credentials"}, 403 try: product_key = "/v1/products/" product_value = { "name": data["product_name"], "description": data["product_description"], "type": data["product_type"], "price": data["product_price"], "recurring_duration": data["product_recurring_duration"], "recurring_duration_units": data["product_recurring_duration_units"] } logging.debug("Adding product data: {}".format(str(product_value))) client.put(product_key, product_value, value_in_json=True) return {"message": "Product {} created".format(data['product_name'])}, 200 except KeyError as ke: logging.error("KeyError occurred. details = {}".format(str(ke))) return {"message": "Missing or wrong parameters"}, 400 class UserRegisterPayment(Resource): @staticmethod def get_token(card_number, cvc, exp_month, exp_year): stripe_utils = StripeUtils() token_response = stripe_utils.get_token_from_card( card_number, cvc, exp_month, exp_year ) if token_response["response_object"]: return token_response["response_object"].id else: return None @staticmethod def post(): try: data = request.json logging.debug("Got data: {}".format(str(data))) otp_response = check_otp(data["name"], data["realm"], data["token"]) if otp_response != 200: return {"message": "Wrong Credentials"}, 403 stripe_utils = StripeUtils() stripe_customer = stripe_utils.get_stripe_customer_from_email( data["email"]) token = UserRegisterPayment.get_token( data["card_number"], data["cvc"], data["expiry_month"], data["expiry_year"] ) if token: if stripe_customer is None: stripe_customer_resp = stripe_utils.create_customer( name=data["card_holder_name"], token=token, email=data["email"] ) if stripe_customer_resp: stripe_customer = stripe_customer_resp[ "response_object"] else: logging.error("Could not get/create stripe_customer " "for {}".format(data["email"])) return {"message": "Error with card. Contact support"}, 400 else: logging.error("Could not get token for the card") return {"message": "Error with card. " "Contact support@ungleich.ch" }, 400 user_key = "/v1/users/{}/stripe_customer/".format(data["email"]) user_value = stripe_customer.id client.put(user_key, user_value, value_in_json=False) if token: user_key = "/v1/users/{}/cards/".format(data["email"]) user_value = token client.put(user_key, user_value, value_in_json=False) fresh_token = UserRegisterPayment.get_token( data["card_number"], data["cvc"], data["expiry_month"], data["expiry_year"] ) if fresh_token: resp = stripe_utils.associate_customer_card( stripe_customer.id, fresh_token ) if resp["response_object"]: return {"message": "Card ending in {} registered as your payment " "soruce".format( data['card_number'].strip()[-4:]) }, 200 else: logging.error("Error obtaining fresh token") return {"message": "Error with card. Contact support"}, 400 else: logging.error( "Unable to associate card " "{} with customer {}".format( token["response_object"].card.id, data["email"] ) ) return {"message": "Error with card. Contact support"}, 400 except KeyError as key_error: logging.error("Key error occurred") logging.error(str(key_error)) return {"message": "Missing or wrong parameters"}, 400 api.add_resource(ListProducts, "/product/list") api.add_resource(AddProduct, "/product/add") api.add_resource(UserRegisterPayment, "/user/register_payment") if __name__ == '__main__': app.run(host="::", port=APP_PORT, debug=True)