class OrderManager:
    def __init__(self):
        self.user_manager = UserManager()

    def get_all_orders_for_collector(self, collector_id=None):
        if not collector_id:
            return None

        collector = self.user_manager.get_user_by_id(user_id=collector_id)

        if collector:
            orders_pickups = OrderPickup.objects.filter(collector=collector)
            return orders_pickups
        else:
            return None

    def get_order_by_id(self, order_id=None):
        if not order_id:
            return None

        if Order.objects.filter(id=order_id).exists():
            return Order.objects.get(id=order_id)
        else:
            return None

    def get_payable_by_order(self, order=None):
        if not order:
            return None

        transactions = Transaction.objects.filter(order=order)
        payable = order.total

        if transactions:
            payable = order.total - sum([txn.amt for txn in transactions])

        return payable
class EncryptionManager:
    def __init__(self):
        self.public_exponent = 65537
        self.key_size = 512
        self.user_manager = UserManager()
        self.otp_length = 4

    def generate_key_pair_for_user(self, user_id):
        private_key = rsa.generate_private_key(
            public_exponent=self.public_exponent,
            key_size=self.key_size,
            backend=default_backend())
        public_key = private_key.public_key()

        user = self.user_manager.get_user_by_id(user_id=user_id)
        print(type(user))
        if user:
            user.privkey = private_key.private_bytes(
                encoding=serialization.Encoding.PEM,
                format=serialization.PrivateFormat.TraditionalOpenSSL,
                encryption_algorithm=serialization.NoEncryption()).decode()

            user.pubkey = public_key.public_bytes(
                encoding=serialization.Encoding.PEM,
                format=serialization.PublicFormat.SubjectPublicKeyInfo).decode(
                )

            user.save()

    def get_private_key_by_user_id(self, user_id):
        # user = self.user_manager.get_user_by_id(user_id=user_id)
        # if not user.privkey:
        #     self.generate_key_pair_for_user(user_id=user.id)
        #     user = self.user_manager.get_user_by_id(user_id=user_id)

        with open(settings.PRIVKEY, "rb") as key_file:
            private_key = serialization.load_pem_private_key(
                key_file.read(), password=None, backend=default_backend())

        return private_key

    def get_public_key_by_user_id(self, user_id):
        private_key = self.get_private_key_by_user_id(user_id)
        return private_key.public_key()

    def get_encrypted_cipher(self, user_id, data):
        public_key = self.get_public_key_by_user_id(user_id)
        ciphertext = public_key.encrypt(
            data.encode(),
            padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA1()),
                         algorithm=hashes.SHA1(),
                         label=None))
        return ciphertext

    def get_decrypt_cipher(self, user_id, ciphertext):
        private_key = self.get_private_key_by_user_id(user_id)
        plaintext = private_key.decrypt(
            ciphertext,
            padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA1()),
                         algorithm=hashes.SHA1(),
                         label=None))
        return plaintext

    def get_otp_string(self):
        otp = ""
        for _ in range(self.otp_length):
            otp += str(random.randint(1, 9))
        return otp

    def get_signature(self, data, user_id):
        private_key = self.get_private_key_by_user_id(user_id)
        signature = private_key.sign(
            data.encode(),
            padding.PSS(mgf=padding.MGF1(hashes.SHA1()),
                        salt_length=padding.PSS.MAX_LENGTH), hashes.SHA1())
        return signature

    def get_encoded_signature(self, signature):
        return b64encode(signature)

    def get_decoded_signature(self, signature):
        return b64decode(signature)

    def is_data_verified(self, data, signature, user_id):
        public_key = self.get_public_key_by_user_id(user_id)
        print(type(signature))
        try:
            public_key.verify(
                signature, data.encode(),
                padding.PSS(mgf=padding.MGF1(hashes.SHA1()),
                            salt_length=padding.PSS.MAX_LENGTH), hashes.SHA1())
            return True
        except Exception as e:
            print(e)
            return False
Example #3
0
class OrdersView(View):
    def __init__(self):
        super().__init__()
        self.order_manager = OrderManager()
        self.encryption_manager = EncryptionManager()
        self.otp_manager = OTPManager()
        self.user_manager = UserManager()

    def get(self, request, order_id=None):
        login_id = request.session.get('login_id', None)

        if not login_id:
            redirect(reverse('home'))

        if not order_id:
            pickups = self.order_manager.get_all_orders_for_collector(login_id)
            context = {"pickups": pickups if pickups else []}
            return render(request, "orders.html", context)

        if order_id:
            order = self.order_manager.get_order_by_id(order_id=order_id)
            if order:
                payable = self.order_manager.get_payable_by_order(order)
                context = {"order": order, "payable": payable}
                return render(request, "order.html", context)
            else:
                return redirect(reverse('orders'))

    def post(self, request, order_id=None):
        login_id = request.session.get('login_id', None)

        if not login_id:
            redirect(reverse('home'))

        if order_id:
            if request.POST.get('action') == 'start_transaction':
                payable = request.POST.get('payable')
                if not payable:
                    return redirect(reverse('orders'))
                context = {
                    "payable": int(payable),
                    "order_id": order_id,
                    "user_id": login_id
                }
                return render(request, "transact.html", context)

            if request.POST.get('action') == 'start_verification':
                order_id = request.POST.get('order_id')
                payable = request.POST.get('payable')
                user_id = request.POST.get('user_id')

                if order_id and payable and user_id:
                    data = f"{order_id}.{payable}.{user_id}"

                    print(data)

                    ciphertext = self.encryption_manager.get_encrypted_cipher(
                        user_id=int(user_id), data=data)

                    plaintext = self.encryption_manager.get_decrypt_cipher(
                        user_id=user_id, ciphertext=ciphertext)

                    otp = self.encryption_manager.get_otp_string()

                    data = f"{plaintext.decode()}.{otp}"

                    signature = self.encryption_manager.get_signature(
                        data=data, user_id=user_id)
                    print(f'generated: {signature}')

                    otp_message = f"Your OTP is - {otp}. Payable amount is Rs.{payable}"
                    self.otp_manager.send_otp(
                        data=otp_message,
                        to=[self.user_manager.get_user_by_id(user_id).phone])
                    print(f'otp_message: {otp_message}')

                    context = {
                        "order_id": order_id,
                        "payable": payable,
                        "user_id": user_id,
                        "cipher": b64encode(ciphertext).decode(),
                        "signature": b64encode(signature).decode()
                    }
                    return render(request, "verify.html", context)
                else:
                    return redirect(reverse('orders'))

            if request.POST.get('action') == 'start_otp_validation':
                otp = request.POST.get('otp')
                order_id = request.POST.get('order_id')
                payable = request.POST.get('payable')
                user_id = request.POST.get('user_id')
                signature = request.POST.get('signature')
                print(f'Received: {b64decode(signature)}')

                data = f"{order_id}.{payable}.{user_id}.{otp}"

                is_verified = self.encryption_manager.is_data_verified(
                    data=data, signature=b64decode(signature), user_id=user_id)

                if is_verified:
                    return render(request, "success.html")

                else:
                    return redirect(reverse('orders'))