defmodule DaProductApp.Security.InputValidator do require Logger @doc """ Validates the input parameters for XSS and other malicious content """ def validate_payment_params(params) do with {:ok, _} <- validate_transaction_refid(params["transaction_refid"]), {:ok, _} <- validate_merchant_id(params["merchantId"]), {:ok, _} <- validate_merchant_name(params["merchantName"]), {:ok, _} <- validate_amount(params["amount"]), {:ok, _} <- validate_device_id(params["deviceId"]), {:ok, _} <- validate_additional_data(params["additionalData"]) do {:ok, params} else {:error, message} -> {:error, message} end end # Validate transaction_refid (alphanumeric, maximum length) defp validate_transaction_refid(nil), do: {:error, "Transaction RefID is required"} defp validate_transaction_refid(refid) when not is_binary(refid), do: {:error, "Invalid Transaction RefID format"} defp validate_transaction_refid(refid) do if Regex.match?(~r/^[a-zA-Z0-9_-]{1,64}$/, refid) do {:ok, refid} else {:error, "Transaction RefID contains invalid characters"} end end # Validate merchant_id (alphanumeric, maximum length) defp validate_merchant_id(nil), do: {:error, "Merchant ID is required"} defp validate_merchant_id(id) when not is_binary(id), do: {:error, "Invalid Merchant ID format"} defp validate_merchant_id(id) do if Regex.match?(~r/^[a-zA-Z0-9_-]{1,32}$/, id) do {:ok, id} else {:error, "Merchant ID contains invalid characters"} end end # Validate merchant_name (prevent XSS) defp validate_merchant_name(nil), do: {:error, "Merchant Name is required"} defp validate_merchant_name(name) when not is_binary(name), do: {:error, "Invalid Merchant Name format"} defp validate_merchant_name(name) do sanitized_name = HtmlSanitizeEx.strip_tags(name) if String.length(sanitized_name) in 1..255 do {:ok, sanitized_name} else {:error, "Invalid Merchant Name length"} end end # Validate amount (prevent manipulation) defp validate_amount(nil), do: {:error, "Amount is required"} defp validate_amount(amount) when is_binary(amount) do case Float.parse(amount) do {value, ""} when value > 0 and value <= 999_999.99 -> {:ok, value} _ -> {:error, "Invalid amount value"} end end defp validate_amount(amount) when is_number(amount) do if amount > 0 and amount <= 999_999.99, do: {:ok, amount}, else: {:error, "Invalid amount value"} end defp validate_amount(_), do: {:error, "Invalid amount format"} # Validate device_id (prevent injection) defp validate_device_id(nil), do: {:error, "Device ID is required"} defp validate_device_id(id) when not is_binary(id), do: {:error, "Invalid Device ID format"} defp validate_device_id(id) do if Regex.match?(~r/^[a-zA-Z0-9_-]{1,32}$/, id) do {:ok, id} else {:error, "Device ID contains invalid characters"} end end # Validate additional_data (prevent JSON injection) defp validate_additional_data(nil), do: {:ok, nil} defp validate_additional_data(data) when not is_map(data), do: {:error, "Invalid additional data format"} defp validate_additional_data(data) do if map_size(data) <= 10 and validate_map_values(data) do {:ok, data} else {:error, "Invalid additional data"} end end # Validate map values recursively defp validate_map_values(map) when is_map(map) do Enum.all?(map, fn {k, v} -> is_binary(k) and (is_binary(v) or is_number(v) or is_boolean(v) or is_map(v)) end) end end