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"]) last4 = data['card_number'].strip()[-4:] if otp_response != 200: return {"message": "Wrong Credentials"}, 403 stripe_utils = StripeUtils() # Does customer already exist ? stripe_customer = stripe_utils.get_stripe_customer_from_email( data["email"]) # Does customer already exist ? if stripe_customer is not None: logging.debug( "Customer {} exists already".format(data['email']) ) # Check if the card already exists ce_response = stripe_utils.card_exists( stripe_customer.id, cc_number=data["card_number"], exp_month=int(data["expiry_month"]), exp_year=int(data["expiry_year"]), cvc=data["cvc"]) if ce_response["response_object"]: message = ("The given card ending in " "{} exists already.").format(last4) logging.debug(message) return { "message": message }, 400 elif ce_response["response_object"] is False: # Associate card with user logging.debug("Adding card ending in {}".format(last4)) token_response = stripe_utils.get_token_from_card( data["card_number"], data["cvc"], data["expiry_month"], data["expiry_year"] ) if token_response["response_object"]: logging.debug( "Token {}".format( token_response["response_object"].id ) ) resp = stripe_utils.associate_customer_card( stripe_customer.id, token_response["response_object"].id ) if resp["response_object"]: return {"message": "Card ending in {} registered as your payment " "source".format(last4) }, 200 else: logging.error("Could not obtain token") return {"message": "Error with payment gateway. " "Contact support"}, 400 else: logging.error( "Error occurred {}".format(ce_response["error"]) ) return {"message": "Error: {}".format( ce_response["error"] )}, 400 else: # Stripe customer does not exist, create a new one logging.debug( "Customer {} does not exist, " "creating new".format(data['email']) ) token_response = stripe_utils.get_token_from_card( data["card_number"], data["cvc"], data["expiry_month"], data["expiry_year"] ) if token_response["response_object"]: logging.debug( "Token {}".format( token_response["response_object"].id)) #Create stripe customer stripe_customer_resp = stripe_utils.create_customer( name=data["card_holder_name"], token=token_response["response_object"].id, email=data["email"] ) if stripe_customer_resp["response_object"]: logging.debug( "Created stripe customer {}".format( stripe_customer_resp["response_object"].id ) ) stripe_customer = stripe_customer_resp[ "response_object"] return {"message": "Card ending in {} registered as your payment " "source".format(last4) }, 200 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 obtain token") return {"message": "Error with payment gateway. " "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)