arachni 1.2.1 → 1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +66 -0
- data/Gemfile +1 -1
- data/README.md +16 -5
- data/components/checks/active/ldap_injection/errors.txt +1 -0
- data/components/checks/active/source_code_disclosure.rb +1 -1
- data/components/checks/active/unvalidated_redirect.rb +6 -6
- data/components/checks/active/unvalidated_redirect_dom.rb +10 -7
- data/components/checks/passive/grep/captcha.rb +14 -5
- data/components/checks/passive/grep/form_upload.rb +7 -3
- data/components/checks/passive/grep/hsts.rb +3 -3
- data/components/checks/passive/grep/html_objects.rb +2 -3
- data/components/checks/passive/grep/http_only_cookies.rb +2 -3
- data/components/checks/passive/grep/insecure_cookies.rb +1 -1
- data/components/checks/passive/grep/password_autocomplete.rb +2 -2
- data/components/checks/passive/grep/unencrypted_password_forms.rb +7 -7
- data/components/checks/passive/grep/x_frame_options.rb +2 -2
- data/components/checks/passive/http_put.rb +2 -3
- data/components/path_extractors/comments.rb +3 -3
- data/components/path_extractors/scripts.rb +10 -1
- data/components/plugins/defaults/autothrottle.rb +27 -18
- data/components/plugins/defaults/meta/remedies/discovery.rb +30 -33
- data/components/plugins/defaults/meta/remedies/timing_attacks.rb +7 -11
- data/components/plugins/login_script.rb +9 -3
- data/components/plugins/proxy.rb +4 -3
- data/components/reporters/html.rb +11 -14
- data/components/reporters/html/default/issue.erb +13 -38
- data/components/reporters/html/default/issue/info.erb +1 -1
- data/components/reporters/html/default/summary/issues/by_name.erb +3 -3
- data/components/reporters/stdout.rb +62 -71
- data/components/reporters/xml.rb +26 -40
- data/components/reporters/xml/schema.xsd +43 -89
- data/lib/arachni/browser.rb +52 -3
- data/lib/arachni/browser/javascript.rb +3 -3
- data/lib/arachni/browser/javascript/scripts/taint_tracer.js +46 -25
- data/lib/arachni/browser_cluster.rb +61 -0
- data/lib/arachni/browser_cluster/job.rb +21 -1
- data/lib/arachni/browser_cluster/jobs/browser_provider.rb +3 -1
- data/lib/arachni/browser_cluster/jobs/resource_exploration.rb +2 -1
- data/lib/arachni/browser_cluster/jobs/resource_exploration/event_trigger.rb +2 -1
- data/lib/arachni/browser_cluster/jobs/taint_trace.rb +3 -2
- data/lib/arachni/browser_cluster/jobs/taint_trace/event_trigger.rb +1 -1
- data/lib/arachni/browser_cluster/worker.rb +5 -0
- data/lib/arachni/check/auditor.rb +22 -12
- data/lib/arachni/data/framework.rb +13 -1
- data/lib/arachni/data/issues.rb +9 -25
- data/lib/arachni/element/base.rb +9 -3
- data/lib/arachni/element/capabilities/analyzable.rb +2 -6
- data/lib/arachni/element/capabilities/analyzable/differential.rb +24 -7
- data/lib/arachni/element/capabilities/analyzable/{taint.rb → signature.rb} +23 -23
- data/lib/arachni/element/capabilities/auditable.rb +0 -6
- data/lib/arachni/element/capabilities/dom_only.rb +61 -0
- data/lib/arachni/element/capabilities/with_dom.rb +3 -1
- data/lib/arachni/element/cookie.rb +35 -5
- data/lib/arachni/element/cookie/dom.rb +13 -4
- data/lib/arachni/element/{capabilities/auditable/dom.rb → dom.rb} +20 -68
- data/lib/arachni/element/dom/capabilities/auditable.rb +29 -0
- data/lib/arachni/element/dom/capabilities/inputtable.rb +27 -0
- data/lib/arachni/element/dom/capabilities/mutable.rb +21 -0
- data/lib/arachni/element/dom/capabilities/submittable.rb +52 -0
- data/lib/arachni/element/form.rb +12 -1
- data/lib/arachni/element/form/capabilities/mutable.rb +2 -1
- data/lib/arachni/element/form/capabilities/with_dom.rb +0 -1
- data/lib/arachni/element/form/dom.rb +9 -3
- data/lib/arachni/element/header.rb +14 -33
- data/lib/arachni/element/header/capabilities/inputtable.rb +29 -0
- data/lib/arachni/element/header/capabilities/mutable.rb +51 -0
- data/lib/arachni/element/input/dom.rb +71 -0
- data/lib/arachni/element/json.rb +2 -0
- data/lib/arachni/element/link.rb +3 -0
- data/lib/arachni/element/link/capabilities/with_dom.rb +0 -1
- data/lib/arachni/element/link/dom.rb +16 -3
- data/lib/arachni/element/link/dom/capabilities/submittable.rb +29 -0
- data/lib/arachni/element/link_template.rb +3 -5
- data/lib/arachni/element/link_template/capabilities/inputtable.rb +5 -0
- data/lib/arachni/element/link_template/capabilities/with_dom.rb +0 -1
- data/lib/arachni/element/link_template/dom.rb +16 -3
- data/lib/arachni/element/link_template/dom/capabilities/submittable.rb +29 -0
- data/lib/arachni/element/server.rb +3 -5
- data/lib/arachni/element/ui_form.rb +106 -0
- data/lib/arachni/element/ui_form/dom.rb +107 -0
- data/lib/arachni/element/ui_input.rb +62 -0
- data/lib/arachni/element/xml.rb +2 -1
- data/lib/arachni/framework.rb +7 -5
- data/lib/arachni/framework/parts/audit.rb +0 -1
- data/lib/arachni/framework/parts/check.rb +1 -0
- data/lib/arachni/framework/parts/data.rb +4 -0
- data/lib/arachni/framework/parts/state.rb +0 -2
- data/lib/arachni/http/client.rb +17 -6
- data/lib/arachni/http/proxy_server.rb +52 -5
- data/lib/arachni/http/request.rb +1 -1
- data/lib/arachni/issue.rb +34 -179
- data/lib/arachni/issue/severity.rb +2 -0
- data/lib/arachni/option_groups/audit.rb +22 -2
- data/lib/arachni/option_groups/browser_cluster.rb +15 -0
- data/lib/arachni/page.rb +3 -2
- data/lib/arachni/parser.rb +24 -5
- data/lib/arachni/platform/manager.rb +1 -2
- data/lib/arachni/rpc/server/framework.rb +3 -4
- data/lib/arachni/rpc/server/framework/multi_instance.rb +2 -1
- data/lib/arachni/session.rb +1 -1
- data/lib/arachni/trainer.rb +4 -7
- data/lib/arachni/watir/element.rb +12 -1
- data/lib/version +1 -1
- data/spec/arachni/browser/element_locator_spec.rb +43 -43
- data/spec/arachni/browser/javascript/dom_monitor_spec.rb +44 -44
- data/spec/arachni/browser/javascript/proxy/stub_spec.rb +17 -14
- data/spec/arachni/browser/javascript/proxy_spec.rb +24 -24
- data/spec/arachni/browser/javascript/taint_tracer/frame/called_function_spec.rb +11 -11
- data/spec/arachni/browser/javascript/taint_tracer/frame_spec.rb +7 -7
- data/spec/arachni/browser/javascript/taint_tracer/sink/data_flow_spec.rb +13 -13
- data/spec/arachni/browser/javascript/taint_tracer/sink/execution_flow_spec.rb +7 -7
- data/spec/arachni/browser/javascript/taint_tracer_spec.rb +568 -558
- data/spec/arachni/browser/javascript_spec.rb +73 -63
- data/spec/arachni/browser_cluster/job/result_spec.rb +3 -3
- data/spec/arachni/browser_cluster/job_spec.rb +68 -48
- data/spec/arachni/browser_cluster/jobs/resource_exploration/event_trigger/result_spec.rb +2 -2
- data/spec/arachni/browser_cluster/jobs/resource_exploration/event_trigger_spec.rb +5 -4
- data/spec/arachni/browser_cluster/jobs/resource_exploration/result_spec.rb +2 -2
- data/spec/arachni/browser_cluster/jobs/resource_exploration_spec.rb +5 -5
- data/spec/arachni/browser_cluster/worker_spec.rb +87 -70
- data/spec/arachni/browser_cluster_spec.rb +64 -39
- data/spec/arachni/browser_spec.rb +692 -527
- data/spec/arachni/check/auditor_spec.rb +177 -147
- data/spec/arachni/check/base_spec.rb +33 -33
- data/spec/arachni/check/manager_spec.rb +15 -15
- data/spec/arachni/component/base_spec.rb +8 -8
- data/spec/arachni/component/manager_spec.rb +100 -99
- data/spec/arachni/component/options/address_spec.rb +3 -3
- data/spec/arachni/component/options/base_spec.rb +7 -7
- data/spec/arachni/component/options/bool_spec.rb +9 -9
- data/spec/arachni/component/options/float_spec.rb +6 -6
- data/spec/arachni/component/options/int_spec.rb +5 -5
- data/spec/arachni/component/options/multiple_choice_spec.rb +12 -12
- data/spec/arachni/component/options/object_spec.rb +2 -2
- data/spec/arachni/component/options/path_spec.rb +3 -3
- data/spec/arachni/component/options/port_spec.rb +5 -5
- data/spec/arachni/component/options/string_spec.rb +3 -3
- data/spec/arachni/component/options/url_spec.rb +4 -4
- data/spec/arachni/component/utilities_spec.rb +2 -2
- data/spec/arachni/data/framework/rpc_spec.rb +10 -9
- data/spec/arachni/data/framework_spec.rb +65 -46
- data/spec/arachni/data/issues_spec.rb +39 -77
- data/spec/arachni/data/plugins_spec.rb +11 -11
- data/spec/arachni/data/session_spec.rb +6 -6
- data/spec/arachni/data_spec.rb +8 -8
- data/spec/arachni/element/body_spec.rb +10 -10
- data/spec/arachni/element/capabilities/analyzable/differential_spec.rb +39 -21
- data/spec/arachni/element/capabilities/analyzable/{taint_spec.rb → signature_spec.rb} +63 -63
- data/spec/arachni/element/capabilities/analyzable/timeout_spec.rb +51 -51
- data/spec/arachni/element/capabilities/with_scope/scope_spec.rb +5 -5
- data/spec/arachni/element/cookie/dom_spec.rb +37 -18
- data/spec/arachni/element/cookie_spec.rb +206 -139
- data/spec/arachni/element/form/dom_spec.rb +36 -19
- data/spec/arachni/element/form_spec.rb +210 -187
- data/spec/arachni/element/generic_dom_spec.rb +14 -14
- data/spec/arachni/element/header_spec.rb +35 -17
- data/spec/arachni/element/json_spec.rb +53 -31
- data/spec/arachni/element/link/dom_spec.rb +46 -28
- data/spec/arachni/element/link_spec.rb +58 -40
- data/spec/arachni/element/link_template/dom_spec.rb +47 -29
- data/spec/arachni/element/link_template_spec.rb +79 -61
- data/spec/arachni/element/path_spec.rb +1 -1
- data/spec/arachni/element/server_spec.rb +33 -32
- data/spec/arachni/element/ui_form/ui_form_dom_spec.rb +164 -0
- data/spec/arachni/element/ui_form_spec.rb +242 -0
- data/spec/arachni/element/ui_input/dom_spec.rb +157 -0
- data/spec/arachni/element/ui_input_spec.rb +136 -0
- data/spec/arachni/element/xml_spec.rb +42 -24
- data/spec/arachni/element_filter_spec.rb +49 -48
- data/spec/arachni/error_spec.rb +3 -3
- data/spec/arachni/framework/parts/audit_spec.rb +64 -63
- data/spec/arachni/framework/parts/browser_spec.rb +16 -16
- data/spec/arachni/framework/parts/check_spec.rb +3 -3
- data/spec/arachni/framework/parts/data_spec.rb +48 -48
- data/spec/arachni/framework/parts/platform_spec.rb +3 -3
- data/spec/arachni/framework/parts/plugin_spec.rb +7 -6
- data/spec/arachni/framework/parts/report_spec.rb +7 -7
- data/spec/arachni/framework/parts/scope_spec.rb +16 -16
- data/spec/arachni/framework/parts/state_spec.rb +68 -69
- data/spec/arachni/framework_spec.rb +39 -31
- data/spec/arachni/http/client/dynamic_404_handlers_spec.rb +32 -32
- data/spec/arachni/http/client_spec.rb +219 -208
- data/spec/arachni/http/cookie_jar_spec.rb +72 -72
- data/spec/arachni/http/headers_spec.rb +14 -14
- data/spec/arachni/http/proxy_server_spec.rb +43 -42
- data/spec/arachni/http/request_spec.rb +105 -103
- data/spec/arachni/http/response/scope_spec.rb +24 -24
- data/spec/arachni/http/response_spec.rb +50 -49
- data/spec/arachni/issue/severity_spec.rb +10 -9
- data/spec/arachni/issue_spec.rb +71 -369
- data/spec/arachni/option_groups/audit_spec.rb +114 -114
- data/spec/arachni/option_groups/browser_cluster_spec.rb +20 -3
- data/spec/arachni/option_groups/datastore_spec.rb +6 -6
- data/spec/arachni/option_groups/dispatcher_spec.rb +19 -19
- data/spec/arachni/option_groups/http_spec.rb +11 -11
- data/spec/arachni/option_groups/input_spec.rb +31 -27
- data/spec/arachni/option_groups/output_spec.rb +2 -2
- data/spec/arachni/option_groups/paths_spec.rb +17 -17
- data/spec/arachni/option_groups/rpc_spec.rb +2 -2
- data/spec/arachni/option_groups/scope_spec.rb +40 -40
- data/spec/arachni/option_groups/session_spec.rb +6 -5
- data/spec/arachni/option_groups/snapshot_spec.rb +4 -4
- data/spec/arachni/options_spec.rb +46 -45
- data/spec/arachni/page/dom/transition_spec.rb +74 -72
- data/spec/arachni/page/dom_spec.rb +35 -35
- data/spec/arachni/page/scope_spec.rb +15 -15
- data/spec/arachni/page_spec.rb +217 -217
- data/spec/arachni/parser_spec.rb +106 -104
- data/spec/arachni/platform/fingerprinter_spec.rb +17 -14
- data/spec/arachni/platform/list_spec.rb +33 -33
- data/spec/arachni/platform/manager_spec.rb +67 -64
- data/spec/arachni/plugin/base_spec.rb +10 -10
- data/spec/arachni/plugin/manager_spec.rb +38 -37
- data/spec/arachni/report_spec.rb +43 -40
- data/spec/arachni/reporter/base_spec.rb +15 -15
- data/spec/arachni/reporter/manager_spec.rb +4 -4
- data/spec/arachni/reporter/options_spec.rb +6 -6
- data/spec/arachni/rpc/client/base_spec.rb +6 -6
- data/spec/arachni/rpc/client/dispatcher_spec.rb +2 -2
- data/spec/arachni/rpc/client/instance_spec.rb +6 -6
- data/spec/arachni/rpc/server/active_options_spec.rb +11 -8
- data/spec/arachni/rpc/server/base_spec.rb +5 -5
- data/spec/arachni/rpc/server/checks/manager_spec.rb +8 -8
- data/spec/arachni/rpc/server/dispatcher/node_spec.rb +37 -37
- data/spec/arachni/rpc/server/dispatcher/service_spec.rb +15 -14
- data/spec/arachni/rpc/server/dispatcher_spec.rb +36 -35
- data/spec/arachni/rpc/server/framework/distributor_spec.rb +36 -36
- data/spec/arachni/rpc/server/framework_multi_spec.rb +340 -336
- data/spec/arachni/rpc/server/framework_spec.rb +90 -85
- data/spec/arachni/rpc/server/instance_spec.rb +126 -107
- data/spec/arachni/rpc/server/output_spec.rb +1 -1
- data/spec/arachni/rpc/server/plugin/manager_spec.rb +6 -6
- data/spec/arachni/ruby/array_spec.rb +42 -42
- data/spec/arachni/ruby/hash_spec.rb +20 -18
- data/spec/arachni/ruby/io_spec.rb +2 -2
- data/spec/arachni/ruby/object_spec.rb +1 -1
- data/spec/arachni/ruby/set_spec.rb +3 -3
- data/spec/arachni/ruby/string_spec.rb +30 -30
- data/spec/arachni/ruby/webrick_spec.rb +2 -2
- data/spec/arachni/scope_spec.rb +1 -1
- data/spec/arachni/session_spec.rb +67 -64
- data/spec/arachni/snapshot_spec.rb +15 -15
- data/spec/arachni/state/audit_spec.rb +11 -11
- data/spec/arachni/state/element_filter_spec.rb +6 -6
- data/spec/arachni/state/framework/rpc_spec.rb +12 -12
- data/spec/arachni/state/framework_spec.rb +125 -121
- data/spec/arachni/state/http_spec.rb +7 -7
- data/spec/arachni/state/options_spec.rb +7 -7
- data/spec/arachni/state/plugins_spec.rb +8 -8
- data/spec/arachni/state_spec.rb +10 -10
- data/spec/arachni/support/buffer/autoflush_spec.rb +16 -16
- data/spec/arachni/support/buffer/base_spec.rb +39 -39
- data/spec/arachni/support/cache/least_cost_replacement_spec.rb +18 -18
- data/spec/arachni/support/cache/least_recently_pushed_spec.rb +24 -24
- data/spec/arachni/support/cache/least_recently_used_spec.rb +20 -20
- data/spec/arachni/support/cache/preference_spec.rb +4 -4
- data/spec/arachni/support/cache/random_replacement_spec.rb +8 -8
- data/spec/arachni/support/crypto/rsa_aes_cbc_spec.rb +1 -1
- data/spec/arachni/support/database/hash_spec.rb +44 -43
- data/spec/arachni/support/database/queue_spec.rb +27 -27
- data/spec/arachni/support/lookup/hash_set_spec.rb +8 -8
- data/spec/arachni/support/lookup/moolb_spec.rb +3 -3
- data/spec/arachni/support/mixins/observable_spec.rb +6 -6
- data/spec/arachni/support/signature_spec.rb +19 -19
- data/spec/arachni/trainer_spec.rb +39 -39
- data/spec/arachni/typhoeus/hydra_spec.rb +2 -2
- data/spec/arachni/uri/scope_spec.rb +66 -66
- data/spec/arachni/uri_spec.rb +107 -105
- data/spec/arachni/utilities_spec.rb +40 -40
- data/spec/components/checks/active/csrf_spec.rb +8 -8
- data/spec/components/checks/active/no_sql_injection_spec.rb +1 -1
- data/spec/components/checks/active/sql_injection_spec.rb +16 -16
- data/spec/components/checks/active/trainer_spec.rb +4 -4
- data/spec/components/checks/active/unvalidated_redirect_dom_spec.rb +4 -2
- data/spec/components/checks/active/xpath_injection_spec.rb +1 -1
- data/spec/components/checks/active/xss_dom_script_context_spec.rb +51 -21
- data/spec/components/checks/active/xss_dom_spec.rb +46 -24
- data/spec/components/checks/passive/allowed_methods_spec.rb +1 -1
- data/spec/components/checks/passive/grep/cookie_set_for_parent_domain_spec.rb +1 -1
- data/spec/components/checks/passive/grep/hsts_spec.rb +2 -2
- data/spec/components/checks/passive/grep/http_only_cookies_spec.rb +1 -1
- data/spec/components/checks/passive/grep/insecure_cookies_spec.rb +1 -1
- data/spec/components/checks/passive/grep/insecure_cors_policy_spec.rb +2 -2
- data/spec/components/checks/passive/grep/password_autocomplete_spec.rb +1 -1
- data/spec/components/checks/passive/grep/private_ip_spec.rb +3 -3
- data/spec/components/checks/passive/grep/unencrypted_password_forms_spec.rb +1 -1
- data/spec/components/checks/passive/grep/x_frame_options_spec.rb +2 -2
- data/spec/components/checks/passive/interesting_responses_spec.rb +2 -2
- data/spec/components/checks/passive/webdav_spec.rb +1 -1
- data/spec/components/checks/passive/xst_spec.rb +1 -1
- data/spec/components/fingerprinters/servers/apache_spec.rb +2 -2
- data/spec/components/path_extractors/comments_spec.rb +5 -1
- data/spec/components/path_extractors/scripts_spec.rb +5 -2
- data/spec/components/plugins/autologin_spec.rb +22 -22
- data/spec/components/plugins/autothrottle_spec.rb +6 -5
- data/spec/components/plugins/content_types_spec.rb +4 -4
- data/spec/components/plugins/cookie_collector_spec.rb +5 -5
- data/spec/components/plugins/exec_spec.rb +12 -12
- data/spec/components/plugins/form_dicattack_spec.rb +3 -3
- data/spec/components/plugins/headers_collector_spec.rb +8 -8
- data/spec/components/plugins/healthmap_spec.rb +3 -3
- data/spec/components/plugins/http_dicattack_spec.rb +3 -3
- data/spec/components/plugins/login_script_spec.rb +79 -22
- data/spec/components/plugins/meta/remedies/discovery_spec.rb +3 -2
- data/spec/components/plugins/meta/remedies/timing_attacks_spec.rb +3 -3
- data/spec/components/plugins/meta/uniformity_spec.rb +2 -2
- data/spec/components/plugins/restrict_to_dom_state_spec.rb +1 -1
- data/spec/components/plugins/script_spec.rb +1 -1
- data/spec/components/plugins/uncommon_headers_spec.rb +2 -2
- data/spec/components/plugins/vector_collector_spec.rb +2 -2
- data/spec/components/plugins/vector_feed_spec.rb +40 -40
- data/spec/components/plugins/waf_detector_spec.rb +6 -6
- data/spec/components/reporters/json_spec.rb +4 -4
- data/spec/components/reporters/marshal_spec.rb +2 -2
- data/spec/components/reporters/yaml_spec.rb +3 -2
- data/spec/external/wavsep/active/sqli_spec.rb +1 -3
- data/spec/spec_helper.rb +4 -0
- data/spec/support/factories/element/ui_form.rb +14 -0
- data/spec/support/factories/element/ui_input.rb +13 -0
- data/spec/support/factories/issue.rb +0 -13
- data/spec/support/fixtures/report.afr +0 -0
- data/spec/support/fixtures/{taint_check/taint.rb → signature_check/signature.rb} +2 -2
- data/spec/support/helpers/browser_cluster/jobs/taint_tracer.rb +11 -11
- data/spec/support/helpers/framework.rb +1 -1
- data/spec/support/helpers/pages.rb +2 -2
- data/spec/support/servers/arachni/browser.rb +139 -0
- data/spec/support/servers/arachni/browser/javascript/taint_tracer.rb +40 -0
- data/spec/support/servers/arachni/element/capabilities/analyzable/{taint.rb → signature.rb} +0 -0
- data/spec/support/servers/arachni/element/input/input_dom.rb +102 -0
- data/spec/support/servers/arachni/element/ui_form/ui_form_dom.rb +238 -0
- data/spec/support/servers/checks/active/trainer_check.rb +7 -7
- data/spec/support/servers/checks/active/unvalidated_redirect_dom.rb +22 -6
- data/spec/support/servers/checks/active/xss_dom.rb +50 -0
- data/spec/support/servers/checks/active/xss_dom_script_context.rb +53 -0
- data/spec/support/shared/browser/javascript/taint_tracer/sink/base.rb +6 -6
- data/spec/support/shared/check.rb +10 -12
- data/spec/support/shared/component/options/base.rb +24 -24
- data/spec/support/shared/element/base.rb +25 -25
- data/spec/support/shared/element/capabilities/auditable.rb +116 -140
- data/spec/support/shared/element/capabilities/dom_only.rb +65 -0
- data/spec/support/shared/element/capabilities/inputtable.rb +71 -86
- data/spec/support/shared/element/capabilities/mutable.rb +122 -111
- data/spec/support/shared/element/capabilities/refreshable.rb +10 -10
- data/spec/support/shared/element/capabilities/{submitable.rb → submittable.rb} +26 -26
- data/spec/support/shared/element/capabilities/with_auditor.rb +10 -10
- data/spec/support/shared/element/capabilities/with_dom.rb +8 -8
- data/spec/support/shared/element/capabilities/with_node.rb +4 -6
- data/spec/support/shared/element/capabilities/with_scope.rb +2 -2
- data/spec/support/shared/element/capabilities/with_source.rb +6 -8
- data/spec/support/shared/element/dom.rb +144 -0
- data/spec/support/shared/element/dom/auditable.rb +42 -0
- data/spec/support/shared/element/dom/inputtable.rb +5 -0
- data/spec/support/shared/element/dom/mutable.rb +3 -0
- data/spec/support/shared/element/dom/submittable.rb +119 -0
- data/spec/support/shared/external/wavsep.rb +3 -3
- data/spec/support/shared/fingerprinter.rb +2 -2
- data/spec/support/shared/framework.rb +1 -1
- data/spec/support/shared/http/message.rb +9 -9
- data/spec/support/shared/option_group.rb +17 -17
- data/spec/support/shared/path_extractor.rb +1 -1
- data/spec/support/shared/plugin.rb +2 -2
- data/spec/support/shared/support/cache.rb +57 -57
- data/spec/support/shared/support/lookup.rb +25 -25
- data/ui/cli/framework.rb +22 -11
- data/ui/cli/framework/option_parser.rb +15 -0
- data/ui/cli/option_parser.rb +8 -1
- data/ui/cli/output.rb +2 -1
- metadata +54 -20
- data/components/checks/active/xss_dom_inputs.rb +0 -236
- data/spec/components/checks/active/xss_dom_inputs_spec.rb +0 -30
- data/spec/support/servers/checks/active/xss_dom_inputs.rb +0 -59
- data/spec/support/shared/element/capabilities/auditable/dom.rb +0 -322
@@ -1,12 +1,26 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Arachni::Element::Form::DOM do
|
4
|
-
|
4
|
+
inputs = { 'param' => '1' }
|
5
|
+
|
6
|
+
it_should_behave_like 'element_dom'
|
7
|
+
|
8
|
+
it_should_behave_like 'with_node'
|
9
|
+
it_should_behave_like 'with_auditor'
|
10
|
+
|
11
|
+
it_should_behave_like 'submittable_dom'
|
12
|
+
it_should_behave_like 'inputtable_dom', inputs: inputs
|
13
|
+
it_should_behave_like 'mutable_dom', inputs: inputs
|
14
|
+
it_should_behave_like 'auditable_dom'
|
5
15
|
|
6
16
|
def auditable_extract_parameters( page )
|
7
17
|
YAML.load( page.document.css( 'body' ).text )
|
8
18
|
end
|
9
19
|
|
20
|
+
def run
|
21
|
+
auditor.browser_cluster.wait
|
22
|
+
end
|
23
|
+
|
10
24
|
before :each do
|
11
25
|
@framework = Arachni::Framework.new
|
12
26
|
@page = Arachni::Page.from_url( "#{url}/form" )
|
@@ -33,25 +47,25 @@ describe Arachni::Element::Form::DOM do
|
|
33
47
|
|
34
48
|
describe '#type' do
|
35
49
|
it 'returns :form_dom' do
|
36
|
-
subject.type.
|
50
|
+
expect(subject.type).to eq(:form_dom)
|
37
51
|
end
|
38
52
|
end
|
39
53
|
|
40
54
|
describe '.type' do
|
41
55
|
it 'returns :form_dom' do
|
42
|
-
described_class.type.
|
56
|
+
expect(described_class.type).to eq(:form_dom)
|
43
57
|
end
|
44
58
|
end
|
45
59
|
|
46
60
|
describe '#parent' do
|
47
61
|
it 'returns the parent element' do
|
48
|
-
subject.parent.
|
62
|
+
expect(subject.parent).to be_kind_of Arachni::Element::Form
|
49
63
|
end
|
50
64
|
end
|
51
65
|
|
52
66
|
describe '#inputs' do
|
53
67
|
it 'uses the parent\'s inputs' do
|
54
|
-
subject.inputs.
|
68
|
+
expect(subject.inputs).to eq(parent.inputs)
|
55
69
|
end
|
56
70
|
end
|
57
71
|
|
@@ -63,17 +77,17 @@ describe Arachni::Element::Form::DOM do
|
|
63
77
|
browser.load subject.page
|
64
78
|
|
65
79
|
element = subject.locate
|
66
|
-
element.
|
80
|
+
expect(element).to be_kind_of Watir::HTMLElement
|
67
81
|
|
68
|
-
parent.class.from_document(
|
82
|
+
expect(parent.class.from_document(
|
69
83
|
parent.url, Nokogiri::HTML(element.html)
|
70
|
-
).first.
|
84
|
+
).first).to eq(parent)
|
71
85
|
|
72
86
|
called = true
|
73
87
|
end
|
74
88
|
|
75
89
|
subject.auditor.browser_cluster.wait
|
76
|
-
called.
|
90
|
+
expect(called).to be_truthy
|
77
91
|
end
|
78
92
|
end
|
79
93
|
|
@@ -91,46 +105,49 @@ describe Arachni::Element::Form::DOM do
|
|
91
105
|
|
92
106
|
page = browser.to_page
|
93
107
|
|
94
|
-
subject.inputs.
|
108
|
+
expect(subject.inputs).to eq(auditable_extract_parameters( page ))
|
95
109
|
called = true
|
96
110
|
end
|
97
111
|
|
98
112
|
subject.auditor.browser_cluster.wait
|
99
|
-
called.
|
113
|
+
expect(called).to be_truthy
|
100
114
|
end
|
101
115
|
|
102
116
|
it 'returns a playable transition' do
|
103
117
|
inputs = { 'param' => 'The.Dude' }
|
104
118
|
subject.update inputs
|
105
119
|
|
106
|
-
|
120
|
+
transitions = []
|
107
121
|
called = false
|
108
122
|
subject.with_browser do |browser|
|
109
123
|
subject.browser = browser
|
110
124
|
browser.load subject.page
|
111
125
|
|
112
|
-
|
126
|
+
transitions = subject.trigger
|
113
127
|
|
114
128
|
page = browser.to_page
|
115
129
|
|
116
|
-
subject.inputs.
|
130
|
+
expect(subject.inputs).to eq(auditable_extract_parameters( page ))
|
117
131
|
called = true
|
118
132
|
end
|
119
133
|
|
120
134
|
subject.auditor.browser_cluster.wait
|
121
|
-
called.
|
135
|
+
expect(called).to be_truthy
|
122
136
|
|
123
137
|
called = false
|
124
138
|
auditor.with_browser do |browser|
|
125
139
|
browser.load subject.page
|
126
|
-
auditable_extract_parameters( browser.to_page ).
|
140
|
+
expect(auditable_extract_parameters( browser.to_page )).to be_falsey
|
141
|
+
|
142
|
+
transitions.each do |transition|
|
143
|
+
transition.play browser
|
144
|
+
end
|
127
145
|
|
128
|
-
|
129
|
-
auditable_extract_parameters( browser.to_page ).should == inputs
|
146
|
+
expect(auditable_extract_parameters( browser.to_page )).to eq(inputs)
|
130
147
|
called = true
|
131
148
|
end
|
132
149
|
auditor.browser_cluster.wait
|
133
|
-
called.
|
150
|
+
expect(called).to be_truthy
|
134
151
|
end
|
135
152
|
end
|
136
153
|
|
@@ -7,11 +7,29 @@ describe Arachni::Element::Form do
|
|
7
7
|
</form>'
|
8
8
|
|
9
9
|
it_should_behave_like 'element'
|
10
|
-
it_should_behave_like 'with_node'
|
10
|
+
it_should_behave_like 'with_node'
|
11
11
|
it_should_behave_like 'with_dom', html
|
12
12
|
it_should_behave_like 'refreshable'
|
13
|
+
it_should_behave_like 'with_source'
|
14
|
+
it_should_behave_like 'with_auditor'
|
15
|
+
|
16
|
+
it_should_behave_like 'submittable'
|
17
|
+
it_should_behave_like 'inputtable'
|
18
|
+
it_should_behave_like 'mutable'
|
13
19
|
it_should_behave_like 'auditable'
|
14
20
|
|
21
|
+
before :each do
|
22
|
+
@framework ||= Arachni::Framework.new
|
23
|
+
@auditor = Auditor.new( Arachni::Page.from_url( url ), @framework )
|
24
|
+
end
|
25
|
+
|
26
|
+
after :each do
|
27
|
+
@framework.reset
|
28
|
+
reset_options
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:auditor) { @auditor }
|
32
|
+
|
15
33
|
def auditable_extract_parameters( resource )
|
16
34
|
YAML.load( resource.body )
|
17
35
|
end
|
@@ -39,29 +57,29 @@ describe Arachni::Element::Form do
|
|
39
57
|
end
|
40
58
|
|
41
59
|
it 'assigned to Arachni::Form for easy access' do
|
42
|
-
Arachni::Form.
|
60
|
+
expect(Arachni::Form).to eq(described_class)
|
43
61
|
end
|
44
62
|
|
45
63
|
describe '#initialize' do
|
46
64
|
describe :method do
|
47
65
|
it 'defaults to :get' do
|
48
|
-
described_class.new( url: url ).method.
|
66
|
+
expect(described_class.new( url: url ).method).to eq(:get)
|
49
67
|
end
|
50
68
|
end
|
51
69
|
describe :name do
|
52
70
|
it 'sets #name' do
|
53
|
-
described_class.new( url: url, name: 'john' ).name.
|
71
|
+
expect(described_class.new( url: url, name: 'john' ).name).to eq('john')
|
54
72
|
end
|
55
73
|
end
|
56
74
|
describe :action do
|
57
75
|
it 'sets #action' do
|
58
76
|
action = "#{url}stuff"
|
59
|
-
described_class.new( url: url, action: action ).action.
|
77
|
+
expect(described_class.new( url: url, action: action ).action).to eq(action)
|
60
78
|
end
|
61
79
|
|
62
80
|
context 'when nil' do
|
63
81
|
it 'defaults to :url' do
|
64
|
-
described_class.new( url: url ).action.
|
82
|
+
expect(described_class.new( url: url ).action).to eq(url)
|
65
83
|
end
|
66
84
|
end
|
67
85
|
end
|
@@ -69,26 +87,26 @@ describe Arachni::Element::Form do
|
|
69
87
|
|
70
88
|
describe '#mutation_with_original_values?' do
|
71
89
|
it 'returns false' do
|
72
|
-
subject.mutation_with_original_values
|
90
|
+
expect(subject.mutation_with_original_values?).to be_falsey
|
73
91
|
end
|
74
92
|
|
75
93
|
context 'when #mutation_with_original_values' do
|
76
94
|
it 'returns true' do
|
77
95
|
subject.mutation_with_original_values
|
78
|
-
subject.mutation_with_original_values
|
96
|
+
expect(subject.mutation_with_original_values?).to be_truthy
|
79
97
|
end
|
80
98
|
end
|
81
99
|
end
|
82
100
|
|
83
101
|
describe '#mutation_with_sample_values?' do
|
84
102
|
it 'returns false' do
|
85
|
-
subject.mutation_with_sample_values
|
103
|
+
expect(subject.mutation_with_sample_values?).to be_falsey
|
86
104
|
end
|
87
105
|
|
88
106
|
context 'when #mutation_with_sample_values' do
|
89
107
|
it 'returns true' do
|
90
108
|
subject.mutation_with_sample_values
|
91
|
-
subject.mutation_with_sample_values
|
109
|
+
expect(subject.mutation_with_sample_values?).to be_truthy
|
92
110
|
end
|
93
111
|
end
|
94
112
|
end
|
@@ -97,7 +115,7 @@ describe Arachni::Element::Form do
|
|
97
115
|
context 'when #force_train?' do
|
98
116
|
it 'returns #mutation_id' do
|
99
117
|
subject.mutation_with_original_values
|
100
|
-
subject.audit_id( 'stuff' ).
|
118
|
+
expect(subject.audit_id( 'stuff' )).to eq(subject.id)
|
101
119
|
end
|
102
120
|
end
|
103
121
|
end
|
@@ -114,7 +132,7 @@ describe Arachni::Element::Form do
|
|
114
132
|
subject.audit( 'stuff', each_mutation: each_mutation ) {}
|
115
133
|
subject.http.run
|
116
134
|
|
117
|
-
had_mutation_with_original_values.
|
135
|
+
expect(had_mutation_with_original_values).to be_falsey
|
118
136
|
end
|
119
137
|
|
120
138
|
it 'ignores mutation_with_sample_values' do
|
@@ -127,7 +145,7 @@ describe Arachni::Element::Form do
|
|
127
145
|
subject.audit( 'stuff', each_mutation: each_mutation ) {}
|
128
146
|
subject.http.run
|
129
147
|
|
130
|
-
had_mutation_with_sample_values.
|
148
|
+
expect(had_mutation_with_sample_values).to be_falsey
|
131
149
|
end
|
132
150
|
end
|
133
151
|
end
|
@@ -135,8 +153,8 @@ describe Arachni::Element::Form do
|
|
135
153
|
describe '#name_or_id' do
|
136
154
|
context 'when a #name is available' do
|
137
155
|
it 'returns it' do
|
138
|
-
described_class.new( url: url, name: 'john' ).
|
139
|
-
name_or_id.
|
156
|
+
expect(described_class.new( url: url, name: 'john' ).
|
157
|
+
name_or_id).to eq('john')
|
140
158
|
end
|
141
159
|
end
|
142
160
|
|
@@ -144,8 +162,8 @@ describe Arachni::Element::Form do
|
|
144
162
|
subject { described_class.new( url: url, id: 'john' ) }
|
145
163
|
|
146
164
|
it 'returns the configured :id' do
|
147
|
-
subject.name.
|
148
|
-
subject.name_or_id.
|
165
|
+
expect(subject.name).to be_nil
|
166
|
+
expect(subject.name_or_id).to eq('john')
|
149
167
|
end
|
150
168
|
end
|
151
169
|
|
@@ -153,7 +171,7 @@ describe Arachni::Element::Form do
|
|
153
171
|
subject { described_class.new( url: url ) }
|
154
172
|
|
155
173
|
it 'returns nil' do
|
156
|
-
subject.name_or_id.
|
174
|
+
expect(subject.name_or_id).to be_nil
|
157
175
|
end
|
158
176
|
end
|
159
177
|
end
|
@@ -162,33 +180,33 @@ describe Arachni::Element::Form do
|
|
162
180
|
context 'when there are no #inputs' do
|
163
181
|
it 'returns nil' do
|
164
182
|
subject.inputs = {}
|
165
|
-
subject.dom.
|
183
|
+
expect(subject.dom).to be_nil
|
166
184
|
end
|
167
185
|
end
|
168
186
|
|
169
187
|
context 'when there is no #node' do
|
170
188
|
it 'returns nil' do
|
171
189
|
subject.source = nil
|
172
|
-
subject.dom.
|
190
|
+
expect(subject.dom).to be_nil
|
173
191
|
end
|
174
192
|
end
|
175
193
|
end
|
176
194
|
|
177
195
|
describe '#force_train?' do
|
178
196
|
it 'returns false' do
|
179
|
-
subject.force_train
|
197
|
+
expect(subject.force_train?).to be_falsey
|
180
198
|
end
|
181
199
|
|
182
200
|
context 'when #mutation_with_original_values?' do
|
183
201
|
it 'returns true' do
|
184
202
|
subject.mutation_with_original_values
|
185
|
-
subject.force_train
|
203
|
+
expect(subject.force_train?).to be_truthy
|
186
204
|
end
|
187
205
|
end
|
188
206
|
context 'when #mutation_with_sample_values?' do
|
189
207
|
it 'returns true' do
|
190
208
|
subject.mutation_with_sample_values
|
191
|
-
subject.force_train
|
209
|
+
expect(subject.force_train?).to be_truthy
|
192
210
|
end
|
193
211
|
end
|
194
212
|
end
|
@@ -221,11 +239,11 @@ describe Arachni::Element::Form do
|
|
221
239
|
let(:method) { :get }
|
222
240
|
|
223
241
|
it 'removes the URL query' do
|
224
|
-
subject.action.
|
242
|
+
expect(subject.action).to eq(url)
|
225
243
|
end
|
226
244
|
|
227
245
|
it 'merges the URL query parameters with the given :inputs' do
|
228
|
-
subject.inputs.
|
246
|
+
expect(subject.inputs).to eq(query_inputs.merge( option_inputs ))
|
229
247
|
end
|
230
248
|
|
231
249
|
context 'when URL query parameters and :inputs have the same name' do
|
@@ -237,7 +255,7 @@ describe Arachni::Element::Form do
|
|
237
255
|
end
|
238
256
|
|
239
257
|
it 'it gives precedence to the :inputs' do
|
240
|
-
subject.inputs.
|
258
|
+
expect(subject.inputs).to eq(query_inputs.merge( option_inputs ))
|
241
259
|
end
|
242
260
|
end
|
243
261
|
end
|
@@ -246,11 +264,11 @@ describe Arachni::Element::Form do
|
|
246
264
|
let(:method) { :post }
|
247
265
|
|
248
266
|
it 'preserves the URL query' do
|
249
|
-
subject.action.
|
267
|
+
expect(subject.action).to eq(action)
|
250
268
|
end
|
251
269
|
|
252
270
|
it 'ignores the URL query parameters' do
|
253
|
-
subject.inputs.
|
271
|
+
expect(subject.inputs).to eq(option_inputs)
|
254
272
|
end
|
255
273
|
end
|
256
274
|
end
|
@@ -270,13 +288,14 @@ describe Arachni::Element::Form do
|
|
270
288
|
}
|
271
289
|
}
|
272
290
|
|
273
|
-
described_class.new( options ).details_for( :password ).
|
291
|
+
expect(described_class.new( options ).details_for( :password )).to eq(
|
274
292
|
options[:inputs]['password']
|
293
|
+
)
|
275
294
|
end
|
276
295
|
end
|
277
296
|
describe 'when no data is available' do
|
278
297
|
it 'return nil' do
|
279
|
-
described_class.new( options ).details_for( :username ).
|
298
|
+
expect(described_class.new( options ).details_for( :username )).to eq({})
|
280
299
|
end
|
281
300
|
end
|
282
301
|
end
|
@@ -284,12 +303,12 @@ describe Arachni::Element::Form do
|
|
284
303
|
describe '#name' do
|
285
304
|
context 'when there is a form name' do
|
286
305
|
it 'returns it' do
|
287
|
-
described_class.new( options ).name.
|
306
|
+
expect(described_class.new( options ).name).to eq(options[:name])
|
288
307
|
end
|
289
308
|
end
|
290
309
|
describe 'when no data is available' do
|
291
310
|
it 'return nil' do
|
292
|
-
described_class.new( url: options[:url] ).name.
|
311
|
+
expect(described_class.new( url: options[:url] ).name).to be_nil
|
293
312
|
end
|
294
313
|
end
|
295
314
|
end
|
@@ -314,8 +333,8 @@ describe Arachni::Element::Form do
|
|
314
333
|
}
|
315
334
|
|
316
335
|
e = described_class.new( options )
|
317
|
-
e.field_type_for( 'password' ).
|
318
|
-
e.field_type_for( 'hidden_field' ).
|
336
|
+
expect(e.field_type_for( 'password' )).to eq(:password)
|
337
|
+
expect(e.field_type_for( 'hidden_field' )).to eq(:hidden)
|
319
338
|
end
|
320
339
|
end
|
321
340
|
|
@@ -333,8 +352,8 @@ describe Arachni::Element::Form do
|
|
333
352
|
</body>
|
334
353
|
</html>'
|
335
354
|
|
336
|
-
described_class.from_document( url, html ).
|
337
|
-
first.requires_password
|
355
|
+
expect(described_class.from_document( url, html ).
|
356
|
+
first.requires_password?).to be_truthy
|
338
357
|
end
|
339
358
|
end
|
340
359
|
context 'when the form does not have a password field' do
|
@@ -349,8 +368,8 @@ describe Arachni::Element::Form do
|
|
349
368
|
</body>
|
350
369
|
</html>'
|
351
370
|
|
352
|
-
described_class.from_document( url, html ).
|
353
|
-
first.requires_password
|
371
|
+
expect(described_class.from_document( url, html ).
|
372
|
+
first.requires_password?).to be_falsey
|
354
373
|
end
|
355
374
|
end
|
356
375
|
end
|
@@ -370,16 +389,16 @@ describe Arachni::Element::Form do
|
|
370
389
|
has_sample ||= false
|
371
390
|
|
372
391
|
e.mutations( 'seed' ).each do |m|
|
373
|
-
m.url.
|
374
|
-
m.action.
|
392
|
+
expect(m.url).to eq(e.url)
|
393
|
+
expect(m.action).to eq(e.action)
|
375
394
|
|
376
395
|
if m.mutation_with_original_values?
|
377
|
-
m.inputs.
|
396
|
+
expect(m.inputs).to eq(e.inputs)
|
378
397
|
has_original ||= true
|
379
398
|
end
|
380
399
|
end
|
381
400
|
|
382
|
-
has_original.
|
401
|
+
expect(has_original).to be_truthy
|
383
402
|
end
|
384
403
|
end
|
385
404
|
end
|
@@ -399,17 +418,17 @@ describe Arachni::Element::Form do
|
|
399
418
|
has_sample ||= false
|
400
419
|
|
401
420
|
e.mutations( 'seed' ).each do |m|
|
402
|
-
m.url.
|
403
|
-
m.action.
|
421
|
+
expect(m.url).to eq(e.url)
|
422
|
+
expect(m.action).to eq(e.action)
|
404
423
|
|
405
424
|
if m.mutation_with_sample_values?
|
406
|
-
m.affected_input_name.
|
407
|
-
m.inputs.
|
425
|
+
expect(m.affected_input_name).to eq(described_class::SAMPLE_VALUES)
|
426
|
+
expect(m.inputs).to eq(Arachni::Options.input.fill( e.inputs ))
|
408
427
|
has_sample ||= true
|
409
428
|
end
|
410
429
|
end
|
411
430
|
|
412
|
-
has_sample.
|
431
|
+
expect(has_sample).to be_truthy
|
413
432
|
end
|
414
433
|
end
|
415
434
|
end
|
@@ -427,14 +446,14 @@ describe Arachni::Element::Form do
|
|
427
446
|
e.mutations( 'seed' ).each do |m|
|
428
447
|
next if m.mutation_with_original_values? || m.mutation_with_sample_values?
|
429
448
|
|
430
|
-
m.url.
|
431
|
-
m.action.
|
449
|
+
expect(m.url).to eq(e.url)
|
450
|
+
expect(m.action).to eq(e.action)
|
432
451
|
|
433
|
-
m.inputs.
|
452
|
+
expect(m.inputs).not_to eq(e.inputs)
|
434
453
|
checked = true
|
435
454
|
end
|
436
455
|
|
437
|
-
checked.
|
456
|
+
expect(checked).to be_truthy
|
438
457
|
end
|
439
458
|
|
440
459
|
it 'sets #affected_input_name to the name of the fuzzed input' do
|
@@ -448,16 +467,16 @@ describe Arachni::Element::Form do
|
|
448
467
|
e.mutations( 'seed' ).each do |m|
|
449
468
|
next if m.mutation_with_original_values? || m.mutation_with_sample_values?
|
450
469
|
|
451
|
-
m.url.
|
452
|
-
m.action.
|
470
|
+
expect(m.url).to eq(e.url)
|
471
|
+
expect(m.action).to eq(e.action)
|
453
472
|
|
454
|
-
m.affected_input_name.
|
455
|
-
m.inputs[m.affected_input_name].
|
473
|
+
expect(m.affected_input_name).not_to eq(e.affected_input_name)
|
474
|
+
expect(m.inputs[m.affected_input_name]).to include 'seed'
|
456
475
|
|
457
476
|
checked = true
|
458
477
|
end
|
459
478
|
|
460
|
-
checked.
|
479
|
+
expect(checked).to be_truthy
|
461
480
|
end
|
462
481
|
|
463
482
|
context 'when it contains more than 1 password field' do
|
@@ -471,9 +490,9 @@ describe Arachni::Element::Form do
|
|
471
490
|
|
472
491
|
e = described_class.from_document( 'http://test.com', form ).first
|
473
492
|
|
474
|
-
e.mutations( 'seed' ).select do |m|
|
493
|
+
expect(e.mutations( 'seed' ).select do |m|
|
475
494
|
m.inputs['my_pass'] == m.inputs['my_pass_validation']
|
476
|
-
end.
|
495
|
+
end).to be_any
|
477
496
|
end
|
478
497
|
end
|
479
498
|
|
@@ -506,10 +525,10 @@ describe Arachni::Element::Form do
|
|
506
525
|
numbers = mutations.map { |f| f['numbers'] }
|
507
526
|
|
508
527
|
include = %w(volvo Saab mercedes audi)
|
509
|
-
(manufacturers & include).
|
528
|
+
expect(manufacturers & include).to eq(include)
|
510
529
|
|
511
530
|
include = %w(33 22)
|
512
|
-
(numbers & include).
|
531
|
+
expect(numbers & include).to eq(include)
|
513
532
|
end
|
514
533
|
end
|
515
534
|
|
@@ -517,7 +536,7 @@ describe Arachni::Element::Form do
|
|
517
536
|
it 'does not add mutations with original nor default values' do
|
518
537
|
e = described_class.new( options )
|
519
538
|
mutations = e.mutations( @seed, skip_original: true )
|
520
|
-
mutations.select { |m| m.mutation? }.size.
|
539
|
+
expect(mutations.select { |m| m.mutation? }.size).to eq(10)
|
521
540
|
end
|
522
541
|
end
|
523
542
|
end
|
@@ -526,7 +545,7 @@ describe Arachni::Element::Form do
|
|
526
545
|
it 'sets the name of the input holding the nonce' do
|
527
546
|
f = described_class.new( url: url, inputs: { nonce: 'value' } )
|
528
547
|
f.nonce_name = 'nonce'
|
529
|
-
f.nonce_name.
|
548
|
+
expect(f.nonce_name).to eq('nonce')
|
530
549
|
end
|
531
550
|
|
532
551
|
context 'when there is no input called nonce_name' do
|
@@ -548,13 +567,13 @@ describe Arachni::Element::Form do
|
|
548
567
|
it 'returns true' do
|
549
568
|
f = described_class.new( url: url, inputs: { nonce: 'value' } )
|
550
569
|
f.nonce_name = 'nonce'
|
551
|
-
f.has_nonce
|
570
|
+
expect(f.has_nonce?).to be_truthy
|
552
571
|
end
|
553
572
|
end
|
554
573
|
context 'when the form does not have a nonce' do
|
555
574
|
it 'returns false' do
|
556
575
|
f = described_class.new( url: url, inputs: { nonce: 'value' } )
|
557
|
-
f.has_nonce
|
576
|
+
expect(f.has_nonce?).to be_falsey
|
558
577
|
end
|
559
578
|
end
|
560
579
|
end
|
@@ -573,7 +592,7 @@ describe Arachni::Element::Form do
|
|
573
592
|
|
574
593
|
f.submit { |res| body = res.body }
|
575
594
|
http.run
|
576
|
-
body_should.
|
595
|
+
expect(body_should).to eq(body)
|
577
596
|
end
|
578
597
|
end
|
579
598
|
context 'when method is get' do
|
@@ -589,7 +608,7 @@ describe Arachni::Element::Form do
|
|
589
608
|
|
590
609
|
f.submit.on_complete { |res| body = res.body }
|
591
610
|
http.run
|
592
|
-
body_should.
|
611
|
+
expect(body_should).to eq(body)
|
593
612
|
end
|
594
613
|
end
|
595
614
|
context 'when the form has a nonce' do
|
@@ -612,20 +631,20 @@ describe Arachni::Element::Form do
|
|
612
631
|
|
613
632
|
subject.submit { |res| body = res.body }
|
614
633
|
http.run
|
615
|
-
body.
|
616
|
-
body.to_i.
|
634
|
+
expect(body).not_to eq(subject.default_inputs['nonce'])
|
635
|
+
expect(body.to_i).to be > 0
|
617
636
|
end
|
618
637
|
|
619
638
|
context 'and it could not refresh it' do
|
620
639
|
it 'submits it anyway' do
|
621
640
|
body = nil
|
622
641
|
|
623
|
-
subject.
|
642
|
+
allow(subject).to receive(:refresh) { nil }
|
624
643
|
subject.submit { |res| body = res.body }
|
625
644
|
http.run
|
626
645
|
|
627
|
-
body.
|
628
|
-
body.to_i.
|
646
|
+
expect(body).not_to eq(subject.default_inputs['nonce'])
|
647
|
+
expect(body.to_i).to be > 0
|
629
648
|
end
|
630
649
|
end
|
631
650
|
end
|
@@ -635,7 +654,7 @@ describe Arachni::Element::Form do
|
|
635
654
|
it 'returns a simplified version of the form attributes and inputs as a Hash' do
|
636
655
|
f = described_class.new( options )
|
637
656
|
f.update 'user' => 'blah'
|
638
|
-
f.simple.
|
657
|
+
expect(f.simple).to eq({
|
639
658
|
url: options[:url],
|
640
659
|
action: options[:url],
|
641
660
|
name: 'login-form',
|
@@ -645,20 +664,20 @@ describe Arachni::Element::Form do
|
|
645
664
|
'password' => 's3cr3t'
|
646
665
|
},
|
647
666
|
source: html
|
648
|
-
}
|
667
|
+
})
|
649
668
|
end
|
650
669
|
end
|
651
670
|
|
652
671
|
describe '#type' do
|
653
672
|
it 'is "form"' do
|
654
|
-
described_class.new( options ).type.
|
673
|
+
expect(described_class.new( options ).type).to eq(:form)
|
655
674
|
end
|
656
675
|
end
|
657
676
|
|
658
677
|
describe '.from_document' do
|
659
678
|
context 'when the response does not contain any forms' do
|
660
679
|
it 'returns an empty array' do
|
661
|
-
described_class.from_document( '', '' ).
|
680
|
+
expect(described_class.from_document( '', '' )).to be_empty
|
662
681
|
end
|
663
682
|
end
|
664
683
|
|
@@ -682,8 +701,8 @@ EOHTML
|
|
682
701
|
Arachni::Options.scope.exclude_path_patterns = [/exclude/]
|
683
702
|
|
684
703
|
forms = described_class.from_document( url, form_html )
|
685
|
-
forms.size.
|
686
|
-
forms.first.action.
|
704
|
+
expect(forms.size).to eq(1)
|
705
|
+
expect(forms.first.action).to eq(utilities.normalize_url( url + '/form_action' ))
|
687
706
|
end
|
688
707
|
|
689
708
|
context 'when ignore_scope is set' do
|
@@ -691,7 +710,7 @@ EOHTML
|
|
691
710
|
Arachni::Options.scope.exclude_path_patterns = [/exclude/]
|
692
711
|
|
693
712
|
forms = described_class.from_document( url, form_html, true )
|
694
|
-
forms.size.
|
713
|
+
expect(forms.size).to eq(2)
|
695
714
|
end
|
696
715
|
end
|
697
716
|
end
|
@@ -711,16 +730,16 @@ EOHTML
|
|
711
730
|
</html>'
|
712
731
|
|
713
732
|
form = described_class.from_document( url, html ).first
|
714
|
-
form.action.
|
715
|
-
form.name.
|
716
|
-
form.url.
|
717
|
-
form.method.
|
718
|
-
form.inputs.
|
733
|
+
expect(form.action).to eq(utilities.normalize_url( url + '/form_action' ))
|
734
|
+
expect(form.name).to eq('my_form')
|
735
|
+
expect(form.url).to eq(url)
|
736
|
+
expect(form.method).to eq(:get)
|
737
|
+
expect(form.inputs).to eq({
|
719
738
|
'my_first_input' => 'my_first_value',
|
720
739
|
'my_second_input' => 'my_second_value'
|
721
|
-
}
|
740
|
+
})
|
722
741
|
form.inputs.keys.each do |input|
|
723
|
-
form.field_type_for( input ).
|
742
|
+
expect(form.field_type_for( input )).to eq(:text)
|
724
743
|
end
|
725
744
|
end
|
726
745
|
end
|
@@ -739,16 +758,16 @@ EOHTML
|
|
739
758
|
</html>'
|
740
759
|
|
741
760
|
form = described_class.from_document( url, html ).first
|
742
|
-
form.action.
|
743
|
-
form.name.
|
744
|
-
form.url.
|
745
|
-
form.method.
|
746
|
-
form.inputs.
|
761
|
+
expect(form.action).to eq(utilities.normalize_url( url + '/form_action' ))
|
762
|
+
expect(form.name).to eq('my_form')
|
763
|
+
expect(form.url).to eq(url)
|
764
|
+
expect(form.method).to eq(:get)
|
765
|
+
expect(form.inputs).to eq({
|
747
766
|
'vehicle' => 'Bike',
|
748
767
|
'stuff' => 'Car'
|
749
|
-
}
|
768
|
+
})
|
750
769
|
form.inputs.keys.each do |input|
|
751
|
-
form.field_type_for( input ).
|
770
|
+
expect(form.field_type_for( input )).to eq(:checkbox)
|
752
771
|
end
|
753
772
|
end
|
754
773
|
end
|
@@ -767,16 +786,16 @@ EOHTML
|
|
767
786
|
</html>'
|
768
787
|
|
769
788
|
form = described_class.from_document( url, html ).first
|
770
|
-
form.action.
|
771
|
-
form.name.
|
772
|
-
form.url.
|
773
|
-
form.method.
|
774
|
-
form.inputs.
|
789
|
+
expect(form.action).to eq(utilities.normalize_url( url + '/form_action' ))
|
790
|
+
expect(form.name).to eq('my_form')
|
791
|
+
expect(form.url).to eq(url)
|
792
|
+
expect(form.method).to eq(:get)
|
793
|
+
expect(form.inputs).to eq({
|
775
794
|
'my_first_input' => 'my_first_value',
|
776
795
|
'my_second_input' => 'my_second_value'
|
777
|
-
}
|
796
|
+
})
|
778
797
|
form.inputs.keys.each do |input|
|
779
|
-
form.field_type_for( input ).
|
798
|
+
expect(form.field_type_for( input )).to eq(:radio)
|
780
799
|
end
|
781
800
|
end
|
782
801
|
end
|
@@ -794,12 +813,12 @@ EOHTML
|
|
794
813
|
</html>'
|
795
814
|
|
796
815
|
form = described_class.from_document( url, html ).first
|
797
|
-
form.action.
|
798
|
-
form.name.
|
799
|
-
form.url.
|
800
|
-
form.method.
|
801
|
-
form.field_type_for( 'my_button' ).
|
802
|
-
form.inputs.
|
816
|
+
expect(form.action).to eq(utilities.normalize_url( url + '/form_action' ))
|
817
|
+
expect(form.name).to eq('my_form')
|
818
|
+
expect(form.url).to eq(url)
|
819
|
+
expect(form.method).to eq(:get)
|
820
|
+
expect(form.field_type_for( 'my_button' )).to eq(:submit)
|
821
|
+
expect(form.inputs).to eq({ 'my_button' => 'my_button_value' })
|
803
822
|
end
|
804
823
|
end
|
805
824
|
|
@@ -816,23 +835,23 @@ EOHTML
|
|
816
835
|
</html>'
|
817
836
|
|
818
837
|
forms = described_class.from_document( url, html )
|
819
|
-
forms.size.
|
838
|
+
expect(forms.size).to eq(2)
|
820
839
|
|
821
840
|
form = forms.first
|
822
|
-
form.action.
|
823
|
-
form.name.
|
824
|
-
form.url.
|
825
|
-
form.method.
|
826
|
-
form.field_type_for( 'choice' ).
|
827
|
-
form.inputs['choice'].
|
841
|
+
expect(form.action).to eq(utilities.normalize_url( url + '/form_action' ))
|
842
|
+
expect(form.name).to eq('my_form')
|
843
|
+
expect(form.url).to eq(url)
|
844
|
+
expect(form.method).to eq(:get)
|
845
|
+
expect(form.field_type_for( 'choice' )).to eq(:submit)
|
846
|
+
expect(form.inputs['choice']).to eq('value 1')
|
828
847
|
|
829
848
|
form = forms[1]
|
830
|
-
form.action.
|
831
|
-
form.name.
|
832
|
-
form.url.
|
833
|
-
form.method.
|
834
|
-
form.field_type_for( 'choice' ).
|
835
|
-
form.inputs['choice'].
|
849
|
+
expect(form.action).to eq(utilities.normalize_url( url + '/form_action' ))
|
850
|
+
expect(form.name).to eq('my_form')
|
851
|
+
expect(form.url).to eq(url)
|
852
|
+
expect(form.method).to eq(:get)
|
853
|
+
expect(form.field_type_for( 'choice' )).to eq(:submit)
|
854
|
+
expect(form.inputs['choice']).to eq('value 2')
|
836
855
|
end
|
837
856
|
end
|
838
857
|
|
@@ -859,16 +878,16 @@ EOHTML
|
|
859
878
|
</html>'
|
860
879
|
|
861
880
|
form = described_class.from_document( url, html ).first
|
862
|
-
form.action.
|
863
|
-
form.name.
|
864
|
-
form.url.
|
865
|
-
form.method.
|
866
|
-
form.inputs.
|
881
|
+
expect(form.action).to eq(utilities.normalize_url( url + '/form_action' ))
|
882
|
+
expect(form.name).to eq('my_form')
|
883
|
+
expect(form.url).to eq(url)
|
884
|
+
expect(form.method).to eq(:get)
|
885
|
+
expect(form.inputs).to eq({
|
867
886
|
'manufacturer' => 'volvo',
|
868
887
|
'numbers' => '1'
|
869
|
-
}
|
888
|
+
})
|
870
889
|
form.inputs.keys.each do |input|
|
871
|
-
form.field_type_for( input ).
|
890
|
+
expect(form.field_type_for( input )).to eq(:select)
|
872
891
|
end
|
873
892
|
end
|
874
893
|
end
|
@@ -893,16 +912,16 @@ EOHTML
|
|
893
912
|
</html>'
|
894
913
|
|
895
914
|
form = described_class.from_document( url, html ).first
|
896
|
-
form.action.
|
897
|
-
form.name.
|
898
|
-
form.url.
|
899
|
-
form.method.
|
900
|
-
form.inputs.
|
915
|
+
expect(form.action).to eq(utilities.normalize_url( url + '/form_action' ))
|
916
|
+
expect(form.name).to eq('my_form')
|
917
|
+
expect(form.url).to eq(url)
|
918
|
+
expect(form.method).to eq(:get)
|
919
|
+
expect(form.inputs).to eq({
|
901
920
|
'manufacturer' => 'Volvo',
|
902
921
|
'numbers' => 'One'
|
903
|
-
}
|
922
|
+
})
|
904
923
|
form.inputs.keys.each do |input|
|
905
|
-
form.field_type_for( input ).
|
924
|
+
expect(form.field_type_for( input )).to eq(:select)
|
906
925
|
end
|
907
926
|
end
|
908
927
|
end
|
@@ -929,16 +948,16 @@ EOHTML
|
|
929
948
|
</html>'
|
930
949
|
|
931
950
|
form = described_class.from_document( url, html ).first
|
932
|
-
form.action.
|
933
|
-
form.name.
|
934
|
-
form.url.
|
935
|
-
form.method.
|
936
|
-
form.inputs.
|
951
|
+
expect(form.action).to eq(utilities.normalize_url( url + '/form_action' ))
|
952
|
+
expect(form.name).to eq('my_form')
|
953
|
+
expect(form.url).to eq(url)
|
954
|
+
expect(form.method).to eq(:get)
|
955
|
+
expect(form.inputs).to eq({
|
937
956
|
'manufacturer' => 'Saab',
|
938
957
|
'numbers' => 'Two'
|
939
|
-
}
|
958
|
+
})
|
940
959
|
form.inputs.keys.each do |input|
|
941
|
-
form.field_type_for( input ).
|
960
|
+
expect(form.field_type_for( input )).to eq(:select)
|
942
961
|
end
|
943
962
|
end
|
944
963
|
end
|
@@ -956,13 +975,13 @@ EOHTML
|
|
956
975
|
</html>'
|
957
976
|
|
958
977
|
form = described_class.from_document( url, html ).first
|
959
|
-
form.action.
|
960
|
-
form.name.
|
961
|
-
form.url.
|
962
|
-
form.method.
|
963
|
-
form.inputs.
|
978
|
+
expect(form.action).to eq(utilities.normalize_url( url + '/form_action' ))
|
979
|
+
expect(form.name).to eq('my_form')
|
980
|
+
expect(form.url).to eq(url)
|
981
|
+
expect(form.method).to eq(:get)
|
982
|
+
expect(form.inputs).to eq({ 'manufacturer' => '' })
|
964
983
|
form.inputs.keys.each do |input|
|
965
|
-
form.field_type_for( input ).
|
984
|
+
expect(form.field_type_for( input )).to eq(:select)
|
966
985
|
end
|
967
986
|
end
|
968
987
|
end
|
@@ -988,29 +1007,29 @@ EOHTML
|
|
988
1007
|
</html>'
|
989
1008
|
|
990
1009
|
forms = described_class.from_document( url, html )
|
991
|
-
forms.size.
|
1010
|
+
expect(forms.size).to eq(2)
|
992
1011
|
|
993
1012
|
form = forms.shift
|
994
|
-
form.action.
|
995
|
-
form.name.
|
996
|
-
form.url.
|
997
|
-
form.method.
|
998
|
-
form.inputs.
|
1013
|
+
expect(form.action).to eq(utilities.normalize_url( url + base_url + 'form_action/is/here'))
|
1014
|
+
expect(form.name).to eq('my_form!')
|
1015
|
+
expect(form.url).to eq(url)
|
1016
|
+
expect(form.method).to eq(:get)
|
1017
|
+
expect(form.inputs).to eq({
|
999
1018
|
'text_here' => '',
|
1000
1019
|
'ha' => 'hoo'
|
1001
|
-
}
|
1020
|
+
})
|
1002
1021
|
form.inputs.keys.each do |input|
|
1003
|
-
form.field_type_for( input ).
|
1022
|
+
expect(form.field_type_for( input )).to eq(:text)
|
1004
1023
|
end
|
1005
1024
|
|
1006
1025
|
form = forms.shift
|
1007
|
-
form.action.
|
1008
|
-
form.name.
|
1009
|
-
form.url.
|
1010
|
-
form.method.
|
1011
|
-
form.inputs.
|
1026
|
+
expect(form.action).to eq(utilities.normalize_url( url + '/form_action' ))
|
1027
|
+
expect(form.name).to eq('my_second_form!')
|
1028
|
+
expect(form.url).to eq(url)
|
1029
|
+
expect(form.method).to eq(:post)
|
1030
|
+
expect(form.inputs).to eq({ 'text_here' => "my value" })
|
1012
1031
|
form.inputs.keys.each do |input|
|
1013
|
-
form.field_type_for( input ).
|
1032
|
+
expect(form.field_type_for( input )).to eq(:text)
|
1014
1033
|
end
|
1015
1034
|
end
|
1016
1035
|
end
|
@@ -1046,34 +1065,34 @@ EOHTML
|
|
1046
1065
|
</html>'
|
1047
1066
|
|
1048
1067
|
forms = described_class.from_document( url, html )
|
1049
|
-
forms.size.
|
1068
|
+
expect(forms.size).to eq(3)
|
1050
1069
|
|
1051
1070
|
form = forms.shift
|
1052
|
-
form.action.
|
1053
|
-
form.name.
|
1054
|
-
form.url.
|
1055
|
-
form.method.
|
1056
|
-
form.inputs.
|
1071
|
+
expect(form.action).to eq(utilities.normalize_url( base_url + 'form_2' ))
|
1072
|
+
expect(form.name).to eq('my_form_2')
|
1073
|
+
expect(form.url).to eq(url)
|
1074
|
+
expect(form.method).to eq(:get)
|
1075
|
+
expect(form.inputs).to eq({ 'text_here' => '' })
|
1057
1076
|
|
1058
1077
|
form = forms.shift
|
1059
|
-
form.action.
|
1060
|
-
form.name.
|
1061
|
-
form.url.
|
1062
|
-
form.method.
|
1063
|
-
form.inputs.
|
1078
|
+
expect(form.action).to eq(utilities.normalize_url( url + '/form' ))
|
1079
|
+
expect(form.name).to eq('my_form')
|
1080
|
+
expect(form.url).to eq(url)
|
1081
|
+
expect(form.method).to eq(:post)
|
1082
|
+
expect(form.inputs).to eq({
|
1064
1083
|
'form_input_1' => 'form_val_1',
|
1065
1084
|
'form_input_2' => 'form_val_2'
|
1066
|
-
}
|
1085
|
+
})
|
1067
1086
|
|
1068
1087
|
form = forms.shift
|
1069
|
-
form.action.
|
1070
|
-
form.name.
|
1071
|
-
form.url.
|
1072
|
-
form.method.
|
1073
|
-
form.inputs.
|
1088
|
+
expect(form.action).to eq(utilities.normalize_url( url + '/form_3' ))
|
1089
|
+
expect(form.name).to eq('my_form_3')
|
1090
|
+
expect(form.url).to eq(url)
|
1091
|
+
expect(form.method).to eq(:get)
|
1092
|
+
expect(form.inputs).to eq({
|
1074
1093
|
'form_3_input_1' => 'form_3_val_1',
|
1075
1094
|
'manufacturer' => 'volvo'
|
1076
|
-
}
|
1095
|
+
})
|
1077
1096
|
end
|
1078
1097
|
end
|
1079
1098
|
|
@@ -1096,8 +1115,8 @@ EOHTML
|
|
1096
1115
|
let(:size) { described_class::MAX_SIZE }
|
1097
1116
|
|
1098
1117
|
it 'returns empty array' do
|
1099
|
-
form.inputs['input_1'].
|
1100
|
-
form.inputs['input_2'].
|
1118
|
+
expect(form.inputs['input_1']).to be_empty
|
1119
|
+
expect(form.inputs['input_2']).to eq('val_2')
|
1101
1120
|
end
|
1102
1121
|
end
|
1103
1122
|
|
@@ -1105,8 +1124,8 @@ EOHTML
|
|
1105
1124
|
let(:size) { described_class::MAX_SIZE + 1 }
|
1106
1125
|
|
1107
1126
|
it 'sets empty value' do
|
1108
|
-
form.inputs['input_1'].
|
1109
|
-
form.inputs['input_2'].
|
1127
|
+
expect(form.inputs['input_1']).to be_empty
|
1128
|
+
expect(form.inputs['input_2']).to eq('val_2')
|
1110
1129
|
end
|
1111
1130
|
end
|
1112
1131
|
|
@@ -1114,8 +1133,8 @@ EOHTML
|
|
1114
1133
|
let(:size) { described_class::MAX_SIZE - 1 }
|
1115
1134
|
|
1116
1135
|
it 'leaves the values alone' do
|
1117
|
-
form.inputs['input_1'].
|
1118
|
-
form.inputs['input_2'].
|
1136
|
+
expect(form.inputs['input_1']).to eq(value)
|
1137
|
+
expect(form.inputs['input_2']).to eq('val_2')
|
1119
1138
|
end
|
1120
1139
|
end
|
1121
1140
|
end
|
@@ -1124,25 +1143,29 @@ EOHTML
|
|
1124
1143
|
|
1125
1144
|
describe '.encode' do
|
1126
1145
|
it 'form-encodes the passed string' do
|
1127
|
-
described_class.encode( '% value\ +=&;' ).
|
1146
|
+
expect(described_class.encode( '% value\ +=&;' )).to eq('%25%20value%5C%20%2B%3D%26%3B')
|
1128
1147
|
end
|
1129
1148
|
end
|
1130
1149
|
describe '#encode' do
|
1131
1150
|
it 'form-encodes the passed string' do
|
1132
1151
|
v = '% value\ +=&;'
|
1133
|
-
subject.encode( v ).
|
1152
|
+
expect(subject.encode( v )).to eq(described_class.encode( v ))
|
1134
1153
|
end
|
1135
1154
|
end
|
1136
1155
|
|
1137
1156
|
describe '.decode' do
|
1138
1157
|
it 'form-decodes the passed string' do
|
1139
|
-
described_class.decode( '%25%20value%5C%20%2B%3D%26%3B' ).
|
1158
|
+
expect(described_class.decode( '%25%20value%5C%20%2B%3D%26%3B' )).to eq('% value\ +=&;')
|
1159
|
+
end
|
1160
|
+
|
1161
|
+
it 'handles broken encodings' do
|
1162
|
+
expect(described_class.decode( '%g' )).to eq('%g')
|
1140
1163
|
end
|
1141
1164
|
end
|
1142
1165
|
describe '#decode' do
|
1143
1166
|
it 'form-decodes the passed string' do
|
1144
1167
|
v = '%25%20value%5C%20%2B%3D%26%3B'
|
1145
|
-
subject.decode( v ).
|
1168
|
+
expect(subject.decode( v )).to eq(described_class.decode( v ))
|
1146
1169
|
end
|
1147
1170
|
end
|
1148
1171
|
|