# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'contrast/agent/assess/rule/response/body_rule' require 'contrast/utils/string_utils' module Contrast module Agent module Assess module Rule module Response # These rules check the content of the HTTP Response to determine if the body contains a form which # incorrectly sets the autocomplete attribute. class AutoComplete < BaseRule include BodyRule def rule_id 'autocomplete-missing' end protected # Rules discern which responses they can/should analyze. # # @param response [Contrast::Agent::Response] the response of the application def analyze_response? response super && body?(response) end # Determine if the Response violates the Rule or not. If it does, return the evidence that proves it so. # # @param response [Contrast::Agent::Response] the response of the application # @return [Hash, nil] the evidence required to prove the violation of the rule def violated? response body = response.body forms = html_elements(body, FORM_START_REGEXP, capture_overflow: true) forms.each do |form| # Because TeamServer will reject any subsequent form on the same page due to deduplication, we can # skip out on the first violation. return form if autocomplete?(form[HTML_PROP]) end nil end def off_values [/"off"/, /'off'/, /off /, /off>/] end # Determine if the given form does not have a valid autocomplete tag. Because autocompletion is on by # default, the form must both have the value and set it to being disabled to not autocomplete. # # @param form [String] the form tag # @return [Boolean] def autocomplete? form idx = form =~ /autocomplete=/i return true unless idx # Adjust for the length of 'autocomplete=' idx += 13 off_values.each do |off_value| return false if (form =~ off_value) == idx end true end end end end end end end