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
@@ -5,9 +5,9 @@ describe Typhoeus::Hydra do
|
|
5
5
|
describe '#max_concurrency' do
|
6
6
|
it 'is be accessible' do
|
7
7
|
h = Typhoeus::Hydra.new
|
8
|
-
h.max_concurrency.
|
8
|
+
expect(h.max_concurrency).to be_truthy
|
9
9
|
h.max_concurrency = 10
|
10
|
-
h.max_concurrency.
|
10
|
+
expect(h.max_concurrency).to eq(10)
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
@@ -15,21 +15,21 @@ describe Arachni::URI::Scope do
|
|
15
15
|
context "less than #{Arachni::OptionGroups::Scope}#directory_depth_limit" do
|
16
16
|
it 'returns false' do
|
17
17
|
scope.directory_depth_limit = 100
|
18
|
-
subject.too_deep
|
18
|
+
expect(subject.too_deep?).to be_falsey
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
22
|
context "less than #{Arachni::OptionGroups::Scope}#directory_depth_limit" do
|
23
23
|
it 'returns true' do
|
24
24
|
scope.directory_depth_limit = 2
|
25
|
-
subject.too_deep
|
25
|
+
expect(subject.too_deep?).to be_truthy
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
30
|
context "when #{Arachni::OptionGroups::Scope}#directory_depth_limit has not been configured" do
|
31
31
|
it 'returns false' do
|
32
|
-
subject.too_deep
|
32
|
+
expect(subject.too_deep?).to be_falsey
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
@@ -43,10 +43,10 @@ describe Arachni::URI::Scope do
|
|
43
43
|
scope.redundant_path_patterns = { /match_this/ => 10 }
|
44
44
|
|
45
45
|
10.times do
|
46
|
-
subject.redundant?( true ).
|
46
|
+
expect(subject.redundant?( true )).to be_falsey
|
47
47
|
end
|
48
48
|
|
49
|
-
scope.redundant_path_patterns[/match_this/].
|
49
|
+
expect(scope.redundant_path_patterns[/match_this/]).to eq(0)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
@@ -55,10 +55,10 @@ describe Arachni::URI::Scope do
|
|
55
55
|
scope.redundant_path_patterns = { /match_this/ => 10 }
|
56
56
|
|
57
57
|
10.times do
|
58
|
-
subject.redundant
|
58
|
+
expect(subject.redundant?).to be_falsey
|
59
59
|
end
|
60
60
|
|
61
|
-
scope.redundant_path_patterns[/match_this/].
|
61
|
+
expect(scope.redundant_path_patterns[/match_this/]).to eq(10)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
@@ -67,10 +67,10 @@ describe Arachni::URI::Scope do
|
|
67
67
|
scope.redundant_path_patterns = { /match_this/ => 10 }
|
68
68
|
|
69
69
|
10.times do
|
70
|
-
subject.redundant
|
70
|
+
expect(subject.redundant?).to be_falsey
|
71
71
|
end
|
72
72
|
|
73
|
-
scope.redundant_path_patterns[/match_this/].
|
73
|
+
expect(scope.redundant_path_patterns[/match_this/]).to eq(10)
|
74
74
|
end
|
75
75
|
end
|
76
76
|
end
|
@@ -80,10 +80,10 @@ describe Arachni::URI::Scope do
|
|
80
80
|
scope.redundant_path_patterns = { /match_this/ => 10 }
|
81
81
|
|
82
82
|
10.times do
|
83
|
-
subject.redundant?( true ).
|
83
|
+
expect(subject.redundant?( true )).to be_falsey
|
84
84
|
end
|
85
85
|
|
86
|
-
subject.redundant?( true ).
|
86
|
+
expect(subject.redundant?( true )).to be_truthy
|
87
87
|
end
|
88
88
|
end
|
89
89
|
context "when a URL's counter has not reached 0" do
|
@@ -91,17 +91,17 @@ describe Arachni::URI::Scope do
|
|
91
91
|
scope.redundant_path_patterns = { /match_this/ => 11 }
|
92
92
|
|
93
93
|
10.times do
|
94
|
-
subject.redundant?( true ).
|
94
|
+
expect(subject.redundant?( true )).to be_falsey
|
95
95
|
end
|
96
96
|
|
97
|
-
subject.redundant?( true ).
|
97
|
+
expect(subject.redundant?( true )).to be_falsey
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
101
|
context 'when #auto_redundant returns true' do
|
102
102
|
it 'returns true' do
|
103
|
-
subject.
|
104
|
-
subject.
|
103
|
+
allow(subject).to receive(:auto_redundant?) { true }
|
104
|
+
expect(subject).to be_redundant
|
105
105
|
end
|
106
106
|
end
|
107
107
|
end
|
@@ -114,12 +114,12 @@ describe Arachni::URI::Scope do
|
|
114
114
|
it 'decrements the counters' do
|
115
115
|
scope.auto_redundant_paths = 10
|
116
116
|
|
117
|
-
subject.auto_redundant?( true ).
|
117
|
+
expect(subject.auto_redundant?( true )).to be_falsey
|
118
118
|
9.times do
|
119
|
-
subject.auto_redundant?( true ).
|
119
|
+
expect(subject.auto_redundant?( true )).to be_falsey
|
120
120
|
end
|
121
121
|
|
122
|
-
subject.auto_redundant
|
122
|
+
expect(subject.auto_redundant?).to be_truthy
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
@@ -127,12 +127,12 @@ describe Arachni::URI::Scope do
|
|
127
127
|
it 'does not decrement the counters' do
|
128
128
|
scope.auto_redundant_paths = 10
|
129
129
|
|
130
|
-
subject.auto_redundant?( false ).
|
130
|
+
expect(subject.auto_redundant?( false )).to be_falsey
|
131
131
|
9.times do
|
132
|
-
subject.auto_redundant?( false ).
|
132
|
+
expect(subject.auto_redundant?( false )).to be_falsey
|
133
133
|
end
|
134
134
|
|
135
|
-
subject.auto_redundant?( false ).
|
135
|
+
expect(subject.auto_redundant?( false )).not_to be_truthy
|
136
136
|
end
|
137
137
|
end
|
138
138
|
|
@@ -140,12 +140,12 @@ describe Arachni::URI::Scope do
|
|
140
140
|
it 'does not decrement the counters' do
|
141
141
|
scope.auto_redundant_paths = 10
|
142
142
|
|
143
|
-
subject.auto_redundant
|
143
|
+
expect(subject.auto_redundant?).to be_falsey
|
144
144
|
9.times do
|
145
|
-
subject.auto_redundant
|
145
|
+
expect(subject.auto_redundant?).to be_falsey
|
146
146
|
end
|
147
147
|
|
148
|
-
subject.auto_redundant
|
148
|
+
expect(subject.auto_redundant?).not_to be_truthy
|
149
149
|
end
|
150
150
|
end
|
151
151
|
end
|
@@ -154,18 +154,18 @@ describe Arachni::URI::Scope do
|
|
154
154
|
it 'returns true' do
|
155
155
|
scope.auto_redundant_paths = 10
|
156
156
|
|
157
|
-
subject.auto_redundant?( true ).
|
157
|
+
expect(subject.auto_redundant?( true )).to be_falsey
|
158
158
|
9.times do
|
159
|
-
subject.auto_redundant?( true ).
|
159
|
+
expect(subject.auto_redundant?( true )).to be_falsey
|
160
160
|
end
|
161
161
|
|
162
|
-
subject.auto_redundant?( true ).
|
162
|
+
expect(subject.auto_redundant?( true )).to be_truthy
|
163
163
|
end
|
164
164
|
end
|
165
165
|
|
166
166
|
describe 'by default' do
|
167
167
|
it 'returns false' do
|
168
|
-
subject.auto_redundant
|
168
|
+
expect(subject.auto_redundant?).to be_falsey
|
169
169
|
end
|
170
170
|
end
|
171
171
|
|
@@ -175,7 +175,7 @@ describe Arachni::URI::Scope do
|
|
175
175
|
it 'returns false' do
|
176
176
|
scope.auto_redundant_paths = 1
|
177
177
|
3.times do
|
178
|
-
subject.auto_redundant
|
178
|
+
expect(subject.auto_redundant?).to be_falsey
|
179
179
|
end
|
180
180
|
end
|
181
181
|
end
|
@@ -188,7 +188,7 @@ describe Arachni::URI::Scope do
|
|
188
188
|
it 'returns true' do
|
189
189
|
scope.exclude_path_patterns = [ /exclude/ ]
|
190
190
|
|
191
|
-
subject.exclude
|
191
|
+
expect(subject.exclude?).to be_truthy
|
192
192
|
end
|
193
193
|
end
|
194
194
|
|
@@ -196,7 +196,7 @@ describe Arachni::URI::Scope do
|
|
196
196
|
it 'returns false' do
|
197
197
|
scope.exclude_path_patterns = [ /boo/ ]
|
198
198
|
|
199
|
-
subject.exclude
|
199
|
+
expect(subject.exclude?).to be_falsey
|
200
200
|
end
|
201
201
|
end
|
202
202
|
end
|
@@ -207,14 +207,14 @@ describe Arachni::URI::Scope do
|
|
207
207
|
context 'when self matches the provided include rules in' do
|
208
208
|
it 'returns true' do
|
209
209
|
scope.include_path_patterns = [ /include/ ]
|
210
|
-
subject.include
|
210
|
+
expect(subject.include?).to be_truthy
|
211
211
|
end
|
212
212
|
end
|
213
213
|
|
214
214
|
context 'when self does not match the provided scope_include_path_patterns rules in' do
|
215
215
|
it 'returns false' do
|
216
216
|
scope.include_path_patterns = [ /boo/ ]
|
217
|
-
subject.include
|
217
|
+
expect(subject.include?).to be_falsey
|
218
218
|
end
|
219
219
|
end
|
220
220
|
end
|
@@ -244,19 +244,19 @@ describe Arachni::URI::Scope do
|
|
244
244
|
|
245
245
|
context 'and the url has a different subdomain' do
|
246
246
|
it 'return true' do
|
247
|
-
with_different_subdomain.in_domain
|
247
|
+
expect(with_different_subdomain.in_domain?).to be_truthy
|
248
248
|
end
|
249
249
|
end
|
250
250
|
|
251
251
|
context 'and the url has the same subdomain' do
|
252
252
|
it 'return true' do
|
253
|
-
with_same_subdomain.in_domain
|
253
|
+
expect(with_same_subdomain.in_domain?).to be_truthy
|
254
254
|
end
|
255
255
|
end
|
256
256
|
|
257
257
|
context 'and the url has no subdomain' do
|
258
258
|
it 'return true' do
|
259
|
-
without_subdomain.in_domain
|
259
|
+
expect(without_subdomain.in_domain?).to be_truthy
|
260
260
|
end
|
261
261
|
end
|
262
262
|
end
|
@@ -268,13 +268,13 @@ describe Arachni::URI::Scope do
|
|
268
268
|
|
269
269
|
context 'and the url has a subdomain' do
|
270
270
|
it 'return true' do
|
271
|
-
with_subdomain.in_domain
|
271
|
+
expect(with_subdomain.in_domain?).to be_truthy
|
272
272
|
end
|
273
273
|
end
|
274
274
|
|
275
275
|
context 'and the url has no subdomain' do
|
276
276
|
it 'return true' do
|
277
|
-
without_subdomain.in_domain
|
277
|
+
expect(without_subdomain.in_domain?).to be_truthy
|
278
278
|
end
|
279
279
|
end
|
280
280
|
end
|
@@ -294,19 +294,19 @@ describe Arachni::URI::Scope do
|
|
294
294
|
|
295
295
|
context 'and the url has a different subdomain' do
|
296
296
|
it 'return false' do
|
297
|
-
with_different_subdomain.in_domain
|
297
|
+
expect(with_different_subdomain.in_domain?).to be_falsey
|
298
298
|
end
|
299
299
|
end
|
300
300
|
|
301
301
|
context 'and the url has the same subdomain' do
|
302
302
|
it 'return true' do
|
303
|
-
with_same_subdomain.in_domain
|
303
|
+
expect(with_same_subdomain.in_domain?).to be_truthy
|
304
304
|
end
|
305
305
|
end
|
306
306
|
|
307
307
|
context 'and the url has no subdomain' do
|
308
308
|
it 'return false' do
|
309
|
-
without_subdomain.in_domain
|
309
|
+
expect(without_subdomain.in_domain?).to be_falsey
|
310
310
|
end
|
311
311
|
end
|
312
312
|
end
|
@@ -318,13 +318,13 @@ describe Arachni::URI::Scope do
|
|
318
318
|
|
319
319
|
context 'and the url has a subdomain' do
|
320
320
|
it 'return false' do
|
321
|
-
with_subdomain.in_domain
|
321
|
+
expect(with_subdomain.in_domain?).to be_falsey
|
322
322
|
end
|
323
323
|
end
|
324
324
|
|
325
325
|
context 'and the url has no subdomain' do
|
326
326
|
it 'return true' do
|
327
|
-
without_subdomain.in_domain
|
327
|
+
expect(without_subdomain.in_domain?).to be_truthy
|
328
328
|
end
|
329
329
|
end
|
330
330
|
end
|
@@ -350,14 +350,14 @@ describe Arachni::URI::Scope do
|
|
350
350
|
context true do
|
351
351
|
it 'returns true' do
|
352
352
|
scope.https_only = true
|
353
|
-
https.follow_protocol
|
353
|
+
expect(https.follow_protocol?).to be_truthy
|
354
354
|
end
|
355
355
|
end
|
356
356
|
|
357
357
|
context false do
|
358
358
|
it 'returns true' do
|
359
359
|
scope.https_only = false
|
360
|
-
https.follow_protocol
|
360
|
+
expect(https.follow_protocol?).to be_truthy
|
361
361
|
end
|
362
362
|
end
|
363
363
|
end
|
@@ -368,14 +368,14 @@ describe Arachni::URI::Scope do
|
|
368
368
|
context true do
|
369
369
|
it 'returns false' do
|
370
370
|
scope.https_only = true
|
371
|
-
http.follow_protocol
|
371
|
+
expect(http.follow_protocol?).to be_falsey
|
372
372
|
end
|
373
373
|
end
|
374
374
|
|
375
375
|
context false do
|
376
376
|
it 'returns true' do
|
377
377
|
scope.https_only = false
|
378
|
-
http.follow_protocol
|
378
|
+
expect(http.follow_protocol?).to be_truthy
|
379
379
|
end
|
380
380
|
end
|
381
381
|
end
|
@@ -394,14 +394,14 @@ describe Arachni::URI::Scope do
|
|
394
394
|
context true do
|
395
395
|
it 'returns true' do
|
396
396
|
scope.https_only = true
|
397
|
-
https.follow_protocol
|
397
|
+
expect(https.follow_protocol?).to be_truthy
|
398
398
|
end
|
399
399
|
end
|
400
400
|
|
401
401
|
context false do
|
402
402
|
it 'returns true' do
|
403
403
|
scope.https_only = false
|
404
|
-
https.follow_protocol
|
404
|
+
expect(https.follow_protocol?).to be_truthy
|
405
405
|
end
|
406
406
|
end
|
407
407
|
end
|
@@ -411,14 +411,14 @@ describe Arachni::URI::Scope do
|
|
411
411
|
context true do
|
412
412
|
it 'returns true' do
|
413
413
|
scope.https_only = true
|
414
|
-
http.follow_protocol
|
414
|
+
expect(http.follow_protocol?).to be_truthy
|
415
415
|
end
|
416
416
|
end
|
417
417
|
|
418
418
|
context false do
|
419
419
|
it 'returns true' do
|
420
420
|
scope.https_only = false
|
421
|
-
http.follow_protocol
|
421
|
+
expect(http.follow_protocol?).to be_truthy
|
422
422
|
end
|
423
423
|
end
|
424
424
|
end
|
@@ -432,14 +432,14 @@ describe Arachni::URI::Scope do
|
|
432
432
|
subject { Arachni::URI.parse( 'http://stuff/' ).scope }
|
433
433
|
|
434
434
|
it 'returns true' do
|
435
|
-
subject.
|
435
|
+
expect(subject).to be_in
|
436
436
|
end
|
437
437
|
|
438
438
|
context 'when #out?' do
|
439
439
|
context 'is true' do
|
440
440
|
it 'returns false' do
|
441
|
-
subject.
|
442
|
-
subject.
|
441
|
+
allow(subject).to receive(:out?) { true }
|
442
|
+
expect(subject).not_to be_in
|
443
443
|
end
|
444
444
|
end
|
445
445
|
end
|
@@ -449,19 +449,19 @@ describe Arachni::URI::Scope do
|
|
449
449
|
subject { Arachni::URI.parse( 'http://stuff/' ).scope }
|
450
450
|
|
451
451
|
it 'returns false' do
|
452
|
-
subject.
|
452
|
+
expect(subject).not_to be_out
|
453
453
|
end
|
454
454
|
|
455
455
|
it 'does not call #redundant?' do
|
456
|
-
subject.
|
456
|
+
expect(subject).not_to receive(:redundant?)
|
457
457
|
subject.out?
|
458
458
|
end
|
459
459
|
|
460
460
|
context 'when #follow_protocol?' do
|
461
461
|
context 'is false' do
|
462
462
|
it 'returns true' do
|
463
|
-
subject.
|
464
|
-
subject.
|
463
|
+
allow(subject).to receive(:follow_protocol?) { false }
|
464
|
+
expect(subject).to be_out
|
465
465
|
end
|
466
466
|
end
|
467
467
|
end
|
@@ -469,8 +469,8 @@ describe Arachni::URI::Scope do
|
|
469
469
|
context 'when #in_domain?' do
|
470
470
|
context 'is false' do
|
471
471
|
it 'returns true' do
|
472
|
-
subject.
|
473
|
-
subject.
|
472
|
+
allow(subject).to receive(:in_domain?) { false }
|
473
|
+
expect(subject).to be_out
|
474
474
|
end
|
475
475
|
end
|
476
476
|
end
|
@@ -478,8 +478,8 @@ describe Arachni::URI::Scope do
|
|
478
478
|
context 'when #too_deep?' do
|
479
479
|
context 'is true' do
|
480
480
|
it 'returns true' do
|
481
|
-
subject.
|
482
|
-
subject.
|
481
|
+
allow(subject).to receive(:too_deep?) { true }
|
482
|
+
expect(subject).to be_out
|
483
483
|
end
|
484
484
|
end
|
485
485
|
end
|
@@ -487,8 +487,8 @@ describe Arachni::URI::Scope do
|
|
487
487
|
context 'when #include?' do
|
488
488
|
context 'is false' do
|
489
489
|
it 'returns true' do
|
490
|
-
subject.
|
491
|
-
subject.
|
490
|
+
allow(subject).to receive(:include?) { false }
|
491
|
+
expect(subject).to be_out
|
492
492
|
end
|
493
493
|
end
|
494
494
|
end
|
@@ -496,8 +496,8 @@ describe Arachni::URI::Scope do
|
|
496
496
|
context 'when #exclude?' do
|
497
497
|
context 'is true' do
|
498
498
|
it 'returns true' do
|
499
|
-
subject.
|
500
|
-
subject.
|
499
|
+
allow(subject).to receive(:exclude?) { true }
|
500
|
+
expect(subject).to be_out
|
501
501
|
end
|
502
502
|
end
|
503
503
|
end
|
data/spec/arachni/uri_spec.rb
CHANGED
@@ -102,8 +102,8 @@ describe Arachni::URI do
|
|
102
102
|
it 'parses and normalize the give string' do
|
103
103
|
@urls.each do |url|
|
104
104
|
uri = Arachni::URI( url )
|
105
|
-
uri.is_a?( Arachni::URI ).
|
106
|
-
uri.to_s.
|
105
|
+
expect(uri.is_a?( Arachni::URI )).to be_truthy
|
106
|
+
expect(uri.to_s).to eq(@ref_normalizer.call( url ))
|
107
107
|
end
|
108
108
|
end
|
109
109
|
end
|
@@ -112,16 +112,18 @@ describe Arachni::URI do
|
|
112
112
|
let(:url) { 'http://test.com/articles/some-stuff/23' }
|
113
113
|
|
114
114
|
it 'rewrites a URL based on the given rules' do
|
115
|
-
described_class.rewrite( url, rewrite_rules ).
|
115
|
+
expect(described_class.rewrite( url, rewrite_rules )).to eq(
|
116
116
|
'http://test.com/articles.php?id=23'
|
117
|
+
)
|
117
118
|
end
|
118
119
|
|
119
120
|
context 'when no rules are provided' do
|
120
121
|
it "uses the ones in #{Arachni::OptionGroups::Scope}#url_rewrites" do
|
121
122
|
Arachni::Options.scope.url_rewrites = rewrite_rules
|
122
123
|
|
123
|
-
described_class.rewrite( url ).
|
124
|
+
expect(described_class.rewrite( url )).to eq(
|
124
125
|
'http://test.com/articles.php?id=23'
|
126
|
+
)
|
125
127
|
end
|
126
128
|
end
|
127
129
|
end
|
@@ -129,29 +131,29 @@ describe Arachni::URI do
|
|
129
131
|
describe '.parse_query' do
|
130
132
|
it 'returns the query parameters as a Hash' do
|
131
133
|
url = 'http://test/?param_one=value_one¶m_two=value_two'
|
132
|
-
described_class.parse_query( url ).
|
134
|
+
expect(described_class.parse_query( url )).to eq({
|
133
135
|
'param_one' => 'value_one',
|
134
136
|
'param_two' => 'value_two'
|
135
|
-
}
|
137
|
+
})
|
136
138
|
end
|
137
139
|
|
138
140
|
it 'decodes the parameters' do
|
139
141
|
url = 'http://test/?stuff%20here=bl%20ah'
|
140
|
-
described_class.parse_query( url ).
|
142
|
+
expect(described_class.parse_query( url )).to eq({
|
141
143
|
'stuff here' => 'bl ah'
|
142
|
-
}
|
144
|
+
})
|
143
145
|
end
|
144
146
|
|
145
147
|
context 'when passed' do
|
146
148
|
describe 'nil' do
|
147
149
|
it 'returns an empty Hash' do
|
148
|
-
described_class.parse_query( nil ).
|
150
|
+
expect(described_class.parse_query( nil )).to eq({})
|
149
151
|
end
|
150
152
|
end
|
151
153
|
describe 'an unparsable URL' do
|
152
154
|
it 'returns an empty Hash' do
|
153
155
|
url = '$#%^$6#5436#$%^'
|
154
|
-
described_class.parse_query( url ).
|
156
|
+
expect(described_class.parse_query( url )).to eq({})
|
155
157
|
end
|
156
158
|
end
|
157
159
|
end
|
@@ -160,20 +162,20 @@ describe Arachni::URI do
|
|
160
162
|
describe '.encode' do
|
161
163
|
it 'decodes a URI' do
|
162
164
|
uri = "my test.asp?name=ståle&car=saab"
|
163
|
-
described_class.encode( uri ).
|
165
|
+
expect(described_class.encode( uri )).to eq('my%20test.asp?name=st%C3%A5le&car=saab')
|
164
166
|
end
|
165
167
|
end
|
166
168
|
|
167
169
|
describe '.decode' do
|
168
170
|
it 'decodes a URI' do
|
169
171
|
uri = 'my%20test.asp?name=st%C3%A5le&car=saab'
|
170
|
-
described_class.decode( uri ).
|
172
|
+
expect(described_class.decode( uri )).to eq("my test.asp?name=ståle&car=saab")
|
171
173
|
end
|
172
174
|
end
|
173
175
|
|
174
176
|
describe '.parser' do
|
175
177
|
it 'returns a URI::Parser' do
|
176
|
-
described_class.parser.class.
|
178
|
+
expect(described_class.parser.class).to eq(::URI::Parser)
|
177
179
|
end
|
178
180
|
end
|
179
181
|
|
@@ -190,40 +192,40 @@ describe Arachni::URI do
|
|
190
192
|
|
191
193
|
parsed_uri = described_class.parse( uri )
|
192
194
|
|
193
|
-
parsed_uri.to_s.
|
195
|
+
expect(parsed_uri.to_s).to eq(uri)
|
194
196
|
|
195
|
-
parsed_uri.scheme.
|
196
|
-
parsed_uri.user.
|
197
|
-
parsed_uri.password.
|
198
|
-
parsed_uri.host.
|
199
|
-
parsed_uri.path.
|
200
|
-
parsed_uri.query.
|
197
|
+
expect(parsed_uri.scheme).to eq(scheme)
|
198
|
+
expect(parsed_uri.user).to eq(user)
|
199
|
+
expect(parsed_uri.password).to eq(password)
|
200
|
+
expect(parsed_uri.host).to eq(host)
|
201
|
+
expect(parsed_uri.path).to eq(path)
|
202
|
+
expect(parsed_uri.query).to eq(query)
|
201
203
|
end
|
202
204
|
|
203
205
|
it 'ignores javascript: URLs' do
|
204
|
-
described_class.parse( 'javascript:stuff()' ).
|
205
|
-
described_class.parse( 'jAvaScRipT:stuff()' ).
|
206
|
+
expect(described_class.parse( 'javascript:stuff()' )).to be_nil
|
207
|
+
expect(described_class.parse( 'jAvaScRipT:stuff()' )).to be_nil
|
206
208
|
end
|
207
209
|
end
|
208
210
|
|
209
211
|
describe '.ruby_parse' do
|
210
212
|
it 'cleans the URL' do
|
211
213
|
@urls.each do |url|
|
212
|
-
described_class.ruby_parse( url ).to_s.
|
214
|
+
expect(described_class.ruby_parse( url ).to_s).to eq(@ref_normalizer.call( url ))
|
213
215
|
end
|
214
216
|
end
|
215
217
|
|
216
218
|
it 'ignores javascript: URLs' do
|
217
|
-
described_class.ruby_parse( 'javascript:stuff()' ).
|
218
|
-
described_class.ruby_parse( 'jAvaScRipT:stuff()' ).
|
219
|
+
expect(described_class.ruby_parse( 'javascript:stuff()' )).to be_nil
|
220
|
+
expect(described_class.ruby_parse( 'jAvaScRipT:stuff()' )).to be_nil
|
219
221
|
end
|
220
222
|
|
221
223
|
context 'when an error occurs' do
|
222
224
|
it 'returns nil' do
|
223
|
-
described_class.
|
224
|
-
described_class.
|
225
|
+
allow(described_class).to receive(:fast_parse){ raise }
|
226
|
+
allow(described_class).to receive(:normalize){ raise }
|
225
227
|
|
226
|
-
described_class.ruby_parse( 'http://test.com/222' ).
|
228
|
+
expect(described_class.ruby_parse( 'http://test.com/222' )).to be_nil
|
227
229
|
end
|
228
230
|
end
|
229
231
|
end
|
@@ -241,19 +243,19 @@ describe Arachni::URI do
|
|
241
243
|
|
242
244
|
parsed_uri = described_class.fast_parse( uri )
|
243
245
|
|
244
|
-
parsed_uri[:scheme].
|
245
|
-
parsed_uri[:userinfo].
|
246
|
-
parsed_uri[:host].
|
247
|
-
parsed_uri[:path].
|
248
|
-
parsed_uri[:query].
|
246
|
+
expect(parsed_uri[:scheme]).to eq(scheme)
|
247
|
+
expect(parsed_uri[:userinfo]).to eq(user + ':' + password)
|
248
|
+
expect(parsed_uri[:host]).to eq(host)
|
249
|
+
expect(parsed_uri[:path]).to eq(path)
|
250
|
+
expect(parsed_uri[:query]).to eq(query)
|
249
251
|
|
250
252
|
parsed_uri = described_class.fast_parse( "//#{user}:#{password}@#{host}/#{path}?#{query}" )
|
251
253
|
|
252
|
-
parsed_uri[:scheme].
|
253
|
-
parsed_uri[:userinfo].
|
254
|
-
parsed_uri[:host].
|
255
|
-
parsed_uri[:path].
|
256
|
-
parsed_uri[:query].
|
254
|
+
expect(parsed_uri[:scheme]).to be_nil
|
255
|
+
expect(parsed_uri[:userinfo]).to eq(user + ':' + password)
|
256
|
+
expect(parsed_uri[:host]).to eq(host)
|
257
|
+
expect(parsed_uri[:path]).to eq(path)
|
258
|
+
expect(parsed_uri[:query]).to eq(query)
|
257
259
|
end
|
258
260
|
|
259
261
|
it 'returns a frozen hash (with frozen values)' do
|
@@ -264,7 +266,7 @@ describe Arachni::URI do
|
|
264
266
|
end
|
265
267
|
|
266
268
|
it 'ignores javascript: URLs' do
|
267
|
-
described_class.fast_parse( 'javascript:stuff()' ).
|
269
|
+
expect(described_class.fast_parse( 'javascript:stuff()' )).to be_nil
|
268
270
|
end
|
269
271
|
end
|
270
272
|
|
@@ -273,41 +275,41 @@ describe Arachni::URI do
|
|
273
275
|
abs = 'http://test.com/blah/ha'
|
274
276
|
rel = '/test'
|
275
277
|
rel2 = 'test2'
|
276
|
-
described_class.to_absolute( rel, abs ).
|
277
|
-
described_class.to_absolute( rel2, abs ).
|
278
|
-
described_class.to_absolute( rel2, abs + '/' ).
|
278
|
+
expect(described_class.to_absolute( rel, abs )).to eq("http://test.com" + rel)
|
279
|
+
expect(described_class.to_absolute( rel2, abs )).to eq("http://test.com/blah/" + rel2)
|
280
|
+
expect(described_class.to_absolute( rel2, abs + '/' )).to eq("http://test.com/blah/ha/" + rel2)
|
279
281
|
|
280
282
|
rel = '//domain-name.com/stuff'
|
281
|
-
described_class.to_absolute( rel, abs ).
|
283
|
+
expect(described_class.to_absolute( rel, abs )).to eq("http:" + rel)
|
282
284
|
end
|
283
285
|
end
|
284
286
|
|
285
287
|
describe '.normalize' do
|
286
288
|
it 'cleans the URL' do
|
287
289
|
@urls.each do |url|
|
288
|
-
described_class.normalize( url ).
|
290
|
+
expect(described_class.normalize( url )).to eq(@ref_normalizer.call( url ))
|
289
291
|
end
|
290
292
|
with_whitespace = 'http://test.com/stuff '
|
291
|
-
described_class.normalize( with_whitespace ).to_s.
|
293
|
+
expect(described_class.normalize( with_whitespace ).to_s).to eq(with_whitespace.strip)
|
292
294
|
end
|
293
295
|
end
|
294
296
|
|
295
297
|
describe '.full_and_absolute?' do
|
296
298
|
context 'when given a nil URL' do
|
297
299
|
it 'returns false' do
|
298
|
-
described_class.full_and_absolute?( nil ).
|
300
|
+
expect(described_class.full_and_absolute?( nil )).to be_falsey
|
299
301
|
end
|
300
302
|
end
|
301
303
|
|
302
304
|
context 'when given an non absolute URL' do
|
303
305
|
it 'returns false' do
|
304
|
-
described_class.full_and_absolute?( '433' ).
|
306
|
+
expect(described_class.full_and_absolute?( '433' )).to be_falsey
|
305
307
|
end
|
306
308
|
end
|
307
309
|
|
308
310
|
context 'when given an absolute URL' do
|
309
311
|
it 'returns true' do
|
310
|
-
described_class.full_and_absolute?( 'http://stuff/' ).
|
312
|
+
expect(described_class.full_and_absolute?( 'http://stuff/' )).to be_truthy
|
311
313
|
end
|
312
314
|
end
|
313
315
|
end
|
@@ -317,8 +319,8 @@ describe Arachni::URI do
|
|
317
319
|
it 'normalizes and parse the string' do
|
318
320
|
@urls.each do |url|
|
319
321
|
uri = described_class.new( url )
|
320
|
-
uri.is_a?( Arachni::URI ).
|
321
|
-
uri.to_s.
|
322
|
+
expect(uri.is_a?( Arachni::URI )).to be_truthy
|
323
|
+
expect(uri.to_s).to eq(@ref_normalizer.call( url ))
|
322
324
|
end
|
323
325
|
end
|
324
326
|
end
|
@@ -327,8 +329,8 @@ describe Arachni::URI do
|
|
327
329
|
it 'normalizes and construct a URI from a Hash of components' do
|
328
330
|
@urls.each do |url|
|
329
331
|
uri = described_class.new( described_class.fast_parse( url ) )
|
330
|
-
uri.is_a?( Arachni::URI ).
|
331
|
-
uri.to_s.
|
332
|
+
expect(uri.is_a?( Arachni::URI )).to be_truthy
|
333
|
+
expect(uri.to_s).to eq(@ref_normalizer.call( url ))
|
332
334
|
end
|
333
335
|
end
|
334
336
|
end
|
@@ -337,11 +339,11 @@ describe Arachni::URI do
|
|
337
339
|
it 'normalizes and construct a URI from a Hash of components' do
|
338
340
|
@urls.each do |url|
|
339
341
|
uri = ::URI.parse( described_class.normalize( url ) )
|
340
|
-
uri.is_a?( ::URI ).
|
342
|
+
expect(uri.is_a?( ::URI )).to be_truthy
|
341
343
|
|
342
344
|
a_uri = described_class.new( url )
|
343
|
-
a_uri.is_a?( Arachni::URI ).
|
344
|
-
a_uri.to_s.
|
345
|
+
expect(a_uri.is_a?( Arachni::URI )).to be_truthy
|
346
|
+
expect(a_uri.to_s).to eq(@ref_normalizer.call( url ))
|
345
347
|
end
|
346
348
|
end
|
347
349
|
end
|
@@ -351,8 +353,8 @@ describe Arachni::URI do
|
|
351
353
|
@urls.each do |url|
|
352
354
|
uri = described_class.new( url )
|
353
355
|
a_uri = described_class.new( uri )
|
354
|
-
a_uri.is_a?( Arachni::URI ).
|
355
|
-
a_uri.
|
356
|
+
expect(a_uri.is_a?( Arachni::URI )).to be_truthy
|
357
|
+
expect(a_uri).to eq(uri)
|
356
358
|
end
|
357
359
|
end
|
358
360
|
end
|
@@ -369,14 +371,14 @@ describe Arachni::URI do
|
|
369
371
|
@urls.each do |url|
|
370
372
|
normalized_str = described_class.normalize( url )
|
371
373
|
uri = ::URI.parse( normalized_str )
|
372
|
-
uri.is_a?( ::URI ).
|
374
|
+
expect(uri.is_a?( ::URI )).to be_truthy
|
373
375
|
|
374
376
|
a_uri = described_class.new( url )
|
375
|
-
a_uri.is_a?( Arachni::URI ).
|
377
|
+
expect(a_uri.is_a?( Arachni::URI )).to be_truthy
|
376
378
|
|
377
|
-
a_uri.
|
378
|
-
a_uri.
|
379
|
-
a_uri.
|
379
|
+
expect(a_uri).to eq(uri)
|
380
|
+
expect(a_uri).to eq(normalized_str)
|
381
|
+
expect(a_uri).to eq(a_uri)
|
380
382
|
end
|
381
383
|
end
|
382
384
|
end
|
@@ -386,20 +388,20 @@ describe Arachni::URI do
|
|
386
388
|
|
387
389
|
it 'sets the URL query' do
|
388
390
|
subject.query = 'my2=val2'
|
389
|
-
subject.query.
|
391
|
+
expect(subject.query).to eq('my2=val2')
|
390
392
|
end
|
391
393
|
|
392
394
|
context 'when given an empty string' do
|
393
395
|
it 'removes the query' do
|
394
396
|
subject.query = ''
|
395
|
-
subject.query.
|
397
|
+
expect(subject.query).to be_nil
|
396
398
|
end
|
397
399
|
end
|
398
400
|
|
399
401
|
context 'when given nil' do
|
400
402
|
it 'removes the query' do
|
401
403
|
subject.query = ''
|
402
|
-
subject.query.
|
404
|
+
expect(subject.query).to be_nil
|
403
405
|
end
|
404
406
|
end
|
405
407
|
end
|
@@ -410,15 +412,15 @@ describe Arachni::URI do
|
|
410
412
|
it 'return a duplicate object' do
|
411
413
|
dupped = subject.dup
|
412
414
|
|
413
|
-
subject.
|
414
|
-
subject.object_id.
|
415
|
+
expect(subject).to eq(dupped)
|
416
|
+
expect(subject.object_id).not_to eq(dupped.object_id)
|
415
417
|
end
|
416
418
|
end
|
417
419
|
|
418
420
|
describe '#_dump' do
|
419
421
|
it 'returns the URL as a string' do
|
420
422
|
uri = 'http://test.com/?my=val'
|
421
|
-
described_class.new( uri )._dump(nil).
|
423
|
+
expect(described_class.new( uri )._dump(nil)).to eq(uri)
|
422
424
|
end
|
423
425
|
end
|
424
426
|
|
@@ -427,7 +429,7 @@ describe Arachni::URI do
|
|
427
429
|
uri = 'http://test.com/?my=val'
|
428
430
|
parsed = described_class.new( uri )
|
429
431
|
|
430
|
-
described_class._load( parsed._dump(nil) ).
|
432
|
+
expect(described_class._load( parsed._dump(nil) )).to eq(parsed)
|
431
433
|
end
|
432
434
|
end
|
433
435
|
|
@@ -436,50 +438,50 @@ describe Arachni::URI do
|
|
436
438
|
abs = 'http://test.com/blah/ha'
|
437
439
|
rel = '/test'
|
438
440
|
rel2 = 'test2'
|
439
|
-
described_class.parse( rel ).to_absolute( abs ).
|
440
|
-
described_class.parse( rel2 ).to_absolute( abs ).
|
441
|
-
described_class.parse( rel2 ).to_absolute( abs + '/' ).
|
441
|
+
expect(described_class.parse( rel ).to_absolute( abs )).to eq("http://test.com" + rel)
|
442
|
+
expect(described_class.parse( rel2 ).to_absolute( abs )).to eq("http://test.com/blah/" + rel2)
|
443
|
+
expect(described_class.parse( rel2 ).to_absolute( abs + '/' )).to eq("http://test.com/blah/ha/" + rel2)
|
442
444
|
end
|
443
445
|
end
|
444
446
|
|
445
447
|
describe '#up_to_path' do
|
446
448
|
it 'returns the URL up to its path component (no resource name, query, fragment, etc)' do
|
447
449
|
url = 'http://test.com/path/goes/here.php?query=goes&here=.!#frag'
|
448
|
-
described_class.parse( url ).up_to_path.
|
450
|
+
expect(described_class.parse( url ).up_to_path).to eq('http://test.com/path/goes/')
|
449
451
|
|
450
452
|
url = 'http://test.com/path/goes/here/?query=goes&here=.!#frag'
|
451
|
-
described_class.parse( url ).up_to_path.
|
453
|
+
expect(described_class.parse( url ).up_to_path).to eq('http://test.com/path/goes/here/')
|
452
454
|
|
453
455
|
url = 'http://test.com/path/goes/here?query=goes&here=.!#frag'
|
454
|
-
described_class.parse( url ).up_to_path.
|
456
|
+
expect(described_class.parse( url ).up_to_path).to eq('http://test.com/path/goes/here/')
|
455
457
|
|
456
458
|
url = 'http://test.com'
|
457
|
-
described_class.parse( url ).up_to_path.
|
459
|
+
expect(described_class.parse( url ).up_to_path).to eq('http://test.com/')
|
458
460
|
|
459
461
|
url = 'http://test.com/'
|
460
|
-
described_class.parse( url ).up_to_path.
|
462
|
+
expect(described_class.parse( url ).up_to_path).to eq('http://test.com/')
|
461
463
|
end
|
462
464
|
end
|
463
465
|
|
464
466
|
describe '#domain' do
|
465
467
|
it 'removes the deepest subdomain from the host' do
|
466
468
|
url = 'http://test.com/'
|
467
|
-
described_class.parse( url ).domain.
|
469
|
+
expect(described_class.parse( url ).domain).to eq('test.com')
|
468
470
|
|
469
471
|
url = 'http://test/'
|
470
|
-
described_class.parse( url ).domain.
|
472
|
+
expect(described_class.parse( url ).domain).to eq('test')
|
471
473
|
|
472
474
|
url = 'http://subdomain.test.com/'
|
473
|
-
described_class.parse( url ).domain.
|
475
|
+
expect(described_class.parse( url ).domain).to eq('test.com')
|
474
476
|
|
475
477
|
url = 'http://deep.subdomain.test.com/'
|
476
|
-
described_class.parse( url ).domain.
|
478
|
+
expect(described_class.parse( url ).domain).to eq('subdomain.test.com')
|
477
479
|
end
|
478
480
|
|
479
481
|
context 'when no host is available' do
|
480
482
|
it 'returns nil' do
|
481
483
|
url = '/stuff/'
|
482
|
-
described_class.parse( url ).domain.
|
484
|
+
expect(described_class.parse( url ).domain).to be_nil
|
483
485
|
end
|
484
486
|
end
|
485
487
|
end
|
@@ -488,13 +490,13 @@ describe Arachni::URI do
|
|
488
490
|
context 'when passed a URL with' do
|
489
491
|
context 'a domain name' do
|
490
492
|
it 'returns false' do
|
491
|
-
described_class.parse( 'http://stuff.com/blah' ).ip_address
|
493
|
+
expect(described_class.parse( 'http://stuff.com/blah' ).ip_address?).to be_falsey
|
492
494
|
end
|
493
495
|
end
|
494
496
|
|
495
497
|
context 'an IP address' do
|
496
498
|
it 'returns the IP address' do
|
497
|
-
described_class.parse( 'http://127.0.0.1/blah/' ).ip_address
|
499
|
+
expect(described_class.parse( 'http://127.0.0.1/blah/' ).ip_address?).to be_truthy
|
498
500
|
end
|
499
501
|
end
|
500
502
|
end
|
@@ -503,7 +505,7 @@ describe Arachni::URI do
|
|
503
505
|
describe '#without_query' do
|
504
506
|
it 'returns the URI up to its resource component without the query' do
|
505
507
|
expected = 'http://test.com/directory/resource.php'
|
506
|
-
described_class.new( "#{expected}?param=1¶m2=2" ).without_query.
|
508
|
+
expect(described_class.new( "#{expected}?param=1¶m2=2" ).without_query).to eq(expected)
|
507
509
|
end
|
508
510
|
end
|
509
511
|
|
@@ -512,14 +514,14 @@ describe Arachni::URI do
|
|
512
514
|
let(:rewritten) { described_class.new( 'http://test.com/articles.php?id=23' ) }
|
513
515
|
|
514
516
|
it 'rewrites a URL based on the given rules' do
|
515
|
-
url.rewrite( rewrite_rules ).
|
517
|
+
expect(url.rewrite( rewrite_rules )).to eq(rewritten)
|
516
518
|
end
|
517
519
|
|
518
520
|
context 'when no rules are provided' do
|
519
521
|
it "uses the ones in #{Arachni::OptionGroups::Scope}#url_rewrites" do
|
520
522
|
Arachni::Options.scope.url_rewrites = rewrite_rules
|
521
523
|
|
522
|
-
url.rewrite.
|
524
|
+
expect(url.rewrite).to eq(rewritten)
|
523
525
|
end
|
524
526
|
end
|
525
527
|
|
@@ -527,8 +529,8 @@ describe Arachni::URI do
|
|
527
529
|
let(:url) { described_class.new( 'http://blahblah/more.blah' ) }
|
528
530
|
|
529
531
|
it 'returns a copy of self' do
|
530
|
-
url.rewrite.
|
531
|
-
url.rewrite.object_id.
|
532
|
+
expect(url.rewrite).to eq(url)
|
533
|
+
expect(url.rewrite.object_id).not_to eq(url.object_id)
|
532
534
|
end
|
533
535
|
end
|
534
536
|
end
|
@@ -536,45 +538,45 @@ describe Arachni::URI do
|
|
536
538
|
describe '#resource_name' do
|
537
539
|
context 'when there is no file name' do
|
538
540
|
it 'returns nil' do
|
539
|
-
described_class.new( 'http://stuff.com/' ).resource_name.
|
541
|
+
expect(described_class.new( 'http://stuff.com/' ).resource_name).to be_nil
|
540
542
|
end
|
541
543
|
end
|
542
544
|
|
543
545
|
it 'returns the file name of the resource' do
|
544
546
|
uri = 'http://test.com/direct.ory/resource.php?param=1¶m2=2'
|
545
|
-
described_class.new( uri ).resource_name.
|
546
|
-
described_class.new( 'http://stuff.com/test/' ).resource_name.
|
547
|
+
expect(described_class.new( uri ).resource_name).to eq('resource.php')
|
548
|
+
expect(described_class.new( 'http://stuff.com/test/' ).resource_name).to eq('test')
|
547
549
|
end
|
548
550
|
end
|
549
551
|
|
550
552
|
describe '#resource_extension' do
|
551
553
|
context 'when there is no extension' do
|
552
554
|
it 'returns nil' do
|
553
|
-
described_class.new( 'http://stuff.com/test' ).resource_extension.
|
555
|
+
expect(described_class.new( 'http://stuff.com/test' ).resource_extension).to be_nil
|
554
556
|
end
|
555
557
|
end
|
556
558
|
|
557
559
|
context 'when there are multiple periods' do
|
558
560
|
it 'returns the last one' do
|
559
|
-
described_class.new( 'http://stuff.com/test.1.2' ).resource_extension.
|
561
|
+
expect(described_class.new( 'http://stuff.com/test.1.2' ).resource_extension).to eq('2')
|
560
562
|
end
|
561
563
|
end
|
562
564
|
|
563
565
|
it 'returns the extension of the resource' do
|
564
566
|
uri = "http://test.com/direct.ory/resource.php?param=1¶m2=2"
|
565
|
-
described_class.new( uri ).resource_extension.
|
567
|
+
expect(described_class.new( uri ).resource_extension).to eq('php')
|
566
568
|
end
|
567
569
|
end
|
568
570
|
|
569
571
|
describe '#mailto?' do
|
570
572
|
context 'when the URI has a mailto scheme' do
|
571
573
|
it 'returns true' do
|
572
|
-
described_class.new( 'mailto:stuff@blah.com' ).mailto
|
574
|
+
expect(described_class.new( 'mailto:stuff@blah.com' ).mailto?).to be_truthy
|
573
575
|
end
|
574
576
|
end
|
575
577
|
context 'when the URI does not have a mailto scheme' do
|
576
578
|
it 'returns false' do
|
577
|
-
described_class.new( 'blah.com' ).mailto
|
579
|
+
expect(described_class.new( 'blah.com' ).mailto?).to be_falsey
|
578
580
|
end
|
579
581
|
end
|
580
582
|
end
|
@@ -582,30 +584,30 @@ describe Arachni::URI do
|
|
582
584
|
describe '#hash' do
|
583
585
|
it 'returns a hash uniquely identifying the URI' do
|
584
586
|
uri = described_class.new( 'http://stuff/' )
|
585
|
-
uri.hash.
|
586
|
-
uri.hash.
|
587
|
+
expect(uri.hash).to be_kind_of Integer
|
588
|
+
expect(uri.hash).to eq(uri.hash)
|
587
589
|
|
588
590
|
uri2 = described_class.new( 'http://stuff2/' )
|
589
|
-
uri.hash.
|
591
|
+
expect(uri.hash).not_to eq(uri2.hash)
|
590
592
|
end
|
591
593
|
|
592
594
|
it 'is an integer' do
|
593
|
-
described_class.new( 'http://stuff/' ).hash.
|
595
|
+
expect(described_class.new( 'http://stuff/' ).hash).to be_kind_of Integer
|
594
596
|
end
|
595
597
|
end
|
596
598
|
|
597
599
|
describe '#persistent_hash' do
|
598
600
|
it 'returns a hash uniquely identifying the URI' do
|
599
601
|
uri = described_class.new( 'http://stuff/' )
|
600
|
-
uri.persistent_hash.
|
601
|
-
uri.persistent_hash.
|
602
|
+
expect(uri.persistent_hash).to be_kind_of Integer
|
603
|
+
expect(uri.persistent_hash).to eq(uri.persistent_hash)
|
602
604
|
|
603
605
|
uri2 = described_class.new( 'http://stuff2/' )
|
604
|
-
uri.persistent_hash.
|
606
|
+
expect(uri.persistent_hash).not_to eq(uri2.persistent_hash)
|
605
607
|
end
|
606
608
|
|
607
609
|
it 'is an integer' do
|
608
|
-
described_class.new( 'http://stuff/' ).persistent_hash.
|
610
|
+
expect(described_class.new( 'http://stuff/' ).persistent_hash).to be_kind_of Integer
|
609
611
|
end
|
610
612
|
end
|
611
613
|
end
|