diff --git a/Library/Homebrew/Gemfile.lock b/Library/Homebrew/Gemfile.lock index be22fccc65..aeb795ac43 100644 --- a/Library/Homebrew/Gemfile.lock +++ b/Library/Homebrew/Gemfile.lock @@ -7,6 +7,8 @@ GEM minitest (>= 5.1) tzinfo (~> 2.0) zeitwerk (~> 2.3) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) ast (2.4.2) bindata (2.4.8) bootsnap (1.7.3) @@ -32,20 +34,21 @@ GEM domain_name (~> 0.5) i18n (1.8.9) concurrent-ruby (~> 1.0) - mechanize (2.7.7) - domain_name (~> 0.5, >= 0.5.1) - http-cookie (~> 1.0) - mime-types (>= 1.17.2) - net-http-digest_auth (~> 1.1, >= 1.1.1) - net-http-persistent (>= 2.5.2) - nokogiri (~> 1.6) - ntlm-http (~> 0.1, >= 0.1.1) + mechanize (2.8.0) + addressable (~> 2.7) + domain_name (~> 0.5, >= 0.5.20190701) + http-cookie (~> 1.0, >= 1.0.3) + mime-types (~> 3.0) + net-http-digest_auth (~> 1.4, >= 1.4.1) + net-http-persistent (>= 2.5.2, < 5.0.dev) + nokogiri (~> 1.11, >= 1.11.2) + rubyntlm (~> 0.6, >= 0.6.3) webrick (~> 1.7) - webrobots (>= 0.0.9, < 0.2) + webrobots (~> 0.1.2) method_source (1.0.0) mime-types (3.3.1) mime-types-data (~> 3.2015) - mime-types-data (3.2021.0212) + mime-types-data (3.2021.0225) mini_portile2 (2.5.0) minitest (5.14.4) msgpack (1.4.2) @@ -56,7 +59,6 @@ GEM nokogiri (1.11.2) mini_portile2 (~> 2.5.0) racc (~> 1.4) - ntlm-http (0.1.1) parallel (1.20.1) parallel_tests (3.6.0) parallel @@ -73,6 +75,7 @@ GEM pry (0.14.0) coderay (~> 1.1) method_source (~> 1.0) + public_suffix (4.0.6) racc (1.5.2) rack (2.2.3) rainbow (3.0.0) @@ -133,6 +136,7 @@ GEM rubocop ruby-macho (2.5.0) ruby-progressbar (1.11.0) + rubyntlm (0.6.3) simplecov (0.21.2) docile (~> 1.1) simplecov-html (~> 0.11) diff --git a/Library/Homebrew/sorbet/rbi/gems/addressable@2.7.0.rbi b/Library/Homebrew/sorbet/rbi/gems/addressable@2.7.0.rbi new file mode 100644 index 0000000000..3a4fed2729 --- /dev/null +++ b/Library/Homebrew/sorbet/rbi/gems/addressable@2.7.0.rbi @@ -0,0 +1,290 @@ +# DO NOT EDIT MANUALLY +# This is an autogenerated file for types exported from the `addressable` gem. +# Please instead update this file by running `bin/tapioca sync`. + +# typed: true + +module Addressable +end + +module Addressable::IDNA + class << self + def to_ascii(input); end + def to_unicode(input); end + def unicode_normalize_kc(input); end + + private + + def lookup_unicode_combining_class(codepoint); end + def lookup_unicode_compatibility(codepoint); end + def lookup_unicode_composition(unpacked); end + def lookup_unicode_lowercase(codepoint); end + def punycode_adapt(delta, numpoints, firsttime); end + def punycode_basic?(codepoint); end + def punycode_decode(punycode); end + def punycode_decode_digit(codepoint); end + def punycode_delimiter?(codepoint); end + def punycode_encode(unicode); end + def punycode_encode_digit(d); end + def unicode_compose(unpacked); end + def unicode_compose_pair(ch_one, ch_two); end + def unicode_decompose(unpacked); end + def unicode_decompose_hangul(codepoint); end + def unicode_downcase(input); end + def unicode_sort_canonical(unpacked); end + end +end + +Addressable::IDNA::ACE_MAX_LENGTH = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::ACE_PREFIX = T.let(T.unsafe(nil), String) + +Addressable::IDNA::COMPOSITION_TABLE = T.let(T.unsafe(nil), Hash) + +Addressable::IDNA::HANGUL_LBASE = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::HANGUL_LCOUNT = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::HANGUL_NCOUNT = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::HANGUL_SBASE = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::HANGUL_SCOUNT = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::HANGUL_TBASE = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::HANGUL_TCOUNT = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::HANGUL_VBASE = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::HANGUL_VCOUNT = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::PUNYCODE_BASE = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::PUNYCODE_DAMP = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::PUNYCODE_DELIMITER = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::PUNYCODE_INITIAL_BIAS = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::PUNYCODE_INITIAL_N = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::PUNYCODE_MAXINT = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::PUNYCODE_PRINT_ASCII = T.let(T.unsafe(nil), String) + +Addressable::IDNA::PUNYCODE_SKEW = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::PUNYCODE_TMAX = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::PUNYCODE_TMIN = T.let(T.unsafe(nil), Integer) + +class Addressable::IDNA::PunycodeBadInput < ::StandardError +end + +class Addressable::IDNA::PunycodeBigOutput < ::StandardError +end + +class Addressable::IDNA::PunycodeOverflow < ::StandardError +end + +Addressable::IDNA::UNICODE_DATA = T.let(T.unsafe(nil), Hash) + +Addressable::IDNA::UNICODE_DATA_CANONICAL = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::UNICODE_DATA_COMBINING_CLASS = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::UNICODE_DATA_COMPATIBILITY = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::UNICODE_DATA_EXCLUSION = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::UNICODE_DATA_LOWERCASE = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::UNICODE_DATA_TITLECASE = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::UNICODE_DATA_UPPERCASE = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::UNICODE_MAX_LENGTH = T.let(T.unsafe(nil), Integer) + +Addressable::IDNA::UNICODE_TABLE = T.let(T.unsafe(nil), String) + +Addressable::IDNA::UTF8_REGEX = T.let(T.unsafe(nil), Regexp) + +Addressable::IDNA::UTF8_REGEX_MULTIBYTE = T.let(T.unsafe(nil), Regexp) + +class Addressable::URI + def initialize(options = T.unsafe(nil)); end + + def +(uri); end + def ==(uri); end + def ===(uri); end + def absolute?; end + def authority; end + def authority=(new_authority); end + def basename; end + def default_port; end + def defer_validation; end + def display_uri; end + def domain; end + def dup; end + def empty?; end + def eql?(uri); end + def extname; end + def fragment; end + def fragment=(new_fragment); end + def freeze; end + def hash; end + def host; end + def host=(new_host); end + def hostname; end + def hostname=(new_hostname); end + def inferred_port; end + def inspect; end + def ip_based?; end + def join(uri); end + def join!(uri); end + def merge(hash); end + def merge!(uri); end + def normalize; end + def normalize!; end + def normalized_authority; end + def normalized_fragment; end + def normalized_host; end + def normalized_password; end + def normalized_path; end + def normalized_port; end + def normalized_query(*flags); end + def normalized_scheme; end + def normalized_site; end + def normalized_user; end + def normalized_userinfo; end + def omit(*components); end + def omit!(*components); end + def origin; end + def origin=(new_origin); end + def password; end + def password=(new_password); end + def path; end + def path=(new_path); end + def port; end + def port=(new_port); end + def query; end + def query=(new_query); end + def query_values(return_type = T.unsafe(nil)); end + def query_values=(new_query_values); end + def relative?; end + def request_uri; end + def request_uri=(new_request_uri); end + def route_from(uri); end + def route_to(uri); end + def scheme; end + def scheme=(new_scheme); end + def site; end + def site=(new_site); end + def tld; end + def tld=(new_tld); end + def to_hash; end + def to_s; end + def to_str; end + def user; end + def user=(new_user); end + def userinfo; end + def userinfo=(new_userinfo); end + + protected + + def remove_composite_values; end + def replace_self(uri); end + def split_path(path); end + def validate; end + + class << self + def convert_path(path); end + def encode(uri, return_type = T.unsafe(nil)); end + def encode_component(component, character_class = T.unsafe(nil), upcase_encoded = T.unsafe(nil)); end + def escape(uri, return_type = T.unsafe(nil)); end + def form_encode(form_values, sort = T.unsafe(nil)); end + def form_unencode(encoded_value); end + def heuristic_parse(uri, hints = T.unsafe(nil)); end + def ip_based_schemes; end + def join(*uris); end + def normalize_component(component, character_class = T.unsafe(nil), leave_encoded = T.unsafe(nil)); end + def normalize_path(path); end + def normalized_encode(uri, return_type = T.unsafe(nil)); end + def parse(uri); end + def port_mapping; end + def unencode(uri, return_type = T.unsafe(nil), leave_encoded = T.unsafe(nil)); end + def unencode_component(uri, return_type = T.unsafe(nil), leave_encoded = T.unsafe(nil)); end + def unescape(uri, return_type = T.unsafe(nil), leave_encoded = T.unsafe(nil)); end + def unescape_component(uri, return_type = T.unsafe(nil), leave_encoded = T.unsafe(nil)); end + end +end + +module Addressable::URI::CharacterClasses +end + +Addressable::URI::CharacterClasses::ALPHA = T.let(T.unsafe(nil), String) + +Addressable::URI::CharacterClasses::AUTHORITY = T.let(T.unsafe(nil), String) + +Addressable::URI::CharacterClasses::DIGIT = T.let(T.unsafe(nil), String) + +Addressable::URI::CharacterClasses::FRAGMENT = T.let(T.unsafe(nil), String) + +Addressable::URI::CharacterClasses::GEN_DELIMS = T.let(T.unsafe(nil), String) + +Addressable::URI::CharacterClasses::HOST = T.let(T.unsafe(nil), String) + +Addressable::URI::CharacterClasses::PATH = T.let(T.unsafe(nil), String) + +Addressable::URI::CharacterClasses::PCHAR = T.let(T.unsafe(nil), String) + +Addressable::URI::CharacterClasses::QUERY = T.let(T.unsafe(nil), String) + +Addressable::URI::CharacterClasses::RESERVED = T.let(T.unsafe(nil), String) + +Addressable::URI::CharacterClasses::SCHEME = T.let(T.unsafe(nil), String) + +Addressable::URI::CharacterClasses::SUB_DELIMS = T.let(T.unsafe(nil), String) + +Addressable::URI::CharacterClasses::UNRESERVED = T.let(T.unsafe(nil), String) + +Addressable::URI::EMPTY_STR = T.let(T.unsafe(nil), String) + +class Addressable::URI::InvalidURIError < ::StandardError +end + +Addressable::URI::NORMPATH = T.let(T.unsafe(nil), Regexp) + +Addressable::URI::PARENT = T.let(T.unsafe(nil), String) + +Addressable::URI::PORT_MAPPING = T.let(T.unsafe(nil), Hash) + +Addressable::URI::RULE_2A = T.let(T.unsafe(nil), Regexp) + +Addressable::URI::RULE_2B_2C = T.let(T.unsafe(nil), Regexp) + +Addressable::URI::RULE_2D = T.let(T.unsafe(nil), Regexp) + +Addressable::URI::RULE_PREFIXED_PARENT = T.let(T.unsafe(nil), Regexp) + +Addressable::URI::SELF_REF = T.let(T.unsafe(nil), String) + +Addressable::URI::SEQUENCE_ENCODING_TABLE = T.let(T.unsafe(nil), Hash) + +Addressable::URI::SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE = T.let(T.unsafe(nil), Hash) + +Addressable::URI::SLASH = T.let(T.unsafe(nil), String) + +Addressable::URI::URIREGEX = T.let(T.unsafe(nil), Regexp) + +module Addressable::VERSION +end + +Addressable::VERSION::MAJOR = T.let(T.unsafe(nil), Integer) + +Addressable::VERSION::MINOR = T.let(T.unsafe(nil), Integer) + +Addressable::VERSION::STRING = T.let(T.unsafe(nil), String) + +Addressable::VERSION::TINY = T.let(T.unsafe(nil), Integer) diff --git a/Library/Homebrew/sorbet/rbi/gems/mechanize@2.7.7.rbi b/Library/Homebrew/sorbet/rbi/gems/mechanize@2.8.0.rbi similarity index 99% rename from Library/Homebrew/sorbet/rbi/gems/mechanize@2.7.7.rbi rename to Library/Homebrew/sorbet/rbi/gems/mechanize@2.8.0.rbi index 843ad5f7cc..ae740567ed 100644 --- a/Library/Homebrew/sorbet/rbi/gems/mechanize@2.7.7.rbi +++ b/Library/Homebrew/sorbet/rbi/gems/mechanize@2.8.0.rbi @@ -1,6 +1,6 @@ # DO NOT EDIT MANUALLY # This is an autogenerated file for types exported from the `mechanize` gem. -# Please instead update this file by running `tapioca sync`. +# Please instead update this file by running `bin/tapioca sync`. # typed: true @@ -293,6 +293,7 @@ class Mechanize::FileResponse def content_length; end def each; end def each_header; end + def file_path; end def get_fields(key); end def http_version; end def message; end @@ -699,6 +700,10 @@ class Mechanize::HTTP::Agent def webrobots; end end +Mechanize::HTTP::Agent::CREDENTIAL_HEADERS = T.let(T.unsafe(nil), Array) + +Mechanize::HTTP::Agent::POST_HEADERS = T.let(T.unsafe(nil), Array) + Mechanize::HTTP::Agent::RobotsKey = T.let(T.unsafe(nil), Symbol) class Mechanize::HTTP::AuthChallenge < ::Struct diff --git a/Library/Homebrew/sorbet/rbi/gems/mime-types-data@3.2021.0212.rbi b/Library/Homebrew/sorbet/rbi/gems/mime-types-data@3.2021.0225.rbi similarity index 96% rename from Library/Homebrew/sorbet/rbi/gems/mime-types-data@3.2021.0212.rbi rename to Library/Homebrew/sorbet/rbi/gems/mime-types-data@3.2021.0225.rbi index c40bda7674..fd45ab967b 100644 --- a/Library/Homebrew/sorbet/rbi/gems/mime-types-data@3.2021.0212.rbi +++ b/Library/Homebrew/sorbet/rbi/gems/mime-types-data@3.2021.0225.rbi @@ -1,6 +1,6 @@ # DO NOT EDIT MANUALLY # This is an autogenerated file for types exported from the `mime-types-data` gem. -# Please instead update this file by running `tapioca sync`. +# Please instead update this file by running `bin/tapioca sync`. # typed: true diff --git a/Library/Homebrew/sorbet/rbi/gems/public_suffix@4.0.6.rbi b/Library/Homebrew/sorbet/rbi/gems/public_suffix@4.0.6.rbi new file mode 100644 index 0000000000..18b49dfcf1 --- /dev/null +++ b/Library/Homebrew/sorbet/rbi/gems/public_suffix@4.0.6.rbi @@ -0,0 +1,152 @@ +# DO NOT EDIT MANUALLY +# This is an autogenerated file for types exported from the `public_suffix` gem. +# Please instead update this file by running `bin/tapioca sync`. + +# typed: true + +module PublicSuffix + class << self + def decompose(name, rule); end + def domain(name, **options); end + def normalize(name); end + def parse(name, list: T.unsafe(nil), default_rule: T.unsafe(nil), ignore_private: T.unsafe(nil)); end + def valid?(name, list: T.unsafe(nil), default_rule: T.unsafe(nil), ignore_private: T.unsafe(nil)); end + end +end + +PublicSuffix::BANG = T.let(T.unsafe(nil), String) + +PublicSuffix::DOT = T.let(T.unsafe(nil), String) + +class PublicSuffix::Domain + def initialize(*args); end + + def domain; end + def domain?; end + def name; end + def sld; end + def subdomain; end + def subdomain?; end + def tld; end + def to_a; end + def to_s; end + def trd; end + + class << self + def name_to_labels(name); end + end +end + +class PublicSuffix::DomainInvalid < ::PublicSuffix::Error +end + +class PublicSuffix::DomainNotAllowed < ::PublicSuffix::DomainInvalid +end + +class PublicSuffix::Error < ::StandardError +end + +class PublicSuffix::List + def initialize; end + + def <<(rule); end + def ==(other); end + def add(rule); end + def clear; end + def default_rule; end + def each(&block); end + def empty?; end + def eql?(other); end + def find(name, default: T.unsafe(nil), **options); end + def size; end + + protected + + def rules; end + + private + + def entry_to_rule(entry, value); end + def rule_to_entry(rule); end + def select(name, ignore_private: T.unsafe(nil)); end + + class << self + def default(**options); end + def default=(value); end + def parse(input, private_domains: T.unsafe(nil)); end + end +end + +PublicSuffix::List::DEFAULT_LIST_PATH = T.let(T.unsafe(nil), String) + +module PublicSuffix::Rule + class << self + def default; end + def factory(content, private: T.unsafe(nil)); end + end +end + +class PublicSuffix::Rule::Base + def initialize(value:, length: T.unsafe(nil), private: T.unsafe(nil)); end + + def ==(other); end + def decompose(*_arg0); end + def eql?(other); end + def length; end + def match?(name); end + def parts; end + def private; end + def value; end + + class << self + def build(content, private: T.unsafe(nil)); end + end +end + +class PublicSuffix::Rule::Entry < ::Struct + def length; end + def length=(_); end + def private; end + def private=(_); end + def type; end + def type=(_); end + + class << self + def [](*_arg0); end + def inspect; end + def members; end + def new(*_arg0); end + end +end + +class PublicSuffix::Rule::Exception < ::PublicSuffix::Rule::Base + def decompose(domain); end + def parts; end + def rule; end + + class << self + def build(content, private: T.unsafe(nil)); end + end +end + +class PublicSuffix::Rule::Normal < ::PublicSuffix::Rule::Base + def decompose(domain); end + def parts; end + def rule; end +end + +class PublicSuffix::Rule::Wildcard < ::PublicSuffix::Rule::Base + def initialize(value:, length: T.unsafe(nil), private: T.unsafe(nil)); end + + def decompose(domain); end + def parts; end + def rule; end + + class << self + def build(content, private: T.unsafe(nil)); end + end +end + +PublicSuffix::STAR = T.let(T.unsafe(nil), String) + +PublicSuffix::VERSION = T.let(T.unsafe(nil), String) diff --git a/Library/Homebrew/sorbet/rbi/gems/ntlm-http@0.1.1.rbi b/Library/Homebrew/sorbet/rbi/gems/rubyntlm@0.6.3.rbi similarity index 60% rename from Library/Homebrew/sorbet/rbi/gems/ntlm-http@0.1.1.rbi rename to Library/Homebrew/sorbet/rbi/gems/rubyntlm@0.6.3.rbi index 8ad5317067..f0dbfb9b77 100644 --- a/Library/Homebrew/sorbet/rbi/gems/ntlm-http@0.1.1.rbi +++ b/Library/Homebrew/sorbet/rbi/gems/rubyntlm@0.6.3.rbi @@ -1,15 +1,14 @@ # DO NOT EDIT MANUALLY -# This is an autogenerated file for types exported from the `ntlm-http` gem. -# Please instead update this file by running `tapioca generate --exclude json`. +# This is an autogenerated file for types exported from the `rubyntlm` gem. +# Please instead update this file by running `bin/tapioca sync`. # typed: true module Net::NTLM class << self def apply_des(plain, keys); end - def decode_utf16le(str); end - def encode_utf16le(str); end def gen_keys(str); end + def is_ntlm_hash?(data); end def lm_hash(password); end def lm_response(arg); end def lmv2_response(arg, opt = T.unsafe(nil)); end @@ -20,7 +19,6 @@ module Net::NTLM def ntlmv2_response(arg, opt = T.unsafe(nil)); end def pack_int64le(val); end def split7(str); end - def swap16(str); end end end @@ -29,6 +27,7 @@ class Net::NTLM::Blob < ::Net::NTLM::FieldSet def blob_signature=(val); end def challenge; end def challenge=(val); end + def parse(str, offset = T.unsafe(nil)); end def reserved; end def reserved=(val); end def target_info; end @@ -39,9 +38,91 @@ class Net::NTLM::Blob < ::Net::NTLM::FieldSet def unknown1=(val); end def unknown2; end def unknown2=(val); end +end + +class Net::NTLM::ChannelBinding + def initialize(outer_channel); end + + def acceptor_address_length; end + def acceptor_addrtype; end + def application_data; end + def channel; end + def channel_binding_token; end + def channel_hash; end + def gss_channel_bindings_struct; end + def initiator_address_length; end + def initiator_addtype; end + def unique_prefix; end class << self - def inherited(subclass); end + def create(outer_channel); end + end +end + +class Net::NTLM::Client + def initialize(username, password, opts = T.unsafe(nil)); end + + def domain; end + def flags; end + def init_context(resp = T.unsafe(nil), channel_binding = T.unsafe(nil)); end + def password; end + def session; end + def session_key; end + def username; end + def workstation; end + + private + + def type1_message; end +end + +class Net::NTLM::Client::Session + def initialize(client, challenge_message, channel_binding = T.unsafe(nil)); end + + def authenticate!; end + def challenge_message; end + def channel_binding; end + def client; end + def exported_session_key; end + def seal_message(message); end + def sign_message(message); end + def unseal_message(emessage); end + def verify_signature(signature, message); end + + private + + def blob; end + def calculate_user_session_key!; end + def client_challenge; end + def client_cipher; end + def client_seal_key; end + def client_sign_key; end + def domain; end + def lmv2_resp; end + def negotiate_key_exchange?; end + def nt_proof_str; end + def ntlmv2_hash; end + def ntlmv2_resp; end + def oem_or_unicode_str(str); end + def password; end + def raw_sequence; end + def sequence; end + def server_challenge; end + def server_cipher; end + def server_seal_key; end + def server_sign_key; end + def target_info; end + def timestamp; end + def use_oem_strings?; end + def user_session_key; end + def username; end + def workstation; end +end + +class Net::NTLM::EncodeUtil + class << self + def decode_utf16le(str); end + def encode_utf16le(str); end end end @@ -49,10 +130,12 @@ class Net::NTLM::Field def initialize(opts); end def active; end - def active=(_); end + def active=(_arg0); end + def parse(str, offset = T.unsafe(nil)); end + def serialize; end def size; end def value; end - def value=(_); end + def value=(_arg0); end end class Net::NTLM::FieldSet @@ -62,12 +145,12 @@ class Net::NTLM::FieldSet def []=(name, val); end def disable(name); end def enable(name); end + def has_disabled_fields?; end def parse(str, offset = T.unsafe(nil)); end def serialize; end def size; end class << self - def define(&block); end def int16LE(name, opts); end def int32LE(name, opts); end def int64LE(name, opts); end @@ -106,23 +189,27 @@ class Net::NTLM::Int64LE < ::Net::NTLM::Field def serialize; end end +class Net::NTLM::InvalidTargetDataError < ::Net::NTLM::NtlmError + def initialize(msg, data); end + + def data; end +end + class Net::NTLM::Message < ::Net::NTLM::FieldSet + def data_edge; end def data_size; end def decode64(str); end + def deflag; end def dump_flags; end def encode64; end def has_flag?(flag); end def head_size; end + def parse(str); end + def security_buffers; end def serialize; end def set_flag(flag); end def size; end - private - - def data_edge; end - def deflag; end - def security_buffers; end - class << self def decode64(str); end def parse(str); end @@ -134,10 +221,6 @@ class Net::NTLM::Message::Type0 < ::Net::NTLM::Message def sign=(val); end def type; end def type=(val); end - - class << self - def inherited(subclass); end - end end class Net::NTLM::Message::Type1 < ::Net::NTLM::Message @@ -145,20 +228,14 @@ class Net::NTLM::Message::Type1 < ::Net::NTLM::Message def domain=(val); end def flag; end def flag=(val); end - def padding; end - def padding=(val); end - def parse(str); end + def os_version; end + def os_version=(val); end def sign; end def sign=(val); end def type; end def type=(val); end def workstation; end def workstation=(val); end - - class << self - def inherited(subclass); end - def parse(str); end - end end class Net::NTLM::Message::Type2 < ::Net::NTLM::Message @@ -168,9 +245,8 @@ class Net::NTLM::Message::Type2 < ::Net::NTLM::Message def context=(val); end def flag; end def flag=(val); end - def padding; end - def padding=(val); end - def parse(str); end + def os_version; end + def os_version=(val); end def response(arg, opt = T.unsafe(nil)); end def sign; end def sign=(val); end @@ -180,14 +256,10 @@ class Net::NTLM::Message::Type2 < ::Net::NTLM::Message def target_name=(val); end def type; end def type=(val); end - - class << self - def inherited(subclass); end - def parse(str); end - end end class Net::NTLM::Message::Type3 < ::Net::NTLM::Message + def blank_password?(server_challenge); end def domain; end def domain=(val); end def flag; end @@ -196,6 +268,10 @@ class Net::NTLM::Message::Type3 < ::Net::NTLM::Message def lm_response=(val); end def ntlm_response; end def ntlm_response=(val); end + def ntlm_version; end + def os_version; end + def os_version=(val); end + def password?(password, server_challenge); end def session_key; end def session_key=(val); end def sign; end @@ -207,18 +283,21 @@ class Net::NTLM::Message::Type3 < ::Net::NTLM::Message def workstation; end def workstation=(val); end + private + + def ntlm2_session_password?(password, server_challenge); end + def ntlmv2_password?(password, server_challenge); end + class << self def create(arg, opt = T.unsafe(nil)); end - def inherited(subclass); end - def parse(str); end end end class Net::NTLM::SecurityBuffer < ::Net::NTLM::FieldSet - def initialize(opts); end + def initialize(opts = T.unsafe(nil)); end def active; end - def active=(_); end + def active=(_arg0); end def allocated; end def allocated=(val); end def data_size; end @@ -230,10 +309,6 @@ class Net::NTLM::SecurityBuffer < ::Net::NTLM::FieldSet def serialize; end def value; end def value=(val); end - - class << self - def inherited(subclass); end - end end class Net::NTLM::String < ::Net::NTLM::Field @@ -244,13 +319,14 @@ class Net::NTLM::String < ::Net::NTLM::Field def value=(val); end end -module Net::NTLM::VERSION +class Net::NTLM::TargetInfo + def initialize(av_pair_sequence); end + + def av_pairs; end + def to_s; end + + private + + def read_pairs(av_pair_sequence); end + def to_hex(str); end end - -Net::NTLM::VERSION::MAJOR = T.let(T.unsafe(nil), Integer) - -Net::NTLM::VERSION::MINOR = T.let(T.unsafe(nil), Integer) - -Net::NTLM::VERSION::STRING = T.let(T.unsafe(nil), String) - -Net::NTLM::VERSION::TINY = T.let(T.unsafe(nil), Integer) diff --git a/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi b/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi index 24be57ff5d..e195eb3242 100644 --- a/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi +++ b/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi @@ -2685,6 +2685,104 @@ module ActiveSupport def self.version(); end end +class Addressable::Template + def ==(template); end + + def eql?(template); end + + def expand(mapping, processor=T.unsafe(nil), normalize_values=T.unsafe(nil)); end + + def extract(uri, processor=T.unsafe(nil)); end + + def generate(params=T.unsafe(nil), recall=T.unsafe(nil), options=T.unsafe(nil)); end + + def initialize(pattern); end + + def keys(); end + + def match(uri, processor=T.unsafe(nil)); end + + def named_captures(); end + + def names(); end + + def partial_expand(mapping, processor=T.unsafe(nil), normalize_values=T.unsafe(nil)); end + + def pattern(); end + + def source(); end + + def to_regexp(); end + + def variable_defaults(); end + + def variables(); end + EXPRESSION = ::T.let(nil, ::T.untyped) + JOINERS = ::T.let(nil, ::T.untyped) + LEADERS = ::T.let(nil, ::T.untyped) + RESERVED = ::T.let(nil, ::T.untyped) + UNRESERVED = ::T.let(nil, ::T.untyped) + VARIABLE_LIST = ::T.let(nil, ::T.untyped) + VARNAME = ::T.let(nil, ::T.untyped) + VARSPEC = ::T.let(nil, ::T.untyped) +end + +class Addressable::Template::InvalidTemplateOperatorError +end + +class Addressable::Template::InvalidTemplateOperatorError +end + +class Addressable::Template::InvalidTemplateValueError +end + +class Addressable::Template::InvalidTemplateValueError +end + +class Addressable::Template::MatchData + def [](key, len=T.unsafe(nil)); end + + def captures(); end + + def initialize(uri, template, mapping); end + + def keys(); end + + def mapping(); end + + def names(); end + + def post_match(); end + + def pre_match(); end + + def string(); end + + def template(); end + + def to_a(); end + + def uri(); end + + def values(); end + + def values_at(*indexes); end + + def variables(); end +end + +class Addressable::Template::MatchData +end + +class Addressable::Template::TemplateOperatorAbortedError +end + +class Addressable::Template::TemplateOperatorAbortedError +end + +class Addressable::Template +end + class Addrinfo def connect_internal(local_addrinfo, timeout=T.unsafe(nil)); end end @@ -9630,12 +9728,6 @@ JSON::State = JSON::Ext::Generator::State JSON::UnparserError = JSON::GeneratorError -module Kconv - AUTO = ::T.let(nil, ::T.untyped) - NOCONV = ::T.let(nil, ::T.untyped) - UNKNOWN = ::T.let(nil, ::T.untyped) -end - class Keg::ConflictError extend ::T::Private::Methods::MethodHooks extend ::T::Private::Methods::SingletonMethodHooks @@ -12349,13 +12441,9 @@ end Net::HTTPFatalErrorCode = Net::HTTPClientError -class Net::HTTPInformation -end +Net::HTTPInformation::EXCEPTION_TYPE = Net::HTTPError -Net::HTTPInformationCode::EXCEPTION_TYPE = Net::HTTPError - -class Net::HTTPInformation -end +Net::HTTPInformationCode = Net::HTTPInformation class Net::HTTPLoopDetected HAS_BODY = ::T.let(nil, ::T.untyped) @@ -12419,13 +12507,9 @@ Net::HTTPServerErrorCode = Net::HTTPServerError Net::HTTPSession = Net::HTTP -class Net::HTTPSuccess -end +Net::HTTPSuccess::EXCEPTION_TYPE = Net::HTTPError -Net::HTTPSuccessCode::EXCEPTION_TYPE = Net::HTTPError - -class Net::HTTPSuccess -end +Net::HTTPSuccessCode = Net::HTTPSuccess class Net::HTTPURITooLong HAS_BODY = ::T.let(nil, ::T.untyped) @@ -29167,18 +29251,8 @@ class String def indent!(amount, indent_string=T.unsafe(nil), indent_empty_lines=T.unsafe(nil)); end - def iseuc(); end - - def isjis(); end - - def issjis(); end - - def isutf8(); end - def italic(); end - def kconv(to_enc, from_enc=T.unsafe(nil)); end - def light_black(); end def light_blue(); end @@ -29259,20 +29333,6 @@ class String def to_time(form=T.unsafe(nil)); end - def toeuc(); end - - def tojis(); end - - def tolocale(); end - - def tosjis(); end - - def toutf16(); end - - def toutf32(); end - - def toutf8(); end - def truncate(truncate_at, options=T.unsafe(nil)); end def truncate_bytes(truncate_at, omission: T.unsafe(nil)); end diff --git a/Library/Homebrew/vendor/bundle/bundler/setup.rb b/Library/Homebrew/vendor/bundle/bundler/setup.rb index 3c86c84358..1283bc4911 100644 --- a/Library/Homebrew/vendor/bundle/bundler/setup.rb +++ b/Library/Homebrew/vendor/bundle/bundler/setup.rb @@ -9,6 +9,8 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/minitest-5.14.4/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/tzinfo-2.0.4/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/zeitwerk-2.4.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/activesupport-6.1.3.1/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/public_suffix-4.0.6/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/addressable-2.7.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ast-2.4.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bindata-2.4.8/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-14/2.6.0-static/msgpack-1.4.2" @@ -37,7 +39,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/elftools-1.1.3/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-14/2.6.0-static/hpricot-0.8.6" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/hpricot-0.8.6/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/http-cookie-1.0.3/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mime-types-data-3.2021.0212/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mime-types-data-3.2021.0225/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mime-types-3.3.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/net-http-digest_auth-1.4.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/net-http-persistent-4.0.1/lib" @@ -45,10 +47,10 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mini_portile2-2.5.0/l $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-14/2.6.0-static/racc-1.5.2" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/racc-1.5.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/nokogiri-1.11.2-x86_64-darwin/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ntlm-http-0.1.1/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubyntlm-0.6.3/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/webrick-1.7.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/webrobots-0.1.2/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mechanize-2.7.7/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mechanize-2.8.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/method_source-1.0.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mustache-1.1.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel-1.20.1/lib" diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable.rb new file mode 100644 index 0000000000..b4e98b6965 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +require 'addressable/uri' +require 'addressable/template' diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/idna.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/idna.rb new file mode 100644 index 0000000000..e41c1f5da4 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/idna.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +# encoding:utf-8 +#-- +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +begin + require "addressable/idna/native" +rescue LoadError + # libidn or the idn gem was not available, fall back on a pure-Ruby + # implementation... + require "addressable/idna/pure" +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/idna/native.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/idna/native.rb new file mode 100644 index 0000000000..84de8e8cb4 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/idna/native.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +# encoding:utf-8 +#-- +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +require "idn" + +module Addressable + module IDNA + def self.punycode_encode(value) + IDN::Punycode.encode(value.to_s) + end + + def self.punycode_decode(value) + IDN::Punycode.decode(value.to_s) + end + + def self.unicode_normalize_kc(value) + IDN::Stringprep.nfkc_normalize(value.to_s) + end + + def self.to_ascii(value) + value.to_s.split('.', -1).map do |segment| + if segment.size > 0 && segment.size < 64 + IDN::Idna.toASCII(segment, IDN::Idna::ALLOW_UNASSIGNED) + elsif segment.size >= 64 + segment + else + '' + end + end.join('.') + end + + def self.to_unicode(value) + value.to_s.split('.', -1).map do |segment| + if segment.size > 0 && segment.size < 64 + IDN::Idna.toUnicode(segment, IDN::Idna::ALLOW_UNASSIGNED) + elsif segment.size >= 64 + segment + else + '' + end + end.join('.') + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/idna/pure.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/idna/pure.rb new file mode 100644 index 0000000000..f7c553c669 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/idna/pure.rb @@ -0,0 +1,676 @@ +# frozen_string_literal: true + +# encoding:utf-8 +#-- +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +module Addressable + module IDNA + # This module is loosely based on idn_actionmailer by Mick Staugaard, + # the unicode library by Yoshida Masato, and the punycode implementation + # by Kazuhiro Nishiyama. Most of the code was copied verbatim, but + # some reformatting was done, and some translation from C was done. + # + # Without their code to work from as a base, we'd all still be relying + # on the presence of libidn. Which nobody ever seems to have installed. + # + # Original sources: + # http://github.com/staugaard/idn_actionmailer + # http://www.yoshidam.net/Ruby.html#unicode + # http://rubyforge.org/frs/?group_id=2550 + + + UNICODE_TABLE = File.expand_path( + File.join(File.dirname(__FILE__), '../../..', 'data/unicode.data') + ) + + ACE_PREFIX = "xn--" + + UTF8_REGEX = /\A(?: + [\x09\x0A\x0D\x20-\x7E] # ASCII + | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} # planes 4nil5 + | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 + )*\z/mnx + + UTF8_REGEX_MULTIBYTE = /(?: + [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} # planes 4nil5 + | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 + )/mnx + + # :startdoc: + + # Converts from a Unicode internationalized domain name to an ASCII + # domain name as described in RFC 3490. + def self.to_ascii(input) + input = input.to_s unless input.is_a?(String) + input = input.dup + if input.respond_to?(:force_encoding) + input.force_encoding(Encoding::ASCII_8BIT) + end + if input =~ UTF8_REGEX && input =~ UTF8_REGEX_MULTIBYTE + parts = unicode_downcase(input).split('.') + parts.map! do |part| + if part.respond_to?(:force_encoding) + part.force_encoding(Encoding::ASCII_8BIT) + end + if part =~ UTF8_REGEX && part =~ UTF8_REGEX_MULTIBYTE + ACE_PREFIX + punycode_encode(unicode_normalize_kc(part)) + else + part + end + end + parts.join('.') + else + input + end + end + + # Converts from an ASCII domain name to a Unicode internationalized + # domain name as described in RFC 3490. + def self.to_unicode(input) + input = input.to_s unless input.is_a?(String) + parts = input.split('.') + parts.map! do |part| + if part =~ /^#{ACE_PREFIX}(.+)/ + begin + punycode_decode(part[/^#{ACE_PREFIX}(.+)/, 1]) + rescue Addressable::IDNA::PunycodeBadInput + # toUnicode is explicitly defined as never-fails by the spec + part + end + else + part + end + end + output = parts.join('.') + if output.respond_to?(:force_encoding) + output.force_encoding(Encoding::UTF_8) + end + output + end + + # Unicode normalization form KC. + def self.unicode_normalize_kc(input) + input = input.to_s unless input.is_a?(String) + unpacked = input.unpack("U*") + unpacked = + unicode_compose(unicode_sort_canonical(unicode_decompose(unpacked))) + return unpacked.pack("U*") + end + + ## + # Unicode aware downcase method. + # + # @api private + # @param [String] input + # The input string. + # @return [String] The downcased result. + def self.unicode_downcase(input) + input = input.to_s unless input.is_a?(String) + unpacked = input.unpack("U*") + unpacked.map! { |codepoint| lookup_unicode_lowercase(codepoint) } + return unpacked.pack("U*") + end + private_class_method :unicode_downcase + + def self.unicode_compose(unpacked) + unpacked_result = [] + length = unpacked.length + + return unpacked if length == 0 + + starter = unpacked[0] + starter_cc = lookup_unicode_combining_class(starter) + starter_cc = 256 if starter_cc != 0 + for i in 1...length + ch = unpacked[i] + + if (starter_cc == 0 && + (composite = unicode_compose_pair(starter, ch)) != nil) + starter = composite + else + unpacked_result << starter + starter = ch + end + end + unpacked_result << starter + return unpacked_result + end + private_class_method :unicode_compose + + def self.unicode_compose_pair(ch_one, ch_two) + if ch_one >= HANGUL_LBASE && ch_one < HANGUL_LBASE + HANGUL_LCOUNT && + ch_two >= HANGUL_VBASE && ch_two < HANGUL_VBASE + HANGUL_VCOUNT + # Hangul L + V + return HANGUL_SBASE + ( + (ch_one - HANGUL_LBASE) * HANGUL_VCOUNT + (ch_two - HANGUL_VBASE) + ) * HANGUL_TCOUNT + elsif ch_one >= HANGUL_SBASE && + ch_one < HANGUL_SBASE + HANGUL_SCOUNT && + (ch_one - HANGUL_SBASE) % HANGUL_TCOUNT == 0 && + ch_two >= HANGUL_TBASE && ch_two < HANGUL_TBASE + HANGUL_TCOUNT + # Hangul LV + T + return ch_one + (ch_two - HANGUL_TBASE) + end + + p = [] + ucs4_to_utf8 = lambda do |ch| + if ch < 128 + p << ch + elsif ch < 2048 + p << (ch >> 6 | 192) + p << (ch & 63 | 128) + elsif ch < 0x10000 + p << (ch >> 12 | 224) + p << (ch >> 6 & 63 | 128) + p << (ch & 63 | 128) + elsif ch < 0x200000 + p << (ch >> 18 | 240) + p << (ch >> 12 & 63 | 128) + p << (ch >> 6 & 63 | 128) + p << (ch & 63 | 128) + elsif ch < 0x4000000 + p << (ch >> 24 | 248) + p << (ch >> 18 & 63 | 128) + p << (ch >> 12 & 63 | 128) + p << (ch >> 6 & 63 | 128) + p << (ch & 63 | 128) + elsif ch < 0x80000000 + p << (ch >> 30 | 252) + p << (ch >> 24 & 63 | 128) + p << (ch >> 18 & 63 | 128) + p << (ch >> 12 & 63 | 128) + p << (ch >> 6 & 63 | 128) + p << (ch & 63 | 128) + end + end + + ucs4_to_utf8.call(ch_one) + ucs4_to_utf8.call(ch_two) + + return lookup_unicode_composition(p) + end + private_class_method :unicode_compose_pair + + def self.unicode_sort_canonical(unpacked) + unpacked = unpacked.dup + i = 1 + length = unpacked.length + + return unpacked if length < 2 + + while i < length + last = unpacked[i-1] + ch = unpacked[i] + last_cc = lookup_unicode_combining_class(last) + cc = lookup_unicode_combining_class(ch) + if cc != 0 && last_cc != 0 && last_cc > cc + unpacked[i] = last + unpacked[i-1] = ch + i -= 1 if i > 1 + else + i += 1 + end + end + return unpacked + end + private_class_method :unicode_sort_canonical + + def self.unicode_decompose(unpacked) + unpacked_result = [] + for cp in unpacked + if cp >= HANGUL_SBASE && cp < HANGUL_SBASE + HANGUL_SCOUNT + l, v, t = unicode_decompose_hangul(cp) + unpacked_result << l + unpacked_result << v if v + unpacked_result << t if t + else + dc = lookup_unicode_compatibility(cp) + unless dc + unpacked_result << cp + else + unpacked_result.concat(unicode_decompose(dc.unpack("U*"))) + end + end + end + return unpacked_result + end + private_class_method :unicode_decompose + + def self.unicode_decompose_hangul(codepoint) + sindex = codepoint - HANGUL_SBASE; + if sindex < 0 || sindex >= HANGUL_SCOUNT + l = codepoint + v = t = nil + return l, v, t + end + l = HANGUL_LBASE + sindex / HANGUL_NCOUNT + v = HANGUL_VBASE + (sindex % HANGUL_NCOUNT) / HANGUL_TCOUNT + t = HANGUL_TBASE + sindex % HANGUL_TCOUNT + if t == HANGUL_TBASE + t = nil + end + return l, v, t + end + private_class_method :unicode_decompose_hangul + + def self.lookup_unicode_combining_class(codepoint) + codepoint_data = UNICODE_DATA[codepoint] + (codepoint_data ? + (codepoint_data[UNICODE_DATA_COMBINING_CLASS] || 0) : + 0) + end + private_class_method :lookup_unicode_combining_class + + def self.lookup_unicode_compatibility(codepoint) + codepoint_data = UNICODE_DATA[codepoint] + (codepoint_data ? + codepoint_data[UNICODE_DATA_COMPATIBILITY] : nil) + end + private_class_method :lookup_unicode_compatibility + + def self.lookup_unicode_lowercase(codepoint) + codepoint_data = UNICODE_DATA[codepoint] + (codepoint_data ? + (codepoint_data[UNICODE_DATA_LOWERCASE] || codepoint) : + codepoint) + end + private_class_method :lookup_unicode_lowercase + + def self.lookup_unicode_composition(unpacked) + return COMPOSITION_TABLE[unpacked] + end + private_class_method :lookup_unicode_composition + + HANGUL_SBASE = 0xac00 + HANGUL_LBASE = 0x1100 + HANGUL_LCOUNT = 19 + HANGUL_VBASE = 0x1161 + HANGUL_VCOUNT = 21 + HANGUL_TBASE = 0x11a7 + HANGUL_TCOUNT = 28 + HANGUL_NCOUNT = HANGUL_VCOUNT * HANGUL_TCOUNT # 588 + HANGUL_SCOUNT = HANGUL_LCOUNT * HANGUL_NCOUNT # 11172 + + UNICODE_DATA_COMBINING_CLASS = 0 + UNICODE_DATA_EXCLUSION = 1 + UNICODE_DATA_CANONICAL = 2 + UNICODE_DATA_COMPATIBILITY = 3 + UNICODE_DATA_UPPERCASE = 4 + UNICODE_DATA_LOWERCASE = 5 + UNICODE_DATA_TITLECASE = 6 + + begin + if defined?(FakeFS) + fakefs_state = FakeFS.activated? + FakeFS.deactivate! + end + # This is a sparse Unicode table. Codepoints without entries are + # assumed to have the value: [0, 0, nil, nil, nil, nil, nil] + UNICODE_DATA = File.open(UNICODE_TABLE, "rb") do |file| + Marshal.load(file.read) + end + ensure + if defined?(FakeFS) + FakeFS.activate! if fakefs_state + end + end + + COMPOSITION_TABLE = {} + UNICODE_DATA.each do |codepoint, data| + canonical = data[UNICODE_DATA_CANONICAL] + exclusion = data[UNICODE_DATA_EXCLUSION] + + if canonical && exclusion == 0 + COMPOSITION_TABLE[canonical.unpack("C*")] = codepoint + end + end + + UNICODE_MAX_LENGTH = 256 + ACE_MAX_LENGTH = 256 + + PUNYCODE_BASE = 36 + PUNYCODE_TMIN = 1 + PUNYCODE_TMAX = 26 + PUNYCODE_SKEW = 38 + PUNYCODE_DAMP = 700 + PUNYCODE_INITIAL_BIAS = 72 + PUNYCODE_INITIAL_N = 0x80 + PUNYCODE_DELIMITER = 0x2D + + PUNYCODE_MAXINT = 1 << 64 + + PUNYCODE_PRINT_ASCII = + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + + " !\"\#$%&'()*+,-./" + + "0123456789:;<=>?" + + "@ABCDEFGHIJKLMNO" + + "PQRSTUVWXYZ[\\]^_" + + "`abcdefghijklmno" + + "pqrstuvwxyz{|}~\n" + + # Input is invalid. + class PunycodeBadInput < StandardError; end + # Output would exceed the space provided. + class PunycodeBigOutput < StandardError; end + # Input needs wider integers to process. + class PunycodeOverflow < StandardError; end + + def self.punycode_encode(unicode) + unicode = unicode.to_s unless unicode.is_a?(String) + input = unicode.unpack("U*") + output = [0] * (ACE_MAX_LENGTH + 1) + input_length = input.size + output_length = [ACE_MAX_LENGTH] + + # Initialize the state + n = PUNYCODE_INITIAL_N + delta = out = 0 + max_out = output_length[0] + bias = PUNYCODE_INITIAL_BIAS + + # Handle the basic code points: + input_length.times do |j| + if punycode_basic?(input[j]) + if max_out - out < 2 + raise PunycodeBigOutput, + "Output would exceed the space provided." + end + output[out] = input[j] + out += 1 + end + end + + h = b = out + + # h is the number of code points that have been handled, b is the + # number of basic code points, and out is the number of characters + # that have been output. + + if b > 0 + output[out] = PUNYCODE_DELIMITER + out += 1 + end + + # Main encoding loop: + + while h < input_length + # All non-basic code points < n have been + # handled already. Find the next larger one: + + m = PUNYCODE_MAXINT + input_length.times do |j| + m = input[j] if (n...m) === input[j] + end + + # Increase delta enough to advance the decoder's + # state to , but guard against overflow: + + if m - n > (PUNYCODE_MAXINT - delta) / (h + 1) + raise PunycodeOverflow, "Input needs wider integers to process." + end + delta += (m - n) * (h + 1) + n = m + + input_length.times do |j| + # Punycode does not need to check whether input[j] is basic: + if input[j] < n + delta += 1 + if delta == 0 + raise PunycodeOverflow, + "Input needs wider integers to process." + end + end + + if input[j] == n + # Represent delta as a generalized variable-length integer: + + q = delta; k = PUNYCODE_BASE + while true + if out >= max_out + raise PunycodeBigOutput, + "Output would exceed the space provided." + end + t = ( + if k <= bias + PUNYCODE_TMIN + elsif k >= bias + PUNYCODE_TMAX + PUNYCODE_TMAX + else + k - bias + end + ) + break if q < t + output[out] = + punycode_encode_digit(t + (q - t) % (PUNYCODE_BASE - t)) + out += 1 + q = (q - t) / (PUNYCODE_BASE - t) + k += PUNYCODE_BASE + end + + output[out] = punycode_encode_digit(q) + out += 1 + bias = punycode_adapt(delta, h + 1, h == b) + delta = 0 + h += 1 + end + end + + delta += 1 + n += 1 + end + + output_length[0] = out + + outlen = out + outlen.times do |j| + c = output[j] + unless c >= 0 && c <= 127 + raise StandardError, "Invalid output char." + end + unless PUNYCODE_PRINT_ASCII[c] + raise PunycodeBadInput, "Input is invalid." + end + end + + output[0..outlen].map { |x| x.chr }.join("").sub(/\0+\z/, "") + end + private_class_method :punycode_encode + + def self.punycode_decode(punycode) + input = [] + output = [] + + if ACE_MAX_LENGTH * 2 < punycode.size + raise PunycodeBigOutput, "Output would exceed the space provided." + end + punycode.each_byte do |c| + unless c >= 0 && c <= 127 + raise PunycodeBadInput, "Input is invalid." + end + input.push(c) + end + + input_length = input.length + output_length = [UNICODE_MAX_LENGTH] + + # Initialize the state + n = PUNYCODE_INITIAL_N + + out = i = 0 + max_out = output_length[0] + bias = PUNYCODE_INITIAL_BIAS + + # Handle the basic code points: Let b be the number of input code + # points before the last delimiter, or 0 if there is none, then + # copy the first b code points to the output. + + b = 0 + input_length.times do |j| + b = j if punycode_delimiter?(input[j]) + end + if b > max_out + raise PunycodeBigOutput, "Output would exceed the space provided." + end + + b.times do |j| + unless punycode_basic?(input[j]) + raise PunycodeBadInput, "Input is invalid." + end + output[out] = input[j] + out+=1 + end + + # Main decoding loop: Start just after the last delimiter if any + # basic code points were copied; start at the beginning otherwise. + + in_ = b > 0 ? b + 1 : 0 + while in_ < input_length + + # in_ is the index of the next character to be consumed, and + # out is the number of code points in the output array. + + # Decode a generalized variable-length integer into delta, + # which gets added to i. The overflow checking is easier + # if we increase i as we go, then subtract off its starting + # value at the end to obtain delta. + + oldi = i; w = 1; k = PUNYCODE_BASE + while true + if in_ >= input_length + raise PunycodeBadInput, "Input is invalid." + end + digit = punycode_decode_digit(input[in_]) + in_+=1 + if digit >= PUNYCODE_BASE + raise PunycodeBadInput, "Input is invalid." + end + if digit > (PUNYCODE_MAXINT - i) / w + raise PunycodeOverflow, "Input needs wider integers to process." + end + i += digit * w + t = ( + if k <= bias + PUNYCODE_TMIN + elsif k >= bias + PUNYCODE_TMAX + PUNYCODE_TMAX + else + k - bias + end + ) + break if digit < t + if w > PUNYCODE_MAXINT / (PUNYCODE_BASE - t) + raise PunycodeOverflow, "Input needs wider integers to process." + end + w *= PUNYCODE_BASE - t + k += PUNYCODE_BASE + end + + bias = punycode_adapt(i - oldi, out + 1, oldi == 0) + + # I was supposed to wrap around from out + 1 to 0, + # incrementing n each time, so we'll fix that now: + + if i / (out + 1) > PUNYCODE_MAXINT - n + raise PunycodeOverflow, "Input needs wider integers to process." + end + n += i / (out + 1) + i %= out + 1 + + # Insert n at position i of the output: + + # not needed for Punycode: + # raise PUNYCODE_INVALID_INPUT if decode_digit(n) <= base + if out >= max_out + raise PunycodeBigOutput, "Output would exceed the space provided." + end + + #memmove(output + i + 1, output + i, (out - i) * sizeof *output) + output[i + 1, out - i] = output[i, out - i] + output[i] = n + i += 1 + + out += 1 + end + + output_length[0] = out + + output.pack("U*") + end + private_class_method :punycode_decode + + def self.punycode_basic?(codepoint) + codepoint < 0x80 + end + private_class_method :punycode_basic? + + def self.punycode_delimiter?(codepoint) + codepoint == PUNYCODE_DELIMITER + end + private_class_method :punycode_delimiter? + + def self.punycode_encode_digit(d) + d + 22 + 75 * ((d < 26) ? 1 : 0) + end + private_class_method :punycode_encode_digit + + # Returns the numeric value of a basic codepoint + # (for use in representing integers) in the range 0 to + # base - 1, or PUNYCODE_BASE if codepoint does not represent a value. + def self.punycode_decode_digit(codepoint) + if codepoint - 48 < 10 + codepoint - 22 + elsif codepoint - 65 < 26 + codepoint - 65 + elsif codepoint - 97 < 26 + codepoint - 97 + else + PUNYCODE_BASE + end + end + private_class_method :punycode_decode_digit + + # Bias adaptation method + def self.punycode_adapt(delta, numpoints, firsttime) + delta = firsttime ? delta / PUNYCODE_DAMP : delta >> 1 + # delta >> 1 is a faster way of doing delta / 2 + delta += delta / numpoints + difference = PUNYCODE_BASE - PUNYCODE_TMIN + + k = 0 + while delta > (difference * PUNYCODE_TMAX) / 2 + delta /= difference + k += PUNYCODE_BASE + end + + k + (difference + 1) * delta / (delta + PUNYCODE_SKEW) + end + private_class_method :punycode_adapt + end + # :startdoc: +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/template.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/template.rb new file mode 100644 index 0000000000..2696695368 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/template.rb @@ -0,0 +1,1045 @@ +# frozen_string_literal: true + +# encoding:utf-8 +#-- +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +require "addressable/version" +require "addressable/uri" + +module Addressable + ## + # This is an implementation of a URI template based on + # RFC 6570 (http://tools.ietf.org/html/rfc6570). + class Template + # Constants used throughout the template code. + anything = + Addressable::URI::CharacterClasses::RESERVED + + Addressable::URI::CharacterClasses::UNRESERVED + + + variable_char_class = + Addressable::URI::CharacterClasses::ALPHA + + Addressable::URI::CharacterClasses::DIGIT + '_' + + var_char = + "(?:(?:[#{variable_char_class}]|%[a-fA-F0-9][a-fA-F0-9])+)" + RESERVED = + "(?:[#{anything}]|%[a-fA-F0-9][a-fA-F0-9])" + UNRESERVED = + "(?:[#{ + Addressable::URI::CharacterClasses::UNRESERVED + }]|%[a-fA-F0-9][a-fA-F0-9])" + variable = + "(?:#{var_char}(?:\\.?#{var_char})*)" + varspec = + "(?:(#{variable})(\\*|:\\d+)?)" + VARNAME = + /^#{variable}$/ + VARSPEC = + /^#{varspec}$/ + VARIABLE_LIST = + /^#{varspec}(?:,#{varspec})*$/ + operator = + "+#./;?&=,!@|" + EXPRESSION = + /\{([#{operator}])?(#{varspec}(?:,#{varspec})*)\}/ + + + LEADERS = { + '?' => '?', + '/' => '/', + '#' => '#', + '.' => '.', + ';' => ';', + '&' => '&' + } + JOINERS = { + '?' => '&', + '.' => '.', + ';' => ';', + '&' => '&', + '/' => '/' + } + + ## + # Raised if an invalid template value is supplied. + class InvalidTemplateValueError < StandardError + end + + ## + # Raised if an invalid template operator is used in a pattern. + class InvalidTemplateOperatorError < StandardError + end + + ## + # Raised if an invalid template operator is used in a pattern. + class TemplateOperatorAbortedError < StandardError + end + + ## + # This class represents the data that is extracted when a Template + # is matched against a URI. + class MatchData + ## + # Creates a new MatchData object. + # MatchData objects should never be instantiated directly. + # + # @param [Addressable::URI] uri + # The URI that the template was matched against. + def initialize(uri, template, mapping) + @uri = uri.dup.freeze + @template = template + @mapping = mapping.dup.freeze + end + + ## + # @return [Addressable::URI] + # The URI that the Template was matched against. + attr_reader :uri + + ## + # @return [Addressable::Template] + # The Template used for the match. + attr_reader :template + + ## + # @return [Hash] + # The mapping that resulted from the match. + # Note that this mapping does not include keys or values for + # variables that appear in the Template, but are not present + # in the URI. + attr_reader :mapping + + ## + # @return [Array] + # The list of variables that were present in the Template. + # Note that this list will include variables which do not appear + # in the mapping because they were not present in URI. + def variables + self.template.variables + end + alias_method :keys, :variables + alias_method :names, :variables + + ## + # @return [Array] + # The list of values that were captured by the Template. + # Note that this list will include nils for any variables which + # were in the Template, but did not appear in the URI. + def values + @values ||= self.variables.inject([]) do |accu, key| + accu << self.mapping[key] + accu + end + end + alias_method :captures, :values + + ## + # Accesses captured values by name or by index. + # + # @param [String, Symbol, Fixnum] key + # Capture index or name. Note that when accessing by with index + # of 0, the full URI will be returned. The intention is to mimic + # the ::MatchData#[] behavior. + # + # @param [#to_int, nil] len + # If provided, an array of values will be returend with the given + # parameter used as length. + # + # @return [Array, String, nil] + # The captured value corresponding to the index or name. If the + # value was not provided or the key is unknown, nil will be + # returned. + # + # If the second parameter is provided, an array of that length will + # be returned instead. + def [](key, len = nil) + if len + to_a[key, len] + elsif String === key or Symbol === key + mapping[key.to_s] + else + to_a[key] + end + end + + ## + # @return [Array] + # Array with the matched URI as first element followed by the captured + # values. + def to_a + [to_s, *values] + end + + ## + # @return [String] + # The matched URI as String. + def to_s + uri.to_s + end + alias_method :string, :to_s + + # Returns multiple captured values at once. + # + # @param [String, Symbol, Fixnum] *indexes + # Indices of the captures to be returned + # + # @return [Array] + # Values corresponding to given indices. + # + # @see Addressable::Template::MatchData#[] + def values_at(*indexes) + indexes.map { |i| self[i] } + end + + ## + # Returns a String representation of the MatchData's state. + # + # @return [String] The MatchData's state, as a String. + def inspect + sprintf("#<%s:%#0x RESULT:%s>", + self.class.to_s, self.object_id, self.mapping.inspect) + end + + ## + # Dummy method for code expecting a ::MatchData instance + # + # @return [String] An empty string. + def pre_match + "" + end + alias_method :post_match, :pre_match + end + + ## + # Creates a new Addressable::Template object. + # + # @param [#to_str] pattern The URI Template pattern. + # + # @return [Addressable::Template] The initialized Template object. + def initialize(pattern) + if !pattern.respond_to?(:to_str) + raise TypeError, "Can't convert #{pattern.class} into String." + end + @pattern = pattern.to_str.dup.freeze + end + + ## + # Freeze URI, initializing instance variables. + # + # @return [Addressable::URI] The frozen URI object. + def freeze + self.variables + self.variable_defaults + self.named_captures + super + end + + ## + # @return [String] The Template object's pattern. + attr_reader :pattern + + ## + # Returns a String representation of the Template object's state. + # + # @return [String] The Template object's state, as a String. + def inspect + sprintf("#<%s:%#0x PATTERN:%s>", + self.class.to_s, self.object_id, self.pattern) + end + + ## + # Returns true if the Template objects are equal. This method + # does NOT normalize either Template before doing the comparison. + # + # @param [Object] template The Template to compare. + # + # @return [TrueClass, FalseClass] + # true if the Templates are equivalent, false + # otherwise. + def ==(template) + return false unless template.kind_of?(Template) + return self.pattern == template.pattern + end + + ## + # Addressable::Template makes no distinction between `==` and `eql?`. + # + # @see #== + alias_method :eql?, :== + + ## + # Extracts a mapping from the URI using a URI Template pattern. + # + # @param [Addressable::URI, #to_str] uri + # The URI to extract from. + # + # @param [#restore, #match] processor + # A template processor object may optionally be supplied. + # + # The object should respond to either the restore or + # match messages or both. The restore method should + # take two parameters: `[String] name` and `[String] value`. + # The restore method should reverse any transformations that + # have been performed on the value to ensure a valid URI. + # The match method should take a single + # parameter: `[String] name`. The match method should return + # a String containing a regular expression capture group for + # matching on that particular variable. The default value is `".*?"`. + # The match method has no effect on multivariate operator + # expansions. + # + # @return [Hash, NilClass] + # The Hash mapping that was extracted from the URI, or + # nil if the URI didn't match the template. + # + # @example + # class ExampleProcessor + # def self.restore(name, value) + # return value.gsub(/\+/, " ") if name == "query" + # return value + # end + # + # def self.match(name) + # return ".*?" if name == "first" + # return ".*" + # end + # end + # + # uri = Addressable::URI.parse( + # "http://example.com/search/an+example+search+query/" + # ) + # Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).extract(uri, ExampleProcessor) + # #=> {"query" => "an example search query"} + # + # uri = Addressable::URI.parse("http://example.com/a/b/c/") + # Addressable::Template.new( + # "http://example.com/{first}/{second}/" + # ).extract(uri, ExampleProcessor) + # #=> {"first" => "a", "second" => "b/c"} + # + # uri = Addressable::URI.parse("http://example.com/a/b/c/") + # Addressable::Template.new( + # "http://example.com/{first}/{-list|/|second}/" + # ).extract(uri) + # #=> {"first" => "a", "second" => ["b", "c"]} + def extract(uri, processor=nil) + match_data = self.match(uri, processor) + return (match_data ? match_data.mapping : nil) + end + + ## + # Extracts match data from the URI using a URI Template pattern. + # + # @param [Addressable::URI, #to_str] uri + # The URI to extract from. + # + # @param [#restore, #match] processor + # A template processor object may optionally be supplied. + # + # The object should respond to either the restore or + # match messages or both. The restore method should + # take two parameters: `[String] name` and `[String] value`. + # The restore method should reverse any transformations that + # have been performed on the value to ensure a valid URI. + # The match method should take a single + # parameter: `[String] name`. The match method should return + # a String containing a regular expression capture group for + # matching on that particular variable. The default value is `".*?"`. + # The match method has no effect on multivariate operator + # expansions. + # + # @return [Hash, NilClass] + # The Hash mapping that was extracted from the URI, or + # nil if the URI didn't match the template. + # + # @example + # class ExampleProcessor + # def self.restore(name, value) + # return value.gsub(/\+/, " ") if name == "query" + # return value + # end + # + # def self.match(name) + # return ".*?" if name == "first" + # return ".*" + # end + # end + # + # uri = Addressable::URI.parse( + # "http://example.com/search/an+example+search+query/" + # ) + # match = Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).match(uri, ExampleProcessor) + # match.variables + # #=> ["query"] + # match.captures + # #=> ["an example search query"] + # + # uri = Addressable::URI.parse("http://example.com/a/b/c/") + # match = Addressable::Template.new( + # "http://example.com/{first}/{+second}/" + # ).match(uri, ExampleProcessor) + # match.variables + # #=> ["first", "second"] + # match.captures + # #=> ["a", "b/c"] + # + # uri = Addressable::URI.parse("http://example.com/a/b/c/") + # match = Addressable::Template.new( + # "http://example.com/{first}{/second*}/" + # ).match(uri) + # match.variables + # #=> ["first", "second"] + # match.captures + # #=> ["a", ["b", "c"]] + def match(uri, processor=nil) + uri = Addressable::URI.parse(uri) + mapping = {} + + # First, we need to process the pattern, and extract the values. + expansions, expansion_regexp = + parse_template_pattern(pattern, processor) + + return nil unless uri.to_str.match(expansion_regexp) + unparsed_values = uri.to_str.scan(expansion_regexp).flatten + + if uri.to_str == pattern + return Addressable::Template::MatchData.new(uri, self, mapping) + elsif expansions.size > 0 + index = 0 + expansions.each do |expansion| + _, operator, varlist = *expansion.match(EXPRESSION) + varlist.split(',').each do |varspec| + _, name, modifier = *varspec.match(VARSPEC) + mapping[name] ||= nil + case operator + when nil, '+', '#', '/', '.' + unparsed_value = unparsed_values[index] + name = varspec[VARSPEC, 1] + value = unparsed_value + value = value.split(JOINERS[operator]) if value && modifier == '*' + when ';', '?', '&' + if modifier == '*' + if unparsed_values[index] + value = unparsed_values[index].split(JOINERS[operator]) + value = value.inject({}) do |acc, v| + key, val = v.split('=') + val = "" if val.nil? + acc[key] = val + acc + end + end + else + if (unparsed_values[index]) + name, value = unparsed_values[index].split('=') + value = "" if value.nil? + end + end + end + if processor != nil && processor.respond_to?(:restore) + value = processor.restore(name, value) + end + if processor == nil + if value.is_a?(Hash) + value = value.inject({}){|acc, (k, v)| + acc[Addressable::URI.unencode_component(k)] = + Addressable::URI.unencode_component(v) + acc + } + elsif value.is_a?(Array) + value = value.map{|v| Addressable::URI.unencode_component(v) } + else + value = Addressable::URI.unencode_component(value) + end + end + if !mapping.has_key?(name) || mapping[name].nil? + # Doesn't exist, set to value (even if value is nil) + mapping[name] = value + end + index = index + 1 + end + end + return Addressable::Template::MatchData.new(uri, self, mapping) + else + return nil + end + end + + ## + # Expands a URI template into another URI template. + # + # @param [Hash] mapping The mapping that corresponds to the pattern. + # @param [#validate, #transform] processor + # An optional processor object may be supplied. + # @param [Boolean] normalize_values + # Optional flag to enable/disable unicode normalization. Default: true + # + # The object should respond to either the validate or + # transform messages or both. Both the validate and + # transform methods should take two parameters: name and + # value. The validate method should return true + # or false; true if the value of the variable is valid, + # false otherwise. An InvalidTemplateValueError + # exception will be raised if the value is invalid. The transform + # method should return the transformed variable value as a String. + # If a transform method is used, the value will not be percent + # encoded automatically. Unicode normalization will be performed both + # before and after sending the value to the transform method. + # + # @return [Addressable::Template] The partially expanded URI template. + # + # @example + # Addressable::Template.new( + # "http://example.com/{one}/{two}/" + # ).partial_expand({"one" => "1"}).pattern + # #=> "http://example.com/1/{two}/" + # + # Addressable::Template.new( + # "http://example.com/{?one,two}/" + # ).partial_expand({"one" => "1"}).pattern + # #=> "http://example.com/?one=1{&two}/" + # + # Addressable::Template.new( + # "http://example.com/{?one,two,three}/" + # ).partial_expand({"one" => "1", "three" => 3}).pattern + # #=> "http://example.com/?one=1{&two}&three=3" + def partial_expand(mapping, processor=nil, normalize_values=true) + result = self.pattern.dup + mapping = normalize_keys(mapping) + result.gsub!( EXPRESSION ) do |capture| + transform_partial_capture(mapping, capture, processor, normalize_values) + end + return Addressable::Template.new(result) + end + + ## + # Expands a URI template into a full URI. + # + # @param [Hash] mapping The mapping that corresponds to the pattern. + # @param [#validate, #transform] processor + # An optional processor object may be supplied. + # @param [Boolean] normalize_values + # Optional flag to enable/disable unicode normalization. Default: true + # + # The object should respond to either the validate or + # transform messages or both. Both the validate and + # transform methods should take two parameters: name and + # value. The validate method should return true + # or false; true if the value of the variable is valid, + # false otherwise. An InvalidTemplateValueError + # exception will be raised if the value is invalid. The transform + # method should return the transformed variable value as a String. + # If a transform method is used, the value will not be percent + # encoded automatically. Unicode normalization will be performed both + # before and after sending the value to the transform method. + # + # @return [Addressable::URI] The expanded URI template. + # + # @example + # class ExampleProcessor + # def self.validate(name, value) + # return !!(value =~ /^[\w ]+$/) if name == "query" + # return true + # end + # + # def self.transform(name, value) + # return value.gsub(/ /, "+") if name == "query" + # return value + # end + # end + # + # Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).expand( + # {"query" => "an example search query"}, + # ExampleProcessor + # ).to_str + # #=> "http://example.com/search/an+example+search+query/" + # + # Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).expand( + # {"query" => "an example search query"} + # ).to_str + # #=> "http://example.com/search/an%20example%20search%20query/" + # + # Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).expand( + # {"query" => "bogus!"}, + # ExampleProcessor + # ).to_str + # #=> Addressable::Template::InvalidTemplateValueError + def expand(mapping, processor=nil, normalize_values=true) + result = self.pattern.dup + mapping = normalize_keys(mapping) + result.gsub!( EXPRESSION ) do |capture| + transform_capture(mapping, capture, processor, normalize_values) + end + return Addressable::URI.parse(result) + end + + ## + # Returns an Array of variables used within the template pattern. + # The variables are listed in the Array in the order they appear within + # the pattern. Multiple occurrences of a variable within a pattern are + # not represented in this Array. + # + # @return [Array] The variables present in the template's pattern. + def variables + @variables ||= ordered_variable_defaults.map { |var, val| var }.uniq + end + alias_method :keys, :variables + alias_method :names, :variables + + ## + # Returns a mapping of variables to their default values specified + # in the template. Variables without defaults are not returned. + # + # @return [Hash] Mapping of template variables to their defaults + def variable_defaults + @variable_defaults ||= + Hash[*ordered_variable_defaults.reject { |k, v| v.nil? }.flatten] + end + + ## + # Coerces a template into a `Regexp` object. This regular expression will + # behave very similarly to the actual template, and should match the same + # URI values, but it cannot fully handle, for example, values that would + # extract to an `Array`. + # + # @return [Regexp] A regular expression which should match the template. + def to_regexp + _, source = parse_template_pattern(pattern) + Regexp.new(source) + end + + ## + # Returns the source of the coerced `Regexp`. + # + # @return [String] The source of the `Regexp` given by {#to_regexp}. + # + # @api private + def source + self.to_regexp.source + end + + ## + # Returns the named captures of the coerced `Regexp`. + # + # @return [Hash] The named captures of the `Regexp` given by {#to_regexp}. + # + # @api private + def named_captures + self.to_regexp.named_captures + end + + ## + # Generates a route result for a given set of parameters. + # Should only be used by rack-mount. + # + # @param params [Hash] The set of parameters used to expand the template. + # @param recall [Hash] Default parameters used to expand the template. + # @param options [Hash] Either a `:processor` or a `:parameterize` block. + # + # @api private + def generate(params={}, recall={}, options={}) + merged = recall.merge(params) + if options[:processor] + processor = options[:processor] + elsif options[:parameterize] + # TODO: This is sending me into fits trying to shoe-horn this into + # the existing API. I think I've got this backwards and processors + # should be a set of 4 optional blocks named :validate, :transform, + # :match, and :restore. Having to use a singleton here is a huge + # code smell. + processor = Object.new + class <validate or + # transform messages or both. Both the validate and + # transform methods should take two parameters: name and + # value. The validate method should return true + # or false; true if the value of the variable is valid, + # false otherwise. An InvalidTemplateValueError exception + # will be raised if the value is invalid. The transform method + # should return the transformed variable value as a String. If a + # transform method is used, the value will not be percent encoded + # automatically. Unicode normalization will be performed both before and + # after sending the value to the transform method. + # + # @return [String] The expanded expression + def transform_partial_capture(mapping, capture, processor = nil, + normalize_values = true) + _, operator, varlist = *capture.match(EXPRESSION) + + vars = varlist.split(",") + + if operator == "?" + # partial expansion of form style query variables sometimes requires a + # slight reordering of the variables to produce a valid url. + first_to_expand = vars.find { |varspec| + _, name, _ = *varspec.match(VARSPEC) + mapping.key?(name) && !mapping[name].nil? + } + + vars = [first_to_expand] + vars.reject {|varspec| varspec == first_to_expand} if first_to_expand + end + + vars. + inject("".dup) do |acc, varspec| + _, name, _ = *varspec.match(VARSPEC) + next_val = if mapping.key? name + transform_capture(mapping, "{#{operator}#{varspec}}", + processor, normalize_values) + else + "{#{operator}#{varspec}}" + end + # If we've already expanded at least one '?' operator with non-empty + # value, change to '&' + operator = "&" if (operator == "?") && (next_val != "") + acc << next_val + end + end + + ## + # Transforms a mapped value so that values can be substituted into the + # template. + # + # @param [Hash] mapping The mapping to replace captures + # @param [String] capture + # The expression to replace + # @param [#validate, #transform] processor + # An optional processor object may be supplied. + # @param [Boolean] normalize_values + # Optional flag to enable/disable unicode normalization. Default: true + # + # + # The object should respond to either the validate or + # transform messages or both. Both the validate and + # transform methods should take two parameters: name and + # value. The validate method should return true + # or false; true if the value of the variable is valid, + # false otherwise. An InvalidTemplateValueError exception + # will be raised if the value is invalid. The transform method + # should return the transformed variable value as a String. If a + # transform method is used, the value will not be percent encoded + # automatically. Unicode normalization will be performed both before and + # after sending the value to the transform method. + # + # @return [String] The expanded expression + def transform_capture(mapping, capture, processor=nil, + normalize_values=true) + _, operator, varlist = *capture.match(EXPRESSION) + return_value = varlist.split(',').inject([]) do |acc, varspec| + _, name, modifier = *varspec.match(VARSPEC) + value = mapping[name] + unless value == nil || value == {} + allow_reserved = %w(+ #).include?(operator) + # Common primitives where the .to_s output is well-defined + if Numeric === value || Symbol === value || + value == true || value == false + value = value.to_s + end + length = modifier.gsub(':', '').to_i if modifier =~ /^:\d+/ + + unless (Hash === value) || + value.respond_to?(:to_ary) || value.respond_to?(:to_str) + raise TypeError, + "Can't convert #{value.class} into String or Array." + end + + value = normalize_value(value) if normalize_values + + if processor == nil || !processor.respond_to?(:transform) + # Handle percent escaping + if allow_reserved + encode_map = + Addressable::URI::CharacterClasses::RESERVED + + Addressable::URI::CharacterClasses::UNRESERVED + else + encode_map = Addressable::URI::CharacterClasses::UNRESERVED + end + if value.kind_of?(Array) + transformed_value = value.map do |val| + if length + Addressable::URI.encode_component(val[0...length], encode_map) + else + Addressable::URI.encode_component(val, encode_map) + end + end + unless modifier == "*" + transformed_value = transformed_value.join(',') + end + elsif value.kind_of?(Hash) + transformed_value = value.map do |key, val| + if modifier == "*" + "#{ + Addressable::URI.encode_component( key, encode_map) + }=#{ + Addressable::URI.encode_component( val, encode_map) + }" + else + "#{ + Addressable::URI.encode_component( key, encode_map) + },#{ + Addressable::URI.encode_component( val, encode_map) + }" + end + end + unless modifier == "*" + transformed_value = transformed_value.join(',') + end + else + if length + transformed_value = Addressable::URI.encode_component( + value[0...length], encode_map) + else + transformed_value = Addressable::URI.encode_component( + value, encode_map) + end + end + end + + # Process, if we've got a processor + if processor != nil + if processor.respond_to?(:validate) + if !processor.validate(name, value) + display_value = value.kind_of?(Array) ? value.inspect : value + raise InvalidTemplateValueError, + "#{name}=#{display_value} is an invalid template value." + end + end + if processor.respond_to?(:transform) + transformed_value = processor.transform(name, value) + if normalize_values + transformed_value = normalize_value(transformed_value) + end + end + end + acc << [name, transformed_value] + end + acc + end + return "" if return_value.empty? + join_values(operator, return_value) + end + + ## + # Takes a set of values, and joins them together based on the + # operator. + # + # @param [String, Nil] operator One of the operators from the set + # (?,&,+,#,;,/,.), or nil if there wasn't one. + # @param [Array] return_value + # The set of return values (as [variable_name, value] tuples) that will + # be joined together. + # + # @return [String] The transformed mapped value + def join_values(operator, return_value) + leader = LEADERS.fetch(operator, '') + joiner = JOINERS.fetch(operator, ',') + case operator + when '&', '?' + leader + return_value.map{|k,v| + if v.is_a?(Array) && v.first =~ /=/ + v.join(joiner) + elsif v.is_a?(Array) + v.map{|inner_value| "#{k}=#{inner_value}"}.join(joiner) + else + "#{k}=#{v}" + end + }.join(joiner) + when ';' + return_value.map{|k,v| + if v.is_a?(Array) && v.first =~ /=/ + ';' + v.join(";") + elsif v.is_a?(Array) + ';' + v.map{|inner_value| "#{k}=#{inner_value}"}.join(";") + else + v && v != '' ? ";#{k}=#{v}" : ";#{k}" + end + }.join + else + leader + return_value.map{|k,v| v}.join(joiner) + end + end + + ## + # Takes a set of values, and joins them together based on the + # operator. + # + # @param [Hash, Array, String] value + # Normalizes keys and values with IDNA#unicode_normalize_kc + # + # @return [Hash, Array, String] The normalized values + def normalize_value(value) + unless value.is_a?(Hash) + value = value.respond_to?(:to_ary) ? value.to_ary : value.to_str + end + + # Handle unicode normalization + if value.kind_of?(Array) + value.map! { |val| Addressable::IDNA.unicode_normalize_kc(val) } + elsif value.kind_of?(Hash) + value = value.inject({}) { |acc, (k, v)| + acc[Addressable::IDNA.unicode_normalize_kc(k)] = + Addressable::IDNA.unicode_normalize_kc(v) + acc + } + else + value = Addressable::IDNA.unicode_normalize_kc(value) + end + value + end + + ## + # Generates a hash with string keys + # + # @param [Hash] mapping A mapping hash to normalize + # + # @return [Hash] + # A hash with stringified keys + def normalize_keys(mapping) + return mapping.inject({}) do |accu, pair| + name, value = pair + if Symbol === name + name = name.to_s + elsif name.respond_to?(:to_str) + name = name.to_str + else + raise TypeError, + "Can't convert #{name.class} into String." + end + accu[name] = value + accu + end + end + + ## + # Generates the Regexp that parses a template pattern. + # + # @param [String] pattern The URI template pattern. + # @param [#match] processor The template processor to use. + # + # @return [Regexp] + # A regular expression which may be used to parse a template pattern. + def parse_template_pattern(pattern, processor=nil) + # Escape the pattern. The two gsubs restore the escaped curly braces + # back to their original form. Basically, escape everything that isn't + # within an expansion. + escaped_pattern = Regexp.escape( + pattern + ).gsub(/\\\{(.*?)\\\}/) do |escaped| + escaped.gsub(/\\(.)/, "\\1") + end + + expansions = [] + + # Create a regular expression that captures the values of the + # variables in the URI. + regexp_string = escaped_pattern.gsub( EXPRESSION ) do |expansion| + + expansions << expansion + _, operator, varlist = *expansion.match(EXPRESSION) + leader = Regexp.escape(LEADERS.fetch(operator, '')) + joiner = Regexp.escape(JOINERS.fetch(operator, ',')) + combined = varlist.split(',').map do |varspec| + _, name, modifier = *varspec.match(VARSPEC) + + result = processor && processor.respond_to?(:match) ? processor.match(name) : nil + if result + "(?<#{name}>#{ result })" + else + group = case operator + when '+' + "#{ RESERVED }*?" + when '#' + "#{ RESERVED }*?" + when '/' + "#{ UNRESERVED }*?" + when '.' + "#{ UNRESERVED.gsub('\.', '') }*?" + when ';' + "#{ UNRESERVED }*=?#{ UNRESERVED }*?" + when '?' + "#{ UNRESERVED }*=#{ UNRESERVED }*?" + when '&' + "#{ UNRESERVED }*=#{ UNRESERVED }*?" + else + "#{ UNRESERVED }*?" + end + if modifier == '*' + "(?<#{name}>#{group}(?:#{joiner}?#{group})*)?" + else + "(?<#{name}>#{group})?" + end + end + end.join("#{joiner}?") + "(?:|#{leader}#{combined})" + end + + # Ensure that the regular expression matches the whole URI. + regexp_string = "^#{regexp_string}$" + return expansions, Regexp.new(regexp_string) + end + + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/uri.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/uri.rb new file mode 100644 index 0000000000..71a806bf63 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/uri.rb @@ -0,0 +1,2529 @@ +# frozen_string_literal: true + +# encoding:utf-8 +#-- +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +require "addressable/version" +require "addressable/idna" +require "public_suffix" + +## +# Addressable is a library for processing links and URIs. +module Addressable + ## + # This is an implementation of a URI parser based on + # RFC 3986, + # RFC 3987. + class URI + ## + # Raised if something other than a uri is supplied. + class InvalidURIError < StandardError + end + + ## + # Container for the character classes specified in + # RFC 3986. + module CharacterClasses + ALPHA = "a-zA-Z" + DIGIT = "0-9" + GEN_DELIMS = "\\:\\/\\?\\#\\[\\]\\@" + SUB_DELIMS = "\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\=" + RESERVED = GEN_DELIMS + SUB_DELIMS + UNRESERVED = ALPHA + DIGIT + "\\-\\.\\_\\~" + PCHAR = UNRESERVED + SUB_DELIMS + "\\:\\@" + SCHEME = ALPHA + DIGIT + "\\-\\+\\." + HOST = UNRESERVED + SUB_DELIMS + "\\[\\:\\]" + AUTHORITY = PCHAR + PATH = PCHAR + "\\/" + QUERY = PCHAR + "\\/\\?" + FRAGMENT = PCHAR + "\\/\\?" + end + + SLASH = '/' + EMPTY_STR = '' + + URIREGEX = /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/ + + PORT_MAPPING = { + "http" => 80, + "https" => 443, + "ftp" => 21, + "tftp" => 69, + "sftp" => 22, + "ssh" => 22, + "svn+ssh" => 22, + "telnet" => 23, + "nntp" => 119, + "gopher" => 70, + "wais" => 210, + "ldap" => 389, + "prospero" => 1525 + } + + ## + # Returns a URI object based on the parsed string. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI string to parse. + # No parsing is performed if the object is already an + # Addressable::URI. + # + # @return [Addressable::URI] The parsed URI. + def self.parse(uri) + # If we were given nil, return nil. + return nil unless uri + # If a URI object is passed, just return itself. + return uri.dup if uri.kind_of?(self) + + # If a URI object of the Ruby standard library variety is passed, + # convert it to a string, then parse the string. + # We do the check this way because we don't want to accidentally + # cause a missing constant exception to be thrown. + if uri.class.name =~ /^URI\b/ + uri = uri.to_s + end + + # Otherwise, convert to a String + begin + uri = uri.to_str + rescue TypeError, NoMethodError + raise TypeError, "Can't convert #{uri.class} into String." + end if not uri.is_a? String + + # This Regexp supplied as an example in RFC 3986, and it works great. + scan = uri.scan(URIREGEX) + fragments = scan[0] + scheme = fragments[1] + authority = fragments[3] + path = fragments[4] + query = fragments[6] + fragment = fragments[8] + user = nil + password = nil + host = nil + port = nil + if authority != nil + # The Regexp above doesn't split apart the authority. + userinfo = authority[/^([^\[\]]*)@/, 1] + if userinfo != nil + user = userinfo.strip[/^([^:]*):?/, 1] + password = userinfo.strip[/:(.*)$/, 1] + end + host = authority.sub( + /^([^\[\]]*)@/, EMPTY_STR + ).sub( + /:([^:@\[\]]*?)$/, EMPTY_STR + ) + port = authority[/:([^:@\[\]]*?)$/, 1] + end + if port == EMPTY_STR + port = nil + end + + return new( + :scheme => scheme, + :user => user, + :password => password, + :host => host, + :port => port, + :path => path, + :query => query, + :fragment => fragment + ) + end + + ## + # Converts an input to a URI. The input does not have to be a valid + # URI — the method will use heuristics to guess what URI was intended. + # This is not standards-compliant, merely user-friendly. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI string to parse. + # No parsing is performed if the object is already an + # Addressable::URI. + # @param [Hash] hints + # A Hash of hints to the heuristic parser. + # Defaults to {:scheme => "http"}. + # + # @return [Addressable::URI] The parsed URI. + def self.heuristic_parse(uri, hints={}) + # If we were given nil, return nil. + return nil unless uri + # If a URI object is passed, just return itself. + return uri.dup if uri.kind_of?(self) + + # If a URI object of the Ruby standard library variety is passed, + # convert it to a string, then parse the string. + # We do the check this way because we don't want to accidentally + # cause a missing constant exception to be thrown. + if uri.class.name =~ /^URI\b/ + uri = uri.to_s + end + + if !uri.respond_to?(:to_str) + raise TypeError, "Can't convert #{uri.class} into String." + end + # Otherwise, convert to a String + uri = uri.to_str.dup.strip + hints = { + :scheme => "http" + }.merge(hints) + case uri + when /^http:\//i + uri.sub!(/^http:\/+/i, "http://") + when /^https:\//i + uri.sub!(/^https:\/+/i, "https://") + when /^feed:\/+http:\//i + uri.sub!(/^feed:\/+http:\/+/i, "feed:http://") + when /^feed:\//i + uri.sub!(/^feed:\/+/i, "feed://") + when %r[^file:/{4}]i + uri.sub!(%r[^file:/+]i, "file:////") + when %r[^file://localhost/]i + uri.sub!(%r[^file://localhost/+]i, "file:///") + when %r[^file:/+]i + uri.sub!(%r[^file:/+]i, "file:///") + when /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ + uri.sub!(/^/, hints[:scheme] + "://") + when /\A\d+\..*:\d+\z/ + uri = "#{hints[:scheme]}://#{uri}" + end + match = uri.match(URIREGEX) + fragments = match.captures + authority = fragments[3] + if authority && authority.length > 0 + new_authority = authority.tr("\\", "/").gsub(" ", "%20") + # NOTE: We want offset 4, not 3! + offset = match.offset(4) + uri = uri.dup + uri[offset[0]...offset[1]] = new_authority + end + parsed = self.parse(uri) + if parsed.scheme =~ /^[^\/?#\.]+\.[^\/?#]+$/ + parsed = self.parse(hints[:scheme] + "://" + uri) + end + if parsed.path.include?(".") + if parsed.path[/\b@\b/] + parsed.scheme = "mailto" unless parsed.scheme + elsif new_host = parsed.path[/^([^\/]+\.[^\/]*)/, 1] + parsed.defer_validation do + new_path = parsed.path.sub( + Regexp.new("^" + Regexp.escape(new_host)), EMPTY_STR) + parsed.host = new_host + parsed.path = new_path + parsed.scheme = hints[:scheme] unless parsed.scheme + end + end + end + return parsed + end + + ## + # Converts a path to a file scheme URI. If the path supplied is + # relative, it will be returned as a relative URI. If the path supplied + # is actually a non-file URI, it will parse the URI as if it had been + # parsed with Addressable::URI.parse. Handles all of the + # various Microsoft-specific formats for specifying paths. + # + # @param [String, Addressable::URI, #to_str] path + # Typically a String path to a file or directory, but + # will return a sensible return value if an absolute URI is supplied + # instead. + # + # @return [Addressable::URI] + # The parsed file scheme URI or the original URI if some other URI + # scheme was provided. + # + # @example + # base = Addressable::URI.convert_path("/absolute/path/") + # uri = Addressable::URI.convert_path("relative/path") + # (base + uri).to_s + # #=> "file:///absolute/path/relative/path" + # + # Addressable::URI.convert_path( + # "c:\\windows\\My Documents 100%20\\foo.txt" + # ).to_s + # #=> "file:///c:/windows/My%20Documents%20100%20/foo.txt" + # + # Addressable::URI.convert_path("http://example.com/").to_s + # #=> "http://example.com/" + def self.convert_path(path) + # If we were given nil, return nil. + return nil unless path + # If a URI object is passed, just return itself. + return path if path.kind_of?(self) + if !path.respond_to?(:to_str) + raise TypeError, "Can't convert #{path.class} into String." + end + # Otherwise, convert to a String + path = path.to_str.strip + + path.sub!(/^file:\/?\/?/, EMPTY_STR) if path =~ /^file:\/?\/?/ + path = SLASH + path if path =~ /^([a-zA-Z])[\|:]/ + uri = self.parse(path) + + if uri.scheme == nil + # Adjust windows-style uris + uri.path.sub!(/^\/?([a-zA-Z])[\|:][\\\/]/) do + "/#{$1.downcase}:/" + end + uri.path.tr!("\\", SLASH) + if File.exist?(uri.path) && + File.stat(uri.path).directory? + uri.path.chomp!(SLASH) + uri.path = uri.path + '/' + end + + # If the path is absolute, set the scheme and host. + if uri.path.start_with?(SLASH) + uri.scheme = "file" + uri.host = EMPTY_STR + end + uri.normalize! + end + + return uri + end + + ## + # Joins several URIs together. + # + # @param [String, Addressable::URI, #to_str] *uris + # The URIs to join. + # + # @return [Addressable::URI] The joined URI. + # + # @example + # base = "http://example.com/" + # uri = Addressable::URI.parse("relative/path") + # Addressable::URI.join(base, uri) + # #=> # + def self.join(*uris) + uri_objects = uris.collect do |uri| + if !uri.respond_to?(:to_str) + raise TypeError, "Can't convert #{uri.class} into String." + end + uri.kind_of?(self) ? uri : self.parse(uri.to_str) + end + result = uri_objects.shift.dup + for uri in uri_objects + result.join!(uri) + end + return result + end + + ## + # Tables used to optimize encoding operations in `self.encode_component` + # and `self.normalize_component` + SEQUENCE_ENCODING_TABLE = Hash.new do |hash, sequence| + hash[sequence] = sequence.unpack("C*").map do |c| + format("%02x", c) + end.join + end + + SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE = Hash.new do |hash, sequence| + hash[sequence] = sequence.unpack("C*").map do |c| + format("%%%02X", c) + end.join + end + + ## + # Percent encodes a URI component. + # + # @param [String, #to_str] component The URI component to encode. + # + # @param [String, Regexp] character_class + # The characters which are not percent encoded. If a String + # is passed, the String must be formatted as a regular + # expression character class. (Do not include the surrounding square + # brackets.) For example, "b-zB-Z0-9" would cause + # everything but the letters 'b' through 'z' and the numbers '0' through + # '9' to be percent encoded. If a Regexp is passed, the + # value /[^b-zB-Z0-9]/ would have the same effect. A set of + # useful String values may be found in the + # Addressable::URI::CharacterClasses module. The default + # value is the reserved plus unreserved character classes specified in + # RFC 3986. + # + # @param [Regexp] upcase_encoded + # A string of characters that may already be percent encoded, and whose + # encodings should be upcased. This allows normalization of percent + # encodings for characters not included in the + # character_class. + # + # @return [String] The encoded component. + # + # @example + # Addressable::URI.encode_component("simple/example", "b-zB-Z0-9") + # => "simple%2Fex%61mple" + # Addressable::URI.encode_component("simple/example", /[^b-zB-Z0-9]/) + # => "simple%2Fex%61mple" + # Addressable::URI.encode_component( + # "simple/example", Addressable::URI::CharacterClasses::UNRESERVED + # ) + # => "simple%2Fexample" + def self.encode_component(component, character_class= + CharacterClasses::RESERVED + CharacterClasses::UNRESERVED, + upcase_encoded='') + return nil if component.nil? + + begin + if component.kind_of?(Symbol) || + component.kind_of?(Numeric) || + component.kind_of?(TrueClass) || + component.kind_of?(FalseClass) + component = component.to_s + else + component = component.to_str + end + rescue TypeError, NoMethodError + raise TypeError, "Can't convert #{component.class} into String." + end if !component.is_a? String + + if ![String, Regexp].include?(character_class.class) + raise TypeError, + "Expected String or Regexp, got #{character_class.inspect}" + end + if character_class.kind_of?(String) + character_class = /[^#{character_class}]/ + end + # We can't perform regexps on invalid UTF sequences, but + # here we need to, so switch to ASCII. + component = component.dup + component.force_encoding(Encoding::ASCII_8BIT) + # Avoiding gsub! because there are edge cases with frozen strings + component = component.gsub(character_class) do |sequence| + SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE[sequence] + end + if upcase_encoded.length > 0 + upcase_encoded_chars = upcase_encoded.chars.map do |char| + SEQUENCE_ENCODING_TABLE[char] + end + component = component.gsub(/%(#{upcase_encoded_chars.join('|')})/, + &:upcase) + end + return component + end + + class << self + alias_method :encode_component, :encode_component + end + + ## + # Unencodes any percent encoded characters within a URI component. + # This method may be used for unencoding either components or full URIs, + # however, it is recommended to use the unencode_component + # alias when unencoding components. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI or component to unencode. + # + # @param [Class] return_type + # The type of object to return. + # This value may only be set to String or + # Addressable::URI. All other values are invalid. Defaults + # to String. + # + # @param [String] leave_encoded + # A string of characters to leave encoded. If a percent encoded character + # in this list is encountered then it will remain percent encoded. + # + # @return [String, Addressable::URI] + # The unencoded component or URI. + # The return type is determined by the return_type + # parameter. + def self.unencode(uri, return_type=String, leave_encoded='') + return nil if uri.nil? + + begin + uri = uri.to_str + rescue NoMethodError, TypeError + raise TypeError, "Can't convert #{uri.class} into String." + end if !uri.is_a? String + if ![String, ::Addressable::URI].include?(return_type) + raise TypeError, + "Expected Class (String or Addressable::URI), " + + "got #{return_type.inspect}" + end + uri = uri.dup + # Seriously, only use UTF-8. I'm really not kidding! + uri.force_encoding("utf-8") + leave_encoded = leave_encoded.dup.force_encoding("utf-8") + result = uri.gsub(/%[0-9a-f]{2}/iu) do |sequence| + c = sequence[1..3].to_i(16).chr + c.force_encoding("utf-8") + leave_encoded.include?(c) ? sequence : c + end + result.force_encoding("utf-8") + if return_type == String + return result + elsif return_type == ::Addressable::URI + return ::Addressable::URI.parse(result) + end + end + + class << self + alias_method :unescape, :unencode + alias_method :unencode_component, :unencode + alias_method :unescape_component, :unencode + end + + + ## + # Normalizes the encoding of a URI component. + # + # @param [String, #to_str] component The URI component to encode. + # + # @param [String, Regexp] character_class + # The characters which are not percent encoded. If a String + # is passed, the String must be formatted as a regular + # expression character class. (Do not include the surrounding square + # brackets.) For example, "b-zB-Z0-9" would cause + # everything but the letters 'b' through 'z' and the numbers '0' + # through '9' to be percent encoded. If a Regexp is passed, + # the value /[^b-zB-Z0-9]/ would have the same effect. A + # set of useful String values may be found in the + # Addressable::URI::CharacterClasses module. The default + # value is the reserved plus unreserved character classes specified in + # RFC 3986. + # + # @param [String] leave_encoded + # When character_class is a String then + # leave_encoded is a string of characters that should remain + # percent encoded while normalizing the component; if they appear percent + # encoded in the original component, then they will be upcased ("%2f" + # normalized to "%2F") but otherwise left alone. + # + # @return [String] The normalized component. + # + # @example + # Addressable::URI.normalize_component("simpl%65/%65xampl%65", "b-zB-Z") + # => "simple%2Fex%61mple" + # Addressable::URI.normalize_component( + # "simpl%65/%65xampl%65", /[^b-zB-Z]/ + # ) + # => "simple%2Fex%61mple" + # Addressable::URI.normalize_component( + # "simpl%65/%65xampl%65", + # Addressable::URI::CharacterClasses::UNRESERVED + # ) + # => "simple%2Fexample" + # Addressable::URI.normalize_component( + # "one%20two%2fthree%26four", + # "0-9a-zA-Z &/", + # "/" + # ) + # => "one two%2Fthree&four" + def self.normalize_component(component, character_class= + CharacterClasses::RESERVED + CharacterClasses::UNRESERVED, + leave_encoded='') + return nil if component.nil? + + begin + component = component.to_str + rescue NoMethodError, TypeError + raise TypeError, "Can't convert #{component.class} into String." + end if !component.is_a? String + + if ![String, Regexp].include?(character_class.class) + raise TypeError, + "Expected String or Regexp, got #{character_class.inspect}" + end + if character_class.kind_of?(String) + leave_re = if leave_encoded.length > 0 + character_class = "#{character_class}%" unless character_class.include?('%') + + "|%(?!#{leave_encoded.chars.map do |char| + seq = SEQUENCE_ENCODING_TABLE[char] + [seq.upcase, seq.downcase] + end.flatten.join('|')})" + end + + character_class = /[^#{character_class}]#{leave_re}/ + end + # We can't perform regexps on invalid UTF sequences, but + # here we need to, so switch to ASCII. + component = component.dup + component.force_encoding(Encoding::ASCII_8BIT) + unencoded = self.unencode_component(component, String, leave_encoded) + begin + encoded = self.encode_component( + Addressable::IDNA.unicode_normalize_kc(unencoded), + character_class, + leave_encoded + ) + rescue ArgumentError + encoded = self.encode_component(unencoded) + end + encoded.force_encoding(Encoding::UTF_8) + return encoded + end + + ## + # Percent encodes any special characters in the URI. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI to encode. + # + # @param [Class] return_type + # The type of object to return. + # This value may only be set to String or + # Addressable::URI. All other values are invalid. Defaults + # to String. + # + # @return [String, Addressable::URI] + # The encoded URI. + # The return type is determined by the return_type + # parameter. + def self.encode(uri, return_type=String) + return nil if uri.nil? + + begin + uri = uri.to_str + rescue NoMethodError, TypeError + raise TypeError, "Can't convert #{uri.class} into String." + end if !uri.is_a? String + + if ![String, ::Addressable::URI].include?(return_type) + raise TypeError, + "Expected Class (String or Addressable::URI), " + + "got #{return_type.inspect}" + end + uri_object = uri.kind_of?(self) ? uri : self.parse(uri) + encoded_uri = Addressable::URI.new( + :scheme => self.encode_component(uri_object.scheme, + Addressable::URI::CharacterClasses::SCHEME), + :authority => self.encode_component(uri_object.authority, + Addressable::URI::CharacterClasses::AUTHORITY), + :path => self.encode_component(uri_object.path, + Addressable::URI::CharacterClasses::PATH), + :query => self.encode_component(uri_object.query, + Addressable::URI::CharacterClasses::QUERY), + :fragment => self.encode_component(uri_object.fragment, + Addressable::URI::CharacterClasses::FRAGMENT) + ) + if return_type == String + return encoded_uri.to_s + elsif return_type == ::Addressable::URI + return encoded_uri + end + end + + class << self + alias_method :escape, :encode + end + + ## + # Normalizes the encoding of a URI. Characters within a hostname are + # not percent encoded to allow for internationalized domain names. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI to encode. + # + # @param [Class] return_type + # The type of object to return. + # This value may only be set to String or + # Addressable::URI. All other values are invalid. Defaults + # to String. + # + # @return [String, Addressable::URI] + # The encoded URI. + # The return type is determined by the return_type + # parameter. + def self.normalized_encode(uri, return_type=String) + begin + uri = uri.to_str + rescue NoMethodError, TypeError + raise TypeError, "Can't convert #{uri.class} into String." + end if !uri.is_a? String + + if ![String, ::Addressable::URI].include?(return_type) + raise TypeError, + "Expected Class (String or Addressable::URI), " + + "got #{return_type.inspect}" + end + uri_object = uri.kind_of?(self) ? uri : self.parse(uri) + components = { + :scheme => self.unencode_component(uri_object.scheme), + :user => self.unencode_component(uri_object.user), + :password => self.unencode_component(uri_object.password), + :host => self.unencode_component(uri_object.host), + :port => (uri_object.port.nil? ? nil : uri_object.port.to_s), + :path => self.unencode_component(uri_object.path), + :query => self.unencode_component(uri_object.query), + :fragment => self.unencode_component(uri_object.fragment) + } + components.each do |key, value| + if value != nil + begin + components[key] = + Addressable::IDNA.unicode_normalize_kc(value.to_str) + rescue ArgumentError + # Likely a malformed UTF-8 character, skip unicode normalization + components[key] = value.to_str + end + end + end + encoded_uri = Addressable::URI.new( + :scheme => self.encode_component(components[:scheme], + Addressable::URI::CharacterClasses::SCHEME), + :user => self.encode_component(components[:user], + Addressable::URI::CharacterClasses::UNRESERVED), + :password => self.encode_component(components[:password], + Addressable::URI::CharacterClasses::UNRESERVED), + :host => components[:host], + :port => components[:port], + :path => self.encode_component(components[:path], + Addressable::URI::CharacterClasses::PATH), + :query => self.encode_component(components[:query], + Addressable::URI::CharacterClasses::QUERY), + :fragment => self.encode_component(components[:fragment], + Addressable::URI::CharacterClasses::FRAGMENT) + ) + if return_type == String + return encoded_uri.to_s + elsif return_type == ::Addressable::URI + return encoded_uri + end + end + + ## + # Encodes a set of key/value pairs according to the rules for the + # application/x-www-form-urlencoded MIME type. + # + # @param [#to_hash, #to_ary] form_values + # The form values to encode. + # + # @param [TrueClass, FalseClass] sort + # Sort the key/value pairs prior to encoding. + # Defaults to false. + # + # @return [String] + # The encoded value. + def self.form_encode(form_values, sort=false) + if form_values.respond_to?(:to_hash) + form_values = form_values.to_hash.to_a + elsif form_values.respond_to?(:to_ary) + form_values = form_values.to_ary + else + raise TypeError, "Can't convert #{form_values.class} into Array." + end + + form_values = form_values.inject([]) do |accu, (key, value)| + if value.kind_of?(Array) + value.each do |v| + accu << [key.to_s, v.to_s] + end + else + accu << [key.to_s, value.to_s] + end + accu + end + + if sort + # Useful for OAuth and optimizing caching systems + form_values = form_values.sort + end + escaped_form_values = form_values.map do |(key, value)| + # Line breaks are CRLF pairs + [ + self.encode_component( + key.gsub(/(\r\n|\n|\r)/, "\r\n"), + CharacterClasses::UNRESERVED + ).gsub("%20", "+"), + self.encode_component( + value.gsub(/(\r\n|\n|\r)/, "\r\n"), + CharacterClasses::UNRESERVED + ).gsub("%20", "+") + ] + end + return escaped_form_values.map do |(key, value)| + "#{key}=#{value}" + end.join("&") + end + + ## + # Decodes a String according to the rules for the + # application/x-www-form-urlencoded MIME type. + # + # @param [String, #to_str] encoded_value + # The form values to decode. + # + # @return [Array] + # The decoded values. + # This is not a Hash because of the possibility for + # duplicate keys. + def self.form_unencode(encoded_value) + if !encoded_value.respond_to?(:to_str) + raise TypeError, "Can't convert #{encoded_value.class} into String." + end + encoded_value = encoded_value.to_str + split_values = encoded_value.split("&").map do |pair| + pair.split("=", 2) + end + return split_values.map do |(key, value)| + [ + key ? self.unencode_component( + key.gsub("+", "%20")).gsub(/(\r\n|\n|\r)/, "\n") : nil, + value ? (self.unencode_component( + value.gsub("+", "%20")).gsub(/(\r\n|\n|\r)/, "\n")) : nil + ] + end + end + + ## + # Creates a new uri object from component parts. + # + # @option [String, #to_str] scheme The scheme component. + # @option [String, #to_str] user The user component. + # @option [String, #to_str] password The password component. + # @option [String, #to_str] userinfo + # The userinfo component. If this is supplied, the user and password + # components must be omitted. + # @option [String, #to_str] host The host component. + # @option [String, #to_str] port The port component. + # @option [String, #to_str] authority + # The authority component. If this is supplied, the user, password, + # userinfo, host, and port components must be omitted. + # @option [String, #to_str] path The path component. + # @option [String, #to_str] query The query component. + # @option [String, #to_str] fragment The fragment component. + # + # @return [Addressable::URI] The constructed URI object. + def initialize(options={}) + if options.has_key?(:authority) + if (options.keys & [:userinfo, :user, :password, :host, :port]).any? + raise ArgumentError, + "Cannot specify both an authority and any of the components " + + "within the authority." + end + end + if options.has_key?(:userinfo) + if (options.keys & [:user, :password]).any? + raise ArgumentError, + "Cannot specify both a userinfo and either the user or password." + end + end + + self.defer_validation do + # Bunch of crazy logic required because of the composite components + # like userinfo and authority. + self.scheme = options[:scheme] if options[:scheme] + self.user = options[:user] if options[:user] + self.password = options[:password] if options[:password] + self.userinfo = options[:userinfo] if options[:userinfo] + self.host = options[:host] if options[:host] + self.port = options[:port] if options[:port] + self.authority = options[:authority] if options[:authority] + self.path = options[:path] if options[:path] + self.query = options[:query] if options[:query] + self.query_values = options[:query_values] if options[:query_values] + self.fragment = options[:fragment] if options[:fragment] + end + self.to_s + end + + ## + # Freeze URI, initializing instance variables. + # + # @return [Addressable::URI] The frozen URI object. + def freeze + self.normalized_scheme + self.normalized_user + self.normalized_password + self.normalized_userinfo + self.normalized_host + self.normalized_port + self.normalized_authority + self.normalized_site + self.normalized_path + self.normalized_query + self.normalized_fragment + self.hash + super + end + + ## + # The scheme component for this URI. + # + # @return [String] The scheme component. + def scheme + return defined?(@scheme) ? @scheme : nil + end + + ## + # The scheme component for this URI, normalized. + # + # @return [String] The scheme component, normalized. + def normalized_scheme + return nil unless self.scheme + @normalized_scheme ||= begin + if self.scheme =~ /^\s*ssh\+svn\s*$/i + "svn+ssh".dup + else + Addressable::URI.normalize_component( + self.scheme.strip.downcase, + Addressable::URI::CharacterClasses::SCHEME + ) + end + end + # All normalized values should be UTF-8 + @normalized_scheme.force_encoding(Encoding::UTF_8) if @normalized_scheme + @normalized_scheme + end + + ## + # Sets the scheme component for this URI. + # + # @param [String, #to_str] new_scheme The new scheme component. + def scheme=(new_scheme) + if new_scheme && !new_scheme.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_scheme.class} into String." + elsif new_scheme + new_scheme = new_scheme.to_str + end + if new_scheme && new_scheme !~ /\A[a-z][a-z0-9\.\+\-]*\z/i + raise InvalidURIError, "Invalid scheme format: #{new_scheme}" + end + @scheme = new_scheme + @scheme = nil if @scheme.to_s.strip.empty? + + # Reset dependent values + remove_instance_variable(:@normalized_scheme) if defined?(@normalized_scheme) + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The user component for this URI. + # + # @return [String] The user component. + def user + return defined?(@user) ? @user : nil + end + + ## + # The user component for this URI, normalized. + # + # @return [String] The user component, normalized. + def normalized_user + return nil unless self.user + return @normalized_user if defined?(@normalized_user) + @normalized_user ||= begin + if normalized_scheme =~ /https?/ && self.user.strip.empty? && + (!self.password || self.password.strip.empty?) + nil + else + Addressable::URI.normalize_component( + self.user.strip, + Addressable::URI::CharacterClasses::UNRESERVED + ) + end + end + # All normalized values should be UTF-8 + @normalized_user.force_encoding(Encoding::UTF_8) if @normalized_user + @normalized_user + end + + ## + # Sets the user component for this URI. + # + # @param [String, #to_str] new_user The new user component. + def user=(new_user) + if new_user && !new_user.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_user.class} into String." + end + @user = new_user ? new_user.to_str : nil + + # You can't have a nil user with a non-nil password + if password != nil + @user = EMPTY_STR if @user.nil? + end + + # Reset dependent values + remove_instance_variable(:@userinfo) if defined?(@userinfo) + remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo) + remove_instance_variable(:@authority) if defined?(@authority) + remove_instance_variable(:@normalized_user) if defined?(@normalized_user) + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The password component for this URI. + # + # @return [String] The password component. + def password + return defined?(@password) ? @password : nil + end + + ## + # The password component for this URI, normalized. + # + # @return [String] The password component, normalized. + def normalized_password + return nil unless self.password + return @normalized_password if defined?(@normalized_password) + @normalized_password ||= begin + if self.normalized_scheme =~ /https?/ && self.password.strip.empty? && + (!self.user || self.user.strip.empty?) + nil + else + Addressable::URI.normalize_component( + self.password.strip, + Addressable::URI::CharacterClasses::UNRESERVED + ) + end + end + # All normalized values should be UTF-8 + if @normalized_password + @normalized_password.force_encoding(Encoding::UTF_8) + end + @normalized_password + end + + ## + # Sets the password component for this URI. + # + # @param [String, #to_str] new_password The new password component. + def password=(new_password) + if new_password && !new_password.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_password.class} into String." + end + @password = new_password ? new_password.to_str : nil + + # You can't have a nil user with a non-nil password + @password ||= nil + @user ||= nil + if @password != nil + @user = EMPTY_STR if @user.nil? + end + + # Reset dependent values + remove_instance_variable(:@userinfo) if defined?(@userinfo) + remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo) + remove_instance_variable(:@authority) if defined?(@authority) + remove_instance_variable(:@normalized_password) if defined?(@normalized_password) + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The userinfo component for this URI. + # Combines the user and password components. + # + # @return [String] The userinfo component. + def userinfo + current_user = self.user + current_password = self.password + (current_user || current_password) && @userinfo ||= begin + if current_user && current_password + "#{current_user}:#{current_password}" + elsif current_user && !current_password + "#{current_user}" + end + end + end + + ## + # The userinfo component for this URI, normalized. + # + # @return [String] The userinfo component, normalized. + def normalized_userinfo + return nil unless self.userinfo + return @normalized_userinfo if defined?(@normalized_userinfo) + @normalized_userinfo ||= begin + current_user = self.normalized_user + current_password = self.normalized_password + if !current_user && !current_password + nil + elsif current_user && current_password + "#{current_user}:#{current_password}".dup + elsif current_user && !current_password + "#{current_user}".dup + end + end + # All normalized values should be UTF-8 + if @normalized_userinfo + @normalized_userinfo.force_encoding(Encoding::UTF_8) + end + @normalized_userinfo + end + + ## + # Sets the userinfo component for this URI. + # + # @param [String, #to_str] new_userinfo The new userinfo component. + def userinfo=(new_userinfo) + if new_userinfo && !new_userinfo.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_userinfo.class} into String." + end + new_user, new_password = if new_userinfo + [ + new_userinfo.to_str.strip[/^(.*):/, 1], + new_userinfo.to_str.strip[/:(.*)$/, 1] + ] + else + [nil, nil] + end + + # Password assigned first to ensure validity in case of nil + self.password = new_password + self.user = new_user + + # Reset dependent values + remove_instance_variable(:@authority) if defined?(@authority) + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The host component for this URI. + # + # @return [String] The host component. + def host + return defined?(@host) ? @host : nil + end + + ## + # The host component for this URI, normalized. + # + # @return [String] The host component, normalized. + def normalized_host + return nil unless self.host + @normalized_host ||= begin + if !self.host.strip.empty? + result = ::Addressable::IDNA.to_ascii( + URI.unencode_component(self.host.strip.downcase) + ) + if result =~ /[^\.]\.$/ + # Single trailing dots are unnecessary. + result = result[0...-1] + end + result = Addressable::URI.normalize_component( + result, + CharacterClasses::HOST) + result + else + EMPTY_STR.dup + end + end + # All normalized values should be UTF-8 + @normalized_host.force_encoding(Encoding::UTF_8) if @normalized_host + @normalized_host + end + + ## + # Sets the host component for this URI. + # + # @param [String, #to_str] new_host The new host component. + def host=(new_host) + if new_host && !new_host.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_host.class} into String." + end + @host = new_host ? new_host.to_str : nil + + # Reset dependent values + remove_instance_variable(:@authority) if defined?(@authority) + remove_instance_variable(:@normalized_host) if defined?(@normalized_host) + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # This method is same as URI::Generic#host except + # brackets for IPv6 (and 'IPvFuture') addresses are removed. + # + # @see Addressable::URI#host + # + # @return [String] The hostname for this URI. + def hostname + v = self.host + /\A\[(.*)\]\z/ =~ v ? $1 : v + end + + ## + # This method is same as URI::Generic#host= except + # the argument can be a bare IPv6 address (or 'IPvFuture'). + # + # @see Addressable::URI#host= + # + # @param [String, #to_str] new_hostname The new hostname for this URI. + def hostname=(new_hostname) + if new_hostname && + (new_hostname.respond_to?(:ipv4?) || new_hostname.respond_to?(:ipv6?)) + new_hostname = new_hostname.to_s + elsif new_hostname && !new_hostname.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_hostname.class} into String." + end + v = new_hostname ? new_hostname.to_str : nil + v = "[#{v}]" if /\A\[.*\]\z/ !~ v && /:/ =~ v + self.host = v + end + + ## + # Returns the top-level domain for this host. + # + # @example + # Addressable::URI.parse("http://www.example.co.uk").tld # => "co.uk" + def tld + PublicSuffix.parse(self.host, ignore_private: true).tld + end + + ## + # Sets the top-level domain for this URI. + # + # @param [String, #to_str] new_tld The new top-level domain. + def tld=(new_tld) + replaced_tld = host.sub(/#{tld}\z/, new_tld) + self.host = PublicSuffix::Domain.new(replaced_tld).to_s + end + + ## + # Returns the public suffix domain for this host. + # + # @example + # Addressable::URI.parse("http://www.example.co.uk").domain # => "example.co.uk" + def domain + PublicSuffix.domain(self.host, ignore_private: true) + end + + ## + # The authority component for this URI. + # Combines the user, password, host, and port components. + # + # @return [String] The authority component. + def authority + self.host && @authority ||= begin + authority = String.new + if self.userinfo != nil + authority << "#{self.userinfo}@" + end + authority << self.host + if self.port != nil + authority << ":#{self.port}" + end + authority + end + end + + ## + # The authority component for this URI, normalized. + # + # @return [String] The authority component, normalized. + def normalized_authority + return nil unless self.authority + @normalized_authority ||= begin + authority = String.new + if self.normalized_userinfo != nil + authority << "#{self.normalized_userinfo}@" + end + authority << self.normalized_host + if self.normalized_port != nil + authority << ":#{self.normalized_port}" + end + authority + end + # All normalized values should be UTF-8 + if @normalized_authority + @normalized_authority.force_encoding(Encoding::UTF_8) + end + @normalized_authority + end + + ## + # Sets the authority component for this URI. + # + # @param [String, #to_str] new_authority The new authority component. + def authority=(new_authority) + if new_authority + if !new_authority.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_authority.class} into String." + end + new_authority = new_authority.to_str + new_userinfo = new_authority[/^([^\[\]]*)@/, 1] + if new_userinfo + new_user = new_userinfo.strip[/^([^:]*):?/, 1] + new_password = new_userinfo.strip[/:(.*)$/, 1] + end + new_host = new_authority.sub( + /^([^\[\]]*)@/, EMPTY_STR + ).sub( + /:([^:@\[\]]*?)$/, EMPTY_STR + ) + new_port = + new_authority[/:([^:@\[\]]*?)$/, 1] + end + + # Password assigned first to ensure validity in case of nil + self.password = defined?(new_password) ? new_password : nil + self.user = defined?(new_user) ? new_user : nil + self.host = defined?(new_host) ? new_host : nil + self.port = defined?(new_port) ? new_port : nil + + # Reset dependent values + remove_instance_variable(:@userinfo) if defined?(@userinfo) + remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo) + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The origin for this URI, serialized to ASCII, as per + # RFC 6454, section 6.2. + # + # @return [String] The serialized origin. + def origin + if self.scheme && self.authority + if self.normalized_port + "#{self.normalized_scheme}://#{self.normalized_host}" + + ":#{self.normalized_port}" + else + "#{self.normalized_scheme}://#{self.normalized_host}" + end + else + "null" + end + end + + ## + # Sets the origin for this URI, serialized to ASCII, as per + # RFC 6454, section 6.2. This assignment will reset the `userinfo` + # component. + # + # @param [String, #to_str] new_origin The new origin component. + def origin=(new_origin) + if new_origin + if !new_origin.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_origin.class} into String." + end + new_origin = new_origin.to_str + new_scheme = new_origin[/^([^:\/?#]+):\/\//, 1] + unless new_scheme + raise InvalidURIError, 'An origin cannot omit the scheme.' + end + new_host = new_origin[/:\/\/([^\/?#:]+)/, 1] + unless new_host + raise InvalidURIError, 'An origin cannot omit the host.' + end + new_port = new_origin[/:([^:@\[\]\/]*?)$/, 1] + end + + self.scheme = defined?(new_scheme) ? new_scheme : nil + self.host = defined?(new_host) ? new_host : nil + self.port = defined?(new_port) ? new_port : nil + self.userinfo = nil + + # Reset dependent values + remove_instance_variable(:@userinfo) if defined?(@userinfo) + remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo) + remove_instance_variable(:@authority) if defined?(@authority) + remove_instance_variable(:@normalized_authority) if defined?(@normalized_authority) + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + # Returns an array of known ip-based schemes. These schemes typically + # use a similar URI form: + # //:@:/ + def self.ip_based_schemes + return self.port_mapping.keys + end + + # Returns a hash of common IP-based schemes and their default port + # numbers. Adding new schemes to this hash, as necessary, will allow + # for better URI normalization. + def self.port_mapping + PORT_MAPPING + end + + ## + # The port component for this URI. + # This is the port number actually given in the URI. This does not + # infer port numbers from default values. + # + # @return [Integer] The port component. + def port + return defined?(@port) ? @port : nil + end + + ## + # The port component for this URI, normalized. + # + # @return [Integer] The port component, normalized. + def normalized_port + return nil unless self.port + return @normalized_port if defined?(@normalized_port) + @normalized_port ||= begin + if URI.port_mapping[self.normalized_scheme] == self.port + nil + else + self.port + end + end + end + + ## + # Sets the port component for this URI. + # + # @param [String, Integer, #to_s] new_port The new port component. + def port=(new_port) + if new_port != nil && new_port.respond_to?(:to_str) + new_port = Addressable::URI.unencode_component(new_port.to_str) + end + + if new_port.respond_to?(:valid_encoding?) && !new_port.valid_encoding? + raise InvalidURIError, "Invalid encoding in port" + end + + if new_port != nil && !(new_port.to_s =~ /^\d+$/) + raise InvalidURIError, + "Invalid port number: #{new_port.inspect}" + end + + @port = new_port.to_s.to_i + @port = nil if @port == 0 + + # Reset dependent values + remove_instance_variable(:@authority) if defined?(@authority) + remove_instance_variable(:@normalized_port) if defined?(@normalized_port) + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The inferred port component for this URI. + # This method will normalize to the default port for the URI's scheme if + # the port isn't explicitly specified in the URI. + # + # @return [Integer] The inferred port component. + def inferred_port + if self.port.to_i == 0 + self.default_port + else + self.port.to_i + end + end + + ## + # The default port for this URI's scheme. + # This method will always returns the default port for the URI's scheme + # regardless of the presence of an explicit port in the URI. + # + # @return [Integer] The default port. + def default_port + URI.port_mapping[self.scheme.strip.downcase] if self.scheme + end + + ## + # The combination of components that represent a site. + # Combines the scheme, user, password, host, and port components. + # Primarily useful for HTTP and HTTPS. + # + # For example, "http://example.com/path?query" would have a + # site value of "http://example.com". + # + # @return [String] The components that identify a site. + def site + (self.scheme || self.authority) && @site ||= begin + site_string = "".dup + site_string << "#{self.scheme}:" if self.scheme != nil + site_string << "//#{self.authority}" if self.authority != nil + site_string + end + end + + ## + # The normalized combination of components that represent a site. + # Combines the scheme, user, password, host, and port components. + # Primarily useful for HTTP and HTTPS. + # + # For example, "http://example.com/path?query" would have a + # site value of "http://example.com". + # + # @return [String] The normalized components that identify a site. + def normalized_site + return nil unless self.site + @normalized_site ||= begin + site_string = "".dup + if self.normalized_scheme != nil + site_string << "#{self.normalized_scheme}:" + end + if self.normalized_authority != nil + site_string << "//#{self.normalized_authority}" + end + site_string + end + # All normalized values should be UTF-8 + @normalized_site.force_encoding(Encoding::UTF_8) if @normalized_site + @normalized_site + end + + ## + # Sets the site value for this URI. + # + # @param [String, #to_str] new_site The new site value. + def site=(new_site) + if new_site + if !new_site.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_site.class} into String." + end + new_site = new_site.to_str + # These two regular expressions derived from the primary parsing + # expression + self.scheme = new_site[/^(?:([^:\/?#]+):)?(?:\/\/(?:[^\/?#]*))?$/, 1] + self.authority = new_site[ + /^(?:(?:[^:\/?#]+):)?(?:\/\/([^\/?#]*))?$/, 1 + ] + else + self.scheme = nil + self.authority = nil + end + end + + ## + # The path component for this URI. + # + # @return [String] The path component. + def path + return defined?(@path) ? @path : EMPTY_STR + end + + NORMPATH = /^(?!\/)[^\/:]*:.*$/ + ## + # The path component for this URI, normalized. + # + # @return [String] The path component, normalized. + def normalized_path + @normalized_path ||= begin + path = self.path.to_s + if self.scheme == nil && path =~ NORMPATH + # Relative paths with colons in the first segment are ambiguous. + path = path.sub(":", "%2F") + end + # String#split(delimeter, -1) uses the more strict splitting behavior + # found by default in Python. + result = path.strip.split(SLASH, -1).map do |segment| + Addressable::URI.normalize_component( + segment, + Addressable::URI::CharacterClasses::PCHAR + ) + end.join(SLASH) + + result = URI.normalize_path(result) + if result.empty? && + ["http", "https", "ftp", "tftp"].include?(self.normalized_scheme) + result = SLASH.dup + end + result + end + # All normalized values should be UTF-8 + @normalized_path.force_encoding(Encoding::UTF_8) if @normalized_path + @normalized_path + end + + ## + # Sets the path component for this URI. + # + # @param [String, #to_str] new_path The new path component. + def path=(new_path) + if new_path && !new_path.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_path.class} into String." + end + @path = (new_path || EMPTY_STR).to_str + if !@path.empty? && @path[0..0] != SLASH && host != nil + @path = "/#{@path}" + end + + # Reset dependent values + remove_instance_variable(:@normalized_path) if defined?(@normalized_path) + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The basename, if any, of the file in the path component. + # + # @return [String] The path's basename. + def basename + # Path cannot be nil + return File.basename(self.path).sub(/;[^\/]*$/, EMPTY_STR) + end + + ## + # The extname, if any, of the file in the path component. + # Empty string if there is no extension. + # + # @return [String] The path's extname. + def extname + return nil unless self.path + return File.extname(self.basename) + end + + ## + # The query component for this URI. + # + # @return [String] The query component. + def query + return defined?(@query) ? @query : nil + end + + ## + # The query component for this URI, normalized. + # + # @return [String] The query component, normalized. + def normalized_query(*flags) + return nil unless self.query + return @normalized_query if defined?(@normalized_query) + @normalized_query ||= begin + modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup + # Make sure possible key-value pair delimiters are escaped. + modified_query_class.sub!("\\&", "").sub!("\\;", "") + pairs = (self.query || "").split("&", -1) + pairs.delete_if(&:empty?) if flags.include?(:compacted) + pairs.sort! if flags.include?(:sorted) + component = pairs.map do |pair| + Addressable::URI.normalize_component(pair, modified_query_class, "+") + end.join("&") + component == "" ? nil : component + end + # All normalized values should be UTF-8 + @normalized_query.force_encoding(Encoding::UTF_8) if @normalized_query + @normalized_query + end + + ## + # Sets the query component for this URI. + # + # @param [String, #to_str] new_query The new query component. + def query=(new_query) + if new_query && !new_query.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_query.class} into String." + end + @query = new_query ? new_query.to_str : nil + + # Reset dependent values + remove_instance_variable(:@normalized_query) if defined?(@normalized_query) + remove_composite_values + end + + ## + # Converts the query component to a Hash value. + # + # @param [Class] return_type The return type desired. Value must be either + # `Hash` or `Array`. + # + # @return [Hash, Array, nil] The query string parsed as a Hash or Array + # or nil if the query string is blank. + # + # @example + # Addressable::URI.parse("?one=1&two=2&three=3").query_values + # #=> {"one" => "1", "two" => "2", "three" => "3"} + # Addressable::URI.parse("?one=two&one=three").query_values(Array) + # #=> [["one", "two"], ["one", "three"]] + # Addressable::URI.parse("?one=two&one=three").query_values(Hash) + # #=> {"one" => "three"} + # Addressable::URI.parse("?").query_values + # #=> {} + # Addressable::URI.parse("").query_values + # #=> nil + def query_values(return_type=Hash) + empty_accumulator = Array == return_type ? [] : {} + if return_type != Hash && return_type != Array + raise ArgumentError, "Invalid return type. Must be Hash or Array." + end + return nil if self.query == nil + split_query = self.query.split("&").map do |pair| + pair.split("=", 2) if pair && !pair.empty? + end.compact + return split_query.inject(empty_accumulator.dup) do |accu, pair| + # I'd rather use key/value identifiers instead of array lookups, + # but in this case I really want to maintain the exact pair structure, + # so it's best to make all changes in-place. + pair[0] = URI.unencode_component(pair[0]) + if pair[1].respond_to?(:to_str) + # I loathe the fact that I have to do this. Stupid HTML 4.01. + # Treating '+' as a space was just an unbelievably bad idea. + # There was nothing wrong with '%20'! + # If it ain't broke, don't fix it! + pair[1] = URI.unencode_component(pair[1].to_str.tr("+", " ")) + end + if return_type == Hash + accu[pair[0]] = pair[1] + else + accu << pair + end + accu + end + end + + ## + # Sets the query component for this URI from a Hash object. + # An empty Hash or Array will result in an empty query string. + # + # @param [Hash, #to_hash, Array] new_query_values The new query values. + # + # @example + # uri.query_values = {:a => "a", :b => ["c", "d", "e"]} + # uri.query + # # => "a=a&b=c&b=d&b=e" + # uri.query_values = [['a', 'a'], ['b', 'c'], ['b', 'd'], ['b', 'e']] + # uri.query + # # => "a=a&b=c&b=d&b=e" + # uri.query_values = [['a', 'a'], ['b', ['c', 'd', 'e']]] + # uri.query + # # => "a=a&b=c&b=d&b=e" + # uri.query_values = [['flag'], ['key', 'value']] + # uri.query + # # => "flag&key=value" + def query_values=(new_query_values) + if new_query_values == nil + self.query = nil + return nil + end + + if !new_query_values.is_a?(Array) + if !new_query_values.respond_to?(:to_hash) + raise TypeError, + "Can't convert #{new_query_values.class} into Hash." + end + new_query_values = new_query_values.to_hash + new_query_values = new_query_values.map do |key, value| + key = key.to_s if key.kind_of?(Symbol) + [key, value] + end + # Useful default for OAuth and caching. + # Only to be used for non-Array inputs. Arrays should preserve order. + new_query_values.sort! + end + + # new_query_values have form [['key1', 'value1'], ['key2', 'value2']] + buffer = "".dup + new_query_values.each do |key, value| + encoded_key = URI.encode_component( + key, CharacterClasses::UNRESERVED + ) + if value == nil + buffer << "#{encoded_key}&" + elsif value.kind_of?(Array) + value.each do |sub_value| + encoded_value = URI.encode_component( + sub_value, CharacterClasses::UNRESERVED + ) + buffer << "#{encoded_key}=#{encoded_value}&" + end + else + encoded_value = URI.encode_component( + value, CharacterClasses::UNRESERVED + ) + buffer << "#{encoded_key}=#{encoded_value}&" + end + end + self.query = buffer.chop + end + + ## + # The HTTP request URI for this URI. This is the path and the + # query string. + # + # @return [String] The request URI required for an HTTP request. + def request_uri + return nil if self.absolute? && self.scheme !~ /^https?$/i + return ( + (!self.path.empty? ? self.path : SLASH) + + (self.query ? "?#{self.query}" : EMPTY_STR) + ) + end + + ## + # Sets the HTTP request URI for this URI. + # + # @param [String, #to_str] new_request_uri The new HTTP request URI. + def request_uri=(new_request_uri) + if !new_request_uri.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_request_uri.class} into String." + end + if self.absolute? && self.scheme !~ /^https?$/i + raise InvalidURIError, + "Cannot set an HTTP request URI for a non-HTTP URI." + end + new_request_uri = new_request_uri.to_str + path_component = new_request_uri[/^([^\?]*)\??(?:.*)$/, 1] + query_component = new_request_uri[/^(?:[^\?]*)\?(.*)$/, 1] + path_component = path_component.to_s + path_component = (!path_component.empty? ? path_component : SLASH) + self.path = path_component + self.query = query_component + + # Reset dependent values + remove_composite_values + end + + ## + # The fragment component for this URI. + # + # @return [String] The fragment component. + def fragment + return defined?(@fragment) ? @fragment : nil + end + + ## + # The fragment component for this URI, normalized. + # + # @return [String] The fragment component, normalized. + def normalized_fragment + return nil unless self.fragment + return @normalized_fragment if defined?(@normalized_fragment) + @normalized_fragment ||= begin + component = Addressable::URI.normalize_component( + self.fragment, + Addressable::URI::CharacterClasses::FRAGMENT + ) + component == "" ? nil : component + end + # All normalized values should be UTF-8 + if @normalized_fragment + @normalized_fragment.force_encoding(Encoding::UTF_8) + end + @normalized_fragment + end + + ## + # Sets the fragment component for this URI. + # + # @param [String, #to_str] new_fragment The new fragment component. + def fragment=(new_fragment) + if new_fragment && !new_fragment.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_fragment.class} into String." + end + @fragment = new_fragment ? new_fragment.to_str : nil + + # Reset dependent values + remove_instance_variable(:@normalized_fragment) if defined?(@normalized_fragment) + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # Determines if the scheme indicates an IP-based protocol. + # + # @return [TrueClass, FalseClass] + # true if the scheme indicates an IP-based protocol. + # false otherwise. + def ip_based? + if self.scheme + return URI.ip_based_schemes.include?( + self.scheme.strip.downcase) + end + return false + end + + ## + # Determines if the URI is relative. + # + # @return [TrueClass, FalseClass] + # true if the URI is relative. false + # otherwise. + def relative? + return self.scheme.nil? + end + + ## + # Determines if the URI is absolute. + # + # @return [TrueClass, FalseClass] + # true if the URI is absolute. false + # otherwise. + def absolute? + return !relative? + end + + ## + # Joins two URIs together. + # + # @param [String, Addressable::URI, #to_str] The URI to join with. + # + # @return [Addressable::URI] The joined URI. + def join(uri) + if !uri.respond_to?(:to_str) + raise TypeError, "Can't convert #{uri.class} into String." + end + if !uri.kind_of?(URI) + # Otherwise, convert to a String, then parse. + uri = URI.parse(uri.to_str) + end + if uri.to_s.empty? + return self.dup + end + + joined_scheme = nil + joined_user = nil + joined_password = nil + joined_host = nil + joined_port = nil + joined_path = nil + joined_query = nil + joined_fragment = nil + + # Section 5.2.2 of RFC 3986 + if uri.scheme != nil + joined_scheme = uri.scheme + joined_user = uri.user + joined_password = uri.password + joined_host = uri.host + joined_port = uri.port + joined_path = URI.normalize_path(uri.path) + joined_query = uri.query + else + if uri.authority != nil + joined_user = uri.user + joined_password = uri.password + joined_host = uri.host + joined_port = uri.port + joined_path = URI.normalize_path(uri.path) + joined_query = uri.query + else + if uri.path == nil || uri.path.empty? + joined_path = self.path + if uri.query != nil + joined_query = uri.query + else + joined_query = self.query + end + else + if uri.path[0..0] == SLASH + joined_path = URI.normalize_path(uri.path) + else + base_path = self.path.dup + base_path = EMPTY_STR if base_path == nil + base_path = URI.normalize_path(base_path) + + # Section 5.2.3 of RFC 3986 + # + # Removes the right-most path segment from the base path. + if base_path.include?(SLASH) + base_path.sub!(/\/[^\/]+$/, SLASH) + else + base_path = EMPTY_STR + end + + # If the base path is empty and an authority segment has been + # defined, use a base path of SLASH + if base_path.empty? && self.authority != nil + base_path = SLASH + end + + joined_path = URI.normalize_path(base_path + uri.path) + end + joined_query = uri.query + end + joined_user = self.user + joined_password = self.password + joined_host = self.host + joined_port = self.port + end + joined_scheme = self.scheme + end + joined_fragment = uri.fragment + + return self.class.new( + :scheme => joined_scheme, + :user => joined_user, + :password => joined_password, + :host => joined_host, + :port => joined_port, + :path => joined_path, + :query => joined_query, + :fragment => joined_fragment + ) + end + alias_method :+, :join + + ## + # Destructive form of join. + # + # @param [String, Addressable::URI, #to_str] The URI to join with. + # + # @return [Addressable::URI] The joined URI. + # + # @see Addressable::URI#join + def join!(uri) + replace_self(self.join(uri)) + end + + ## + # Merges a URI with a Hash of components. + # This method has different behavior from join. Any + # components present in the hash parameter will override the + # original components. The path component is not treated specially. + # + # @param [Hash, Addressable::URI, #to_hash] The components to merge with. + # + # @return [Addressable::URI] The merged URI. + # + # @see Hash#merge + def merge(hash) + if !hash.respond_to?(:to_hash) + raise TypeError, "Can't convert #{hash.class} into Hash." + end + hash = hash.to_hash + + if hash.has_key?(:authority) + if (hash.keys & [:userinfo, :user, :password, :host, :port]).any? + raise ArgumentError, + "Cannot specify both an authority and any of the components " + + "within the authority." + end + end + if hash.has_key?(:userinfo) + if (hash.keys & [:user, :password]).any? + raise ArgumentError, + "Cannot specify both a userinfo and either the user or password." + end + end + + uri = self.class.new + uri.defer_validation do + # Bunch of crazy logic required because of the composite components + # like userinfo and authority. + uri.scheme = + hash.has_key?(:scheme) ? hash[:scheme] : self.scheme + if hash.has_key?(:authority) + uri.authority = + hash.has_key?(:authority) ? hash[:authority] : self.authority + end + if hash.has_key?(:userinfo) + uri.userinfo = + hash.has_key?(:userinfo) ? hash[:userinfo] : self.userinfo + end + if !hash.has_key?(:userinfo) && !hash.has_key?(:authority) + uri.user = + hash.has_key?(:user) ? hash[:user] : self.user + uri.password = + hash.has_key?(:password) ? hash[:password] : self.password + end + if !hash.has_key?(:authority) + uri.host = + hash.has_key?(:host) ? hash[:host] : self.host + uri.port = + hash.has_key?(:port) ? hash[:port] : self.port + end + uri.path = + hash.has_key?(:path) ? hash[:path] : self.path + uri.query = + hash.has_key?(:query) ? hash[:query] : self.query + uri.fragment = + hash.has_key?(:fragment) ? hash[:fragment] : self.fragment + end + + return uri + end + + ## + # Destructive form of merge. + # + # @param [Hash, Addressable::URI, #to_hash] The components to merge with. + # + # @return [Addressable::URI] The merged URI. + # + # @see Addressable::URI#merge + def merge!(uri) + replace_self(self.merge(uri)) + end + + ## + # Returns the shortest normalized relative form of this URI that uses the + # supplied URI as a base for resolution. Returns an absolute URI if + # necessary. This is effectively the opposite of route_to. + # + # @param [String, Addressable::URI, #to_str] uri The URI to route from. + # + # @return [Addressable::URI] + # The normalized relative URI that is equivalent to the original URI. + def route_from(uri) + uri = URI.parse(uri).normalize + normalized_self = self.normalize + if normalized_self.relative? + raise ArgumentError, "Expected absolute URI, got: #{self.to_s}" + end + if uri.relative? + raise ArgumentError, "Expected absolute URI, got: #{uri.to_s}" + end + if normalized_self == uri + return Addressable::URI.parse("##{normalized_self.fragment}") + end + components = normalized_self.to_hash + if normalized_self.scheme == uri.scheme + components[:scheme] = nil + if normalized_self.authority == uri.authority + components[:user] = nil + components[:password] = nil + components[:host] = nil + components[:port] = nil + if normalized_self.path == uri.path + components[:path] = nil + if normalized_self.query == uri.query + components[:query] = nil + end + else + if uri.path != SLASH and components[:path] + self_splitted_path = split_path(components[:path]) + uri_splitted_path = split_path(uri.path) + self_dir = self_splitted_path.shift + uri_dir = uri_splitted_path.shift + while !self_splitted_path.empty? && !uri_splitted_path.empty? and self_dir == uri_dir + self_dir = self_splitted_path.shift + uri_dir = uri_splitted_path.shift + end + components[:path] = (uri_splitted_path.fill('..') + [self_dir] + self_splitted_path).join(SLASH) + end + end + end + end + # Avoid network-path references. + if components[:host] != nil + components[:scheme] = normalized_self.scheme + end + return Addressable::URI.new( + :scheme => components[:scheme], + :user => components[:user], + :password => components[:password], + :host => components[:host], + :port => components[:port], + :path => components[:path], + :query => components[:query], + :fragment => components[:fragment] + ) + end + + ## + # Returns the shortest normalized relative form of the supplied URI that + # uses this URI as a base for resolution. Returns an absolute URI if + # necessary. This is effectively the opposite of route_from. + # + # @param [String, Addressable::URI, #to_str] uri The URI to route to. + # + # @return [Addressable::URI] + # The normalized relative URI that is equivalent to the supplied URI. + def route_to(uri) + return URI.parse(uri).route_from(self) + end + + ## + # Returns a normalized URI object. + # + # NOTE: This method does not attempt to fully conform to specifications. + # It exists largely to correct other people's failures to read the + # specifications, and also to deal with caching issues since several + # different URIs may represent the same resource and should not be + # cached multiple times. + # + # @return [Addressable::URI] The normalized URI. + def normalize + # This is a special exception for the frequently misused feed + # URI scheme. + if normalized_scheme == "feed" + if self.to_s =~ /^feed:\/*http:\/*/ + return URI.parse( + self.to_s[/^feed:\/*(http:\/*.*)/, 1] + ).normalize + end + end + + return self.class.new( + :scheme => normalized_scheme, + :authority => normalized_authority, + :path => normalized_path, + :query => normalized_query, + :fragment => normalized_fragment + ) + end + + ## + # Destructively normalizes this URI object. + # + # @return [Addressable::URI] The normalized URI. + # + # @see Addressable::URI#normalize + def normalize! + replace_self(self.normalize) + end + + ## + # Creates a URI suitable for display to users. If semantic attacks are + # likely, the application should try to detect these and warn the user. + # See RFC 3986, + # section 7.6 for more information. + # + # @return [Addressable::URI] A URI suitable for display purposes. + def display_uri + display_uri = self.normalize + display_uri.host = ::Addressable::IDNA.to_unicode(display_uri.host) + return display_uri + end + + ## + # Returns true if the URI objects are equal. This method + # normalizes both URIs before doing the comparison, and allows comparison + # against Strings. + # + # @param [Object] uri The URI to compare. + # + # @return [TrueClass, FalseClass] + # true if the URIs are equivalent, false + # otherwise. + def ===(uri) + if uri.respond_to?(:normalize) + uri_string = uri.normalize.to_s + else + begin + uri_string = ::Addressable::URI.parse(uri).normalize.to_s + rescue InvalidURIError, TypeError + return false + end + end + return self.normalize.to_s == uri_string + end + + ## + # Returns true if the URI objects are equal. This method + # normalizes both URIs before doing the comparison. + # + # @param [Object] uri The URI to compare. + # + # @return [TrueClass, FalseClass] + # true if the URIs are equivalent, false + # otherwise. + def ==(uri) + return false unless uri.kind_of?(URI) + return self.normalize.to_s == uri.normalize.to_s + end + + ## + # Returns true if the URI objects are equal. This method + # does NOT normalize either URI before doing the comparison. + # + # @param [Object] uri The URI to compare. + # + # @return [TrueClass, FalseClass] + # true if the URIs are equivalent, false + # otherwise. + def eql?(uri) + return false unless uri.kind_of?(URI) + return self.to_s == uri.to_s + end + + ## + # A hash value that will make a URI equivalent to its normalized + # form. + # + # @return [Integer] A hash of the URI. + def hash + @hash ||= self.to_s.hash * -1 + end + + ## + # Clones the URI object. + # + # @return [Addressable::URI] The cloned URI. + def dup + duplicated_uri = self.class.new( + :scheme => self.scheme ? self.scheme.dup : nil, + :user => self.user ? self.user.dup : nil, + :password => self.password ? self.password.dup : nil, + :host => self.host ? self.host.dup : nil, + :port => self.port, + :path => self.path ? self.path.dup : nil, + :query => self.query ? self.query.dup : nil, + :fragment => self.fragment ? self.fragment.dup : nil + ) + return duplicated_uri + end + + ## + # Omits components from a URI. + # + # @param [Symbol] *components The components to be omitted. + # + # @return [Addressable::URI] The URI with components omitted. + # + # @example + # uri = Addressable::URI.parse("http://example.com/path?query") + # #=> # + # uri.omit(:scheme, :authority) + # #=> # + def omit(*components) + invalid_components = components - [ + :scheme, :user, :password, :userinfo, :host, :port, :authority, + :path, :query, :fragment + ] + unless invalid_components.empty? + raise ArgumentError, + "Invalid component names: #{invalid_components.inspect}." + end + duplicated_uri = self.dup + duplicated_uri.defer_validation do + components.each do |component| + duplicated_uri.send((component.to_s + "=").to_sym, nil) + end + duplicated_uri.user = duplicated_uri.normalized_user + end + duplicated_uri + end + + ## + # Destructive form of omit. + # + # @param [Symbol] *components The components to be omitted. + # + # @return [Addressable::URI] The URI with components omitted. + # + # @see Addressable::URI#omit + def omit!(*components) + replace_self(self.omit(*components)) + end + + ## + # Determines if the URI is an empty string. + # + # @return [TrueClass, FalseClass] + # Returns true if empty, false otherwise. + def empty? + return self.to_s.empty? + end + + ## + # Converts the URI to a String. + # + # @return [String] The URI's String representation. + def to_s + if self.scheme == nil && self.path != nil && !self.path.empty? && + self.path =~ NORMPATH + raise InvalidURIError, + "Cannot assemble URI string with ambiguous path: '#{self.path}'" + end + @uri_string ||= begin + uri_string = String.new + uri_string << "#{self.scheme}:" if self.scheme != nil + uri_string << "//#{self.authority}" if self.authority != nil + uri_string << self.path.to_s + uri_string << "?#{self.query}" if self.query != nil + uri_string << "##{self.fragment}" if self.fragment != nil + uri_string.force_encoding(Encoding::UTF_8) + uri_string + end + end + + ## + # URI's are glorified Strings. Allow implicit conversion. + alias_method :to_str, :to_s + + ## + # Returns a Hash of the URI components. + # + # @return [Hash] The URI as a Hash of components. + def to_hash + return { + :scheme => self.scheme, + :user => self.user, + :password => self.password, + :host => self.host, + :port => self.port, + :path => self.path, + :query => self.query, + :fragment => self.fragment + } + end + + ## + # Returns a String representation of the URI object's state. + # + # @return [String] The URI object's state, as a String. + def inspect + sprintf("#<%s:%#0x URI:%s>", URI.to_s, self.object_id, self.to_s) + end + + ## + # This method allows you to make several changes to a URI simultaneously, + # which separately would cause validation errors, but in conjunction, + # are valid. The URI will be revalidated as soon as the entire block has + # been executed. + # + # @param [Proc] block + # A set of operations to perform on a given URI. + def defer_validation + raise LocalJumpError, "No block given." unless block_given? + @validation_deferred = true + yield + @validation_deferred = false + validate + return nil + end + + protected + SELF_REF = '.' + PARENT = '..' + + RULE_2A = /\/\.\/|\/\.$/ + RULE_2B_2C = /\/([^\/]*)\/\.\.\/|\/([^\/]*)\/\.\.$/ + RULE_2D = /^\.\.?\/?/ + RULE_PREFIXED_PARENT = /^\/\.\.?\/|^(\/\.\.?)+\/?$/ + + ## + # Resolves paths to their simplest form. + # + # @param [String] path The path to normalize. + # + # @return [String] The normalized path. + def self.normalize_path(path) + # Section 5.2.4 of RFC 3986 + + return nil if path.nil? + normalized_path = path.dup + begin + mod = nil + mod ||= normalized_path.gsub!(RULE_2A, SLASH) + + pair = normalized_path.match(RULE_2B_2C) + parent, current = pair[1], pair[2] if pair + if pair && ((parent != SELF_REF && parent != PARENT) || + (current != SELF_REF && current != PARENT)) + mod ||= normalized_path.gsub!( + Regexp.new( + "/#{Regexp.escape(parent.to_s)}/\\.\\./|" + + "(/#{Regexp.escape(current.to_s)}/\\.\\.$)" + ), SLASH + ) + end + + mod ||= normalized_path.gsub!(RULE_2D, EMPTY_STR) + # Non-standard, removes prefixed dotted segments from path. + mod ||= normalized_path.gsub!(RULE_PREFIXED_PARENT, SLASH) + end until mod.nil? + + return normalized_path + end + + ## + # Ensures that the URI is valid. + def validate + return if !!@validation_deferred + if self.scheme != nil && self.ip_based? && + (self.host == nil || self.host.empty?) && + (self.path == nil || self.path.empty?) + raise InvalidURIError, + "Absolute URI missing hierarchical segment: '#{self.to_s}'" + end + if self.host == nil + if self.port != nil || + self.user != nil || + self.password != nil + raise InvalidURIError, "Hostname not supplied: '#{self.to_s}'" + end + end + if self.path != nil && !self.path.empty? && self.path[0..0] != SLASH && + self.authority != nil + raise InvalidURIError, + "Cannot have a relative path with an authority set: '#{self.to_s}'" + end + if self.path != nil && !self.path.empty? && + self.path[0..1] == SLASH + SLASH && self.authority == nil + raise InvalidURIError, + "Cannot have a path with two leading slashes " + + "without an authority set: '#{self.to_s}'" + end + unreserved = CharacterClasses::UNRESERVED + sub_delims = CharacterClasses::SUB_DELIMS + if !self.host.nil? && (self.host =~ /[<>{}\/\\\?\#\@"[[:space:]]]/ || + (self.host[/^\[(.*)\]$/, 1] != nil && self.host[/^\[(.*)\]$/, 1] !~ + Regexp.new("^[#{unreserved}#{sub_delims}:]*$"))) + raise InvalidURIError, "Invalid character in host: '#{self.host.to_s}'" + end + return nil + end + + ## + # Replaces the internal state of self with the specified URI's state. + # Used in destructive operations to avoid massive code repetition. + # + # @param [Addressable::URI] uri The URI to replace self with. + # + # @return [Addressable::URI] self. + def replace_self(uri) + # Reset dependent values + instance_variables.each do |var| + if instance_variable_defined?(var) && var != :@validation_deferred + remove_instance_variable(var) + end + end + + @scheme = uri.scheme + @user = uri.user + @password = uri.password + @host = uri.host + @port = uri.port + @path = uri.path + @query = uri.query + @fragment = uri.fragment + return self + end + + ## + # Splits path string with "/" (slash). + # It is considered that there is empty string after last slash when + # path ends with slash. + # + # @param [String] path The path to split. + # + # @return [Array] An array of parts of path. + def split_path(path) + splitted = path.split(SLASH) + splitted << EMPTY_STR if path.end_with? SLASH + splitted + end + + ## + # Resets composite values for the entire URI + # + # @api private + def remove_composite_values + remove_instance_variable(:@uri_string) if defined?(@uri_string) + remove_instance_variable(:@hash) if defined?(@hash) + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/version.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/version.rb new file mode 100644 index 0000000000..5be5ff0905 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/version.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +# encoding:utf-8 +#-- +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +# Used to prevent the class/module from being loaded more than once +if !defined?(Addressable::VERSION) + module Addressable + module VERSION + MAJOR = 2 + MINOR = 7 + TINY = 0 + + STRING = [MAJOR, MINOR, TINY].join('.') + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/mechanize-2.7.7/lib/mechanize/version.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/mechanize-2.7.7/lib/mechanize/version.rb deleted file mode 100644 index 8eb274aaaf..0000000000 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/mechanize-2.7.7/lib/mechanize/version.rb +++ /dev/null @@ -1,3 +0,0 @@ -class Mechanize - VERSION = "2.7.7" -end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/mechanize-2.7.7/lib/mechanize/http/content_disposition_parser.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/mechanize-2.8.0/lib/mechanize/http/content_disposition_parser.rb similarity index 91% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/mechanize-2.7.7/lib/mechanize/http/content_disposition_parser.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/mechanize-2.8.0/lib/mechanize/http/content_disposition_parser.rb index e1ee752536..3ea90971dc 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/mechanize-2.7.7/lib/mechanize/http/content_disposition_parser.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/mechanize-2.8.0/lib/mechanize/http/content_disposition_parser.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # coding: BINARY require 'strscan' @@ -16,6 +17,7 @@ end # * Missing disposition-type # * Multiple semicolons # * Whitespace around semicolons +# * Dates in ISO 8601 format class Mechanize::HTTP::ContentDispositionParser @@ -93,7 +95,17 @@ class Mechanize::HTTP::ContentDispositionParser when /^filename$/ then rfc_2045_value when /^(creation|modification|read)-date$/ then - Time.rfc822 rfc_2045_quoted_string + date = rfc_2045_quoted_string + + begin + Time.rfc822 date + rescue ArgumentError + begin + Time.iso8601 date + rescue ArgumentError + nil + end + end when /^size$/ then rfc_2045_value.to_i(10) else @@ -125,7 +137,7 @@ class Mechanize::HTTP::ContentDispositionParser def rfc_2045_quoted_string return nil unless @scanner.scan(/"/) - text = '' + text = String.new while true do chunk = @scanner.scan(/[\000-\014\016-\041\043-\133\135-\177]+/) # not \r " diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/mechanize-2.8.0/lib/mechanize/version.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/mechanize-2.8.0/lib/mechanize/version.rb new file mode 100644 index 0000000000..af27a15c4e --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/mechanize-2.8.0/lib/mechanize/version.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true +class Mechanize + VERSION = "2.8.0" +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.6/lib/public_suffix.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.6/lib/public_suffix.rb new file mode 100644 index 0000000000..01f880e3a8 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.6/lib/public_suffix.rb @@ -0,0 +1,179 @@ +# frozen_string_literal: true + +# = Public Suffix +# +# Domain name parser based on the Public Suffix List. +# +# Copyright (c) 2009-2020 Simone Carletti + +require_relative "public_suffix/domain" +require_relative "public_suffix/version" +require_relative "public_suffix/errors" +require_relative "public_suffix/rule" +require_relative "public_suffix/list" + +# PublicSuffix is a Ruby domain name parser based on the Public Suffix List. +# +# The [Public Suffix List](https://publicsuffix.org) is a cross-vendor initiative +# to provide an accurate list of domain name suffixes. +# +# The Public Suffix List is an initiative of the Mozilla Project, +# but is maintained as a community resource. It is available for use in any software, +# but was originally created to meet the needs of browser manufacturers. +module PublicSuffix + + DOT = "." + BANG = "!" + STAR = "*" + + # Parses +name+ and returns the {PublicSuffix::Domain} instance. + # + # @example Parse a valid domain + # PublicSuffix.parse("google.com") + # # => # + # + # @example Parse a valid subdomain + # PublicSuffix.parse("www.google.com") + # # => # + # + # @example Parse a fully qualified domain + # PublicSuffix.parse("google.com.") + # # => # + # + # @example Parse a fully qualified domain (subdomain) + # PublicSuffix.parse("www.google.com.") + # # => # + # + # @example Parse an invalid (unlisted) domain + # PublicSuffix.parse("x.yz") + # # => # + # + # @example Parse an invalid (unlisted) domain with strict checking (without applying the default * rule) + # PublicSuffix.parse("x.yz", default_rule: nil) + # # => PublicSuffix::DomainInvalid: `x.yz` is not a valid domain + # + # @example Parse an URL (not supported, only domains) + # PublicSuffix.parse("http://www.google.com") + # # => PublicSuffix::DomainInvalid: http://www.google.com is not expected to contain a scheme + # + # + # @param [String, #to_s] name The domain name or fully qualified domain name to parse. + # @param [PublicSuffix::List] list The rule list to search, defaults to the default {PublicSuffix::List} + # @param [Boolean] ignore_private + # @return [PublicSuffix::Domain] + # + # @raise [PublicSuffix::DomainInvalid] + # If domain is not a valid domain. + # @raise [PublicSuffix::DomainNotAllowed] + # If a rule for +domain+ is found, but the rule doesn't allow +domain+. + def self.parse(name, list: List.default, default_rule: list.default_rule, ignore_private: false) + what = normalize(name) + raise what if what.is_a?(DomainInvalid) + + rule = list.find(what, default: default_rule, ignore_private: ignore_private) + + # rubocop:disable Style/IfUnlessModifier + if rule.nil? + raise DomainInvalid, "`#{what}` is not a valid domain" + end + if rule.decompose(what).last.nil? + raise DomainNotAllowed, "`#{what}` is not allowed according to Registry policy" + end + + # rubocop:enable Style/IfUnlessModifier + + decompose(what, rule) + end + + # Checks whether +domain+ is assigned and allowed, without actually parsing it. + # + # This method doesn't care whether domain is a domain or subdomain. + # The validation is performed using the default {PublicSuffix::List}. + # + # @example Validate a valid domain + # PublicSuffix.valid?("example.com") + # # => true + # + # @example Validate a valid subdomain + # PublicSuffix.valid?("www.example.com") + # # => true + # + # @example Validate a not-listed domain + # PublicSuffix.valid?("example.tldnotlisted") + # # => true + # + # @example Validate a not-listed domain with strict checking (without applying the default * rule) + # PublicSuffix.valid?("example.tldnotlisted") + # # => true + # PublicSuffix.valid?("example.tldnotlisted", default_rule: nil) + # # => false + # + # @example Validate a fully qualified domain + # PublicSuffix.valid?("google.com.") + # # => true + # PublicSuffix.valid?("www.google.com.") + # # => true + # + # @example Check an URL (which is not a valid domain) + # PublicSuffix.valid?("http://www.example.com") + # # => false + # + # + # @param [String, #to_s] name The domain name or fully qualified domain name to validate. + # @param [Boolean] ignore_private + # @return [Boolean] + def self.valid?(name, list: List.default, default_rule: list.default_rule, ignore_private: false) + what = normalize(name) + return false if what.is_a?(DomainInvalid) + + rule = list.find(what, default: default_rule, ignore_private: ignore_private) + + !rule.nil? && !rule.decompose(what).last.nil? + end + + # Attempt to parse the name and returns the domain, if valid. + # + # This method doesn't raise. Instead, it returns nil if the domain is not valid for whatever reason. + # + # @param [String, #to_s] name The domain name or fully qualified domain name to parse. + # @param [PublicSuffix::List] list The rule list to search, defaults to the default {PublicSuffix::List} + # @param [Boolean] ignore_private + # @return [String] + def self.domain(name, **options) + parse(name, **options).domain + rescue PublicSuffix::Error + nil + end + + + # private + + def self.decompose(name, rule) + left, right = rule.decompose(name) + + parts = left.split(DOT) + # If we have 0 parts left, there is just a tld and no domain or subdomain + # If we have 1 part left, there is just a tld, domain and not subdomain + # If we have 2 parts left, the last part is the domain, the other parts (combined) are the subdomain + tld = right + sld = parts.empty? ? nil : parts.pop + trd = parts.empty? ? nil : parts.join(DOT) + + Domain.new(tld, sld, trd) + end + + # Pretend we know how to deal with user input. + def self.normalize(name) + name = name.to_s.dup + name.strip! + name.chomp!(DOT) + name.downcase! + + return DomainInvalid.new("Name is blank") if name.empty? + return DomainInvalid.new("Name starts with a dot") if name.start_with?(DOT) + return DomainInvalid.new("%s is not expected to contain a scheme" % name) if name.include?("://") + + name + end + +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.6/lib/public_suffix/domain.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.6/lib/public_suffix/domain.rb new file mode 100644 index 0000000000..3d65eac7ea --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.6/lib/public_suffix/domain.rb @@ -0,0 +1,235 @@ +# frozen_string_literal: true + +# = Public Suffix +# +# Domain name parser based on the Public Suffix List. +# +# Copyright (c) 2009-2020 Simone Carletti + +module PublicSuffix + + # Domain represents a domain name, composed by a TLD, SLD and TRD. + class Domain + + # Splits a string into the labels, that is the dot-separated parts. + # + # The input is not validated, but it is assumed to be a valid domain name. + # + # @example + # + # name_to_labels('example.com') + # # => ['example', 'com'] + # + # name_to_labels('example.co.uk') + # # => ['example', 'co', 'uk'] + # + # @param name [String, #to_s] The domain name to split. + # @return [Array] + def self.name_to_labels(name) + name.to_s.split(DOT) + end + + + attr_reader :tld, :sld, :trd + + # Creates and returns a new {PublicSuffix::Domain} instance. + # + # @overload initialize(tld) + # Initializes with a +tld+. + # @param [String] tld The TLD (extension) + # @overload initialize(tld, sld) + # Initializes with a +tld+ and +sld+. + # @param [String] tld The TLD (extension) + # @param [String] sld The TRD (domain) + # @overload initialize(tld, sld, trd) + # Initializes with a +tld+, +sld+ and +trd+. + # @param [String] tld The TLD (extension) + # @param [String] sld The SLD (domain) + # @param [String] trd The TRD (subdomain) + # + # @yield [self] Yields on self. + # @yieldparam [PublicSuffix::Domain] self The newly creates instance + # + # @example Initialize with a TLD + # PublicSuffix::Domain.new("com") + # # => # + # + # @example Initialize with a TLD and SLD + # PublicSuffix::Domain.new("com", "example") + # # => # + # + # @example Initialize with a TLD, SLD and TRD + # PublicSuffix::Domain.new("com", "example", "wwww") + # # => # + # + def initialize(*args) + @tld, @sld, @trd = args + yield(self) if block_given? + end + + # Returns a string representation of this object. + # + # @return [String] + def to_s + name + end + + # Returns an array containing the domain parts. + # + # @return [Array] + # + # @example + # + # PublicSuffix::Domain.new("google.com").to_a + # # => [nil, "google", "com"] + # + # PublicSuffix::Domain.new("www.google.com").to_a + # # => [nil, "google", "com"] + # + def to_a + [@trd, @sld, @tld] + end + + # Returns the full domain name. + # + # @return [String] + # + # @example Gets the domain name of a domain + # PublicSuffix::Domain.new("com", "google").name + # # => "google.com" + # + # @example Gets the domain name of a subdomain + # PublicSuffix::Domain.new("com", "google", "www").name + # # => "www.google.com" + # + def name + [@trd, @sld, @tld].compact.join(DOT) + end + + # Returns a domain-like representation of this object + # if the object is a {#domain?}, nil otherwise. + # + # PublicSuffix::Domain.new("com").domain + # # => nil + # + # PublicSuffix::Domain.new("com", "google").domain + # # => "google.com" + # + # PublicSuffix::Domain.new("com", "google", "www").domain + # # => "www.google.com" + # + # This method doesn't validate the input. It handles the domain + # as a valid domain name and simply applies the necessary transformations. + # + # This method returns a FQD, not just the domain part. + # To get the domain part, use #sld (aka second level domain). + # + # PublicSuffix::Domain.new("com", "google", "www").domain + # # => "google.com" + # + # PublicSuffix::Domain.new("com", "google", "www").sld + # # => "google" + # + # @see #domain? + # @see #subdomain + # + # @return [String] + def domain + [@sld, @tld].join(DOT) if domain? + end + + # Returns a subdomain-like representation of this object + # if the object is a {#subdomain?}, nil otherwise. + # + # PublicSuffix::Domain.new("com").subdomain + # # => nil + # + # PublicSuffix::Domain.new("com", "google").subdomain + # # => nil + # + # PublicSuffix::Domain.new("com", "google", "www").subdomain + # # => "www.google.com" + # + # This method doesn't validate the input. It handles the domain + # as a valid domain name and simply applies the necessary transformations. + # + # This method returns a FQD, not just the subdomain part. + # To get the subdomain part, use #trd (aka third level domain). + # + # PublicSuffix::Domain.new("com", "google", "www").subdomain + # # => "www.google.com" + # + # PublicSuffix::Domain.new("com", "google", "www").trd + # # => "www" + # + # @see #subdomain? + # @see #domain + # + # @return [String] + def subdomain + [@trd, @sld, @tld].join(DOT) if subdomain? + end + + # Checks whether self looks like a domain. + # + # This method doesn't actually validate the domain. + # It only checks whether the instance contains + # a value for the {#tld} and {#sld} attributes. + # + # @example + # + # PublicSuffix::Domain.new("com").domain? + # # => false + # + # PublicSuffix::Domain.new("com", "google").domain? + # # => true + # + # PublicSuffix::Domain.new("com", "google", "www").domain? + # # => true + # + # # This is an invalid domain, but returns true + # # because this method doesn't validate the content. + # PublicSuffix::Domain.new("com", nil).domain? + # # => true + # + # @see #subdomain? + # + # @return [Boolean] + def domain? + !(@tld.nil? || @sld.nil?) + end + + # Checks whether self looks like a subdomain. + # + # This method doesn't actually validate the subdomain. + # It only checks whether the instance contains + # a value for the {#tld}, {#sld} and {#trd} attributes. + # If you also want to validate the domain, + # use {#valid_subdomain?} instead. + # + # @example + # + # PublicSuffix::Domain.new("com").subdomain? + # # => false + # + # PublicSuffix::Domain.new("com", "google").subdomain? + # # => false + # + # PublicSuffix::Domain.new("com", "google", "www").subdomain? + # # => true + # + # # This is an invalid domain, but returns true + # # because this method doesn't validate the content. + # PublicSuffix::Domain.new("com", "example", nil).subdomain? + # # => true + # + # @see #domain? + # + # @return [Boolean] + def subdomain? + !(@tld.nil? || @sld.nil? || @trd.nil?) + end + + end + +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.6/lib/public_suffix/errors.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.6/lib/public_suffix/errors.rb new file mode 100644 index 0000000000..2d5798def6 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.6/lib/public_suffix/errors.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +# = Public Suffix +# +# Domain name parser based on the Public Suffix List. +# +# Copyright (c) 2009-2020 Simone Carletti + +module PublicSuffix + + class Error < StandardError + end + + # Raised when trying to parse an invalid name. + # A name is considered invalid when no rule is found in the definition list. + # + # @example + # + # PublicSuffix.parse("nic.test") + # # => PublicSuffix::DomainInvalid + # + # PublicSuffix.parse("http://www.nic.it") + # # => PublicSuffix::DomainInvalid + # + class DomainInvalid < Error + end + + # Raised when trying to parse a name that matches a suffix. + # + # @example + # + # PublicSuffix.parse("nic.do") + # # => PublicSuffix::DomainNotAllowed + # + # PublicSuffix.parse("www.nic.do") + # # => PublicSuffix::Domain + # + class DomainNotAllowed < DomainInvalid + end + +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.6/lib/public_suffix/list.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.6/lib/public_suffix/list.rb new file mode 100644 index 0000000000..321b59a79f --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.6/lib/public_suffix/list.rb @@ -0,0 +1,247 @@ +# frozen_string_literal: true + +# = Public Suffix +# +# Domain name parser based on the Public Suffix List. +# +# Copyright (c) 2009-2020 Simone Carletti + +module PublicSuffix + + # A {PublicSuffix::List} is a collection of one + # or more {PublicSuffix::Rule}. + # + # Given a {PublicSuffix::List}, + # you can add or remove {PublicSuffix::Rule}, + # iterate all items in the list or search for the first rule + # which matches a specific domain name. + # + # # Create a new list + # list = PublicSuffix::List.new + # + # # Push two rules to the list + # list << PublicSuffix::Rule.factory("it") + # list << PublicSuffix::Rule.factory("com") + # + # # Get the size of the list + # list.size + # # => 2 + # + # # Search for the rule matching given domain + # list.find("example.com") + # # => # + # list.find("example.org") + # # => nil + # + # You can create as many {PublicSuffix::List} you want. + # The {PublicSuffix::List.default} rule list is used + # to tokenize and validate a domain. + # + class List + + DEFAULT_LIST_PATH = File.expand_path("../../data/list.txt", __dir__) + + # Gets the default rule list. + # + # Initializes a new {PublicSuffix::List} parsing the content + # of {PublicSuffix::List.default_list_content}, if required. + # + # @return [PublicSuffix::List] + def self.default(**options) + @default ||= parse(File.read(DEFAULT_LIST_PATH), **options) + end + + # Sets the default rule list to +value+. + # + # @param value [PublicSuffix::List] the new list + # @return [PublicSuffix::List] + def self.default=(value) + @default = value + end + + # Parse given +input+ treating the content as Public Suffix List. + # + # See http://publicsuffix.org/format/ for more details about input format. + # + # @param string [#each_line] the list to parse + # @param private_domains [Boolean] whether to ignore the private domains section + # @return [PublicSuffix::List] + def self.parse(input, private_domains: true) + comment_token = "//" + private_token = "===BEGIN PRIVATE DOMAINS===" + section = nil # 1 == ICANN, 2 == PRIVATE + + new do |list| + input.each_line do |line| + line.strip! + case # rubocop:disable Style/EmptyCaseCondition + + # skip blank lines + when line.empty? + next + + # include private domains or stop scanner + when line.include?(private_token) + break if !private_domains + + section = 2 + + # skip comments + when line.start_with?(comment_token) + next + + else + list.add(Rule.factory(line, private: section == 2)) + + end + end + end + end + + + # Initializes an empty {PublicSuffix::List}. + # + # @yield [self] Yields on self. + # @yieldparam [PublicSuffix::List] self The newly created instance. + def initialize + @rules = {} + yield(self) if block_given? + end + + + # Checks whether two lists are equal. + # + # List one is equal to two, if two is an instance of + # {PublicSuffix::List} and each +PublicSuffix::Rule::*+ + # in list one is available in list two, in the same order. + # + # @param other [PublicSuffix::List] the List to compare + # @return [Boolean] + def ==(other) + return false unless other.is_a?(List) + + equal?(other) || @rules == other.rules + end + alias eql? == + + # Iterates each rule in the list. + def each(&block) + Enumerator.new do |y| + @rules.each do |key, node| + y << entry_to_rule(node, key) + end + end.each(&block) + end + + + # Adds the given object to the list and optionally refreshes the rule index. + # + # @param rule [PublicSuffix::Rule::*] the rule to add to the list + # @return [self] + def add(rule) + @rules[rule.value] = rule_to_entry(rule) + self + end + alias << add + + # Gets the number of rules in the list. + # + # @return [Integer] + def size + @rules.size + end + + # Checks whether the list is empty. + # + # @return [Boolean] + def empty? + @rules.empty? + end + + # Removes all rules. + # + # @return [self] + def clear + @rules.clear + self + end + + # Finds and returns the rule corresponding to the longest public suffix for the hostname. + # + # @param name [#to_s] the hostname + # @param default [PublicSuffix::Rule::*] the default rule to return in case no rule matches + # @return [PublicSuffix::Rule::*] + def find(name, default: default_rule, **options) + rule = select(name, **options).inject do |l, r| + return r if r.class == Rule::Exception + + l.length > r.length ? l : r + end + rule || default + end + + # Selects all the rules matching given hostame. + # + # If `ignore_private` is set to true, the algorithm will skip the rules that are flagged as + # private domain. Note that the rules will still be part of the loop. + # If you frequently need to access lists ignoring the private domains, + # you should create a list that doesn't include these domains setting the + # `private_domains: false` option when calling {.parse}. + # + # Note that this method is currently private, as you should not rely on it. Instead, + # the public interface is {#find}. The current internal algorithm allows to return all + # matching rules, but different data structures may not be able to do it, and instead would + # return only the match. For this reason, you should rely on {#find}. + # + # @param name [#to_s] the hostname + # @param ignore_private [Boolean] + # @return [Array] + def select(name, ignore_private: false) + name = name.to_s + + parts = name.split(DOT).reverse! + index = 0 + query = parts[index] + rules = [] + + loop do + match = @rules[query] + rules << entry_to_rule(match, query) if !match.nil? && (ignore_private == false || match.private == false) + + index += 1 + break if index >= parts.size + + query = parts[index] + DOT + query + end + + rules + end + private :select + + # Gets the default rule. + # + # @see PublicSuffix::Rule.default_rule + # + # @return [PublicSuffix::Rule::*] + def default_rule + PublicSuffix::Rule.default + end + + + protected + + attr_reader :rules + + + private + + def entry_to_rule(entry, value) + entry.type.new(value: value, length: entry.length, private: entry.private) + end + + def rule_to_entry(rule) + Rule::Entry.new(rule.class, rule.length, rule.private) + end + + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.6/lib/public_suffix/rule.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.6/lib/public_suffix/rule.rb new file mode 100644 index 0000000000..d4c32ca179 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.6/lib/public_suffix/rule.rb @@ -0,0 +1,350 @@ +# frozen_string_literal: true + +# = Public Suffix +# +# Domain name parser based on the Public Suffix List. +# +# Copyright (c) 2009-2020 Simone Carletti + +module PublicSuffix + + # A Rule is a special object which holds a single definition + # of the Public Suffix List. + # + # There are 3 types of rules, each one represented by a specific + # subclass within the +PublicSuffix::Rule+ namespace. + # + # To create a new Rule, use the {PublicSuffix::Rule#factory} method. + # + # PublicSuffix::Rule.factory("ar") + # # => # + # + module Rule + + # @api internal + Entry = Struct.new(:type, :length, :private) # rubocop:disable Lint/StructNewOverride + + # = Abstract rule class + # + # This represent the base class for a Rule definition + # in the {Public Suffix List}[https://publicsuffix.org]. + # + # This is intended to be an Abstract class + # and you shouldn't create a direct instance. The only purpose + # of this class is to expose a common interface + # for all the available subclasses. + # + # * {PublicSuffix::Rule::Normal} + # * {PublicSuffix::Rule::Exception} + # * {PublicSuffix::Rule::Wildcard} + # + # ## Properties + # + # A rule is composed by 4 properties: + # + # value - A normalized version of the rule name. + # The normalization process depends on rule tpe. + # + # Here's an example + # + # PublicSuffix::Rule.factory("*.google.com") + # # + # + # ## Rule Creation + # + # The best way to create a new rule is passing the rule name + # to the PublicSuffix::Rule.factory method. + # + # PublicSuffix::Rule.factory("com") + # # => PublicSuffix::Rule::Normal + # + # PublicSuffix::Rule.factory("*.com") + # # => PublicSuffix::Rule::Wildcard + # + # This method will detect the rule type and create an instance + # from the proper rule class. + # + # ## Rule Usage + # + # A rule describes the composition of a domain name and explains how to tokenize + # the name into tld, sld and trd. + # + # To use a rule, you first need to be sure the name you want to tokenize + # can be handled by the current rule. + # You can use the #match? method. + # + # rule = PublicSuffix::Rule.factory("com") + # + # rule.match?("google.com") + # # => true + # + # rule.match?("google.com") + # # => false + # + # Rule order is significant. A name can match more than one rule. + # See the {Public Suffix Documentation}[http://publicsuffix.org/format/] + # to learn more about rule priority. + # + # When you have the right rule, you can use it to tokenize the domain name. + # + # rule = PublicSuffix::Rule.factory("com") + # + # rule.decompose("google.com") + # # => ["google", "com"] + # + # rule.decompose("www.google.com") + # # => ["www.google", "com"] + # + # @abstract + # + class Base + + # @return [String] the rule definition + attr_reader :value + + # @return [String] the length of the rule + attr_reader :length + + # @return [Boolean] true if the rule is a private domain + attr_reader :private + + + # Initializes a new rule from the content. + # + # @param content [String] the content of the rule + # @param private [Boolean] + def self.build(content, private: false) + new(value: content, private: private) + end + + # Initializes a new rule. + # + # @param value [String] + # @param private [Boolean] + def initialize(value:, length: nil, private: false) + @value = value.to_s + @length = length || @value.count(DOT) + 1 + @private = private + end + + # Checks whether this rule is equal to other. + # + # @param [PublicSuffix::Rule::*] other The rule to compare + # @return [Boolean] + # Returns true if this rule and other are instances of the same class + # and has the same value, false otherwise. + def ==(other) + equal?(other) || (self.class == other.class && value == other.value) + end + alias eql? == + + # Checks if this rule matches +name+. + # + # A domain name is said to match a rule if and only if + # all of the following conditions are met: + # + # - When the domain and rule are split into corresponding labels, + # that the domain contains as many or more labels than the rule. + # - Beginning with the right-most labels of both the domain and the rule, + # and continuing for all labels in the rule, one finds that for every pair, + # either they are identical, or that the label from the rule is "*". + # + # @see https://publicsuffix.org/list/ + # + # @example + # PublicSuffix::Rule.factory("com").match?("example.com") + # # => true + # PublicSuffix::Rule.factory("com").match?("example.net") + # # => false + # + # @param name [String] the domain name to check + # @return [Boolean] + def match?(name) + # Note: it works because of the assumption there are no + # rules like foo.*.com. If the assumption is incorrect, + # we need to properly walk the input and skip parts according + # to wildcard component. + diff = name.chomp(value) + diff.empty? || diff.end_with?(DOT) + end + + # @abstract + def parts + raise NotImplementedError + end + + # @abstract + # @param [String, #to_s] name The domain name to decompose + # @return [Array] + def decompose(*) + raise NotImplementedError + end + + end + + # Normal represents a standard rule (e.g. com). + class Normal < Base + + # Gets the original rule definition. + # + # @return [String] The rule definition. + def rule + value + end + + # Decomposes the domain name according to rule properties. + # + # @param [String, #to_s] name The domain name to decompose + # @return [Array] The array with [trd + sld, tld]. + def decompose(domain) + suffix = parts.join('\.') + matches = domain.to_s.match(/^(.*)\.(#{suffix})$/) + matches ? matches[1..2] : [nil, nil] + end + + # dot-split rule value and returns all rule parts + # in the order they appear in the value. + # + # @return [Array] + def parts + @value.split(DOT) + end + + end + + # Wildcard represents a wildcard rule (e.g. *.co.uk). + class Wildcard < Base + + # Initializes a new rule from the content. + # + # @param content [String] the content of the rule + # @param private [Boolean] + def self.build(content, private: false) + new(value: content.to_s[2..-1], private: private) + end + + # Initializes a new rule. + # + # @param value [String] + # @param private [Boolean] + def initialize(value:, length: nil, private: false) + super(value: value, length: length, private: private) + length or @length += 1 # * counts as 1 + end + + # Gets the original rule definition. + # + # @return [String] The rule definition. + def rule + value == "" ? STAR : STAR + DOT + value + end + + # Decomposes the domain name according to rule properties. + # + # @param [String, #to_s] name The domain name to decompose + # @return [Array] The array with [trd + sld, tld]. + def decompose(domain) + suffix = ([".*?"] + parts).join('\.') + matches = domain.to_s.match(/^(.*)\.(#{suffix})$/) + matches ? matches[1..2] : [nil, nil] + end + + # dot-split rule value and returns all rule parts + # in the order they appear in the value. + # + # @return [Array] + def parts + @value.split(DOT) + end + + end + + # Exception represents an exception rule (e.g. !parliament.uk). + class Exception < Base + + # Initializes a new rule from the content. + # + # @param content [String] the content of the rule + # @param private [Boolean] + def self.build(content, private: false) + new(value: content.to_s[1..-1], private: private) + end + + # Gets the original rule definition. + # + # @return [String] The rule definition. + def rule + BANG + value + end + + # Decomposes the domain name according to rule properties. + # + # @param [String, #to_s] name The domain name to decompose + # @return [Array] The array with [trd + sld, tld]. + def decompose(domain) + suffix = parts.join('\.') + matches = domain.to_s.match(/^(.*)\.(#{suffix})$/) + matches ? matches[1..2] : [nil, nil] + end + + # dot-split rule value and returns all rule parts + # in the order they appear in the value. + # The leftmost label is not considered a label. + # + # See http://publicsuffix.org/format/: + # If the prevailing rule is a exception rule, + # modify it by removing the leftmost label. + # + # @return [Array] + def parts + @value.split(DOT)[1..-1] + end + + end + + + # Takes the +name+ of the rule, detects the specific rule class + # and creates a new instance of that class. + # The +name+ becomes the rule +value+. + # + # @example Creates a Normal rule + # PublicSuffix::Rule.factory("ar") + # # => # + # + # @example Creates a Wildcard rule + # PublicSuffix::Rule.factory("*.ar") + # # => # + # + # @example Creates an Exception rule + # PublicSuffix::Rule.factory("!congresodelalengua3.ar") + # # => # + # + # @param [String] content The rule content. + # @return [PublicSuffix::Rule::*] A rule instance. + def self.factory(content, private: false) + case content.to_s[0, 1] + when STAR + Wildcard + when BANG + Exception + else + Normal + end.build(content, private: private) + end + + # The default rule to use if no rule match. + # + # The default rule is "*". From https://publicsuffix.org/list/: + # + # > If no rules match, the prevailing rule is "*". + # + # @return [PublicSuffix::Rule::Wildcard] The default rule. + def self.default + factory(STAR) + end + + end + +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.6/lib/public_suffix/version.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.6/lib/public_suffix/version.rb new file mode 100644 index 0000000000..c9f93f10f5 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.6/lib/public_suffix/version.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +# +# = Public Suffix +# +# Domain name parser based on the Public Suffix List. +# +# Copyright (c) 2009-2020 Simone Carletti + +module PublicSuffix + # The current library version. + VERSION = "4.0.6" +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm.rb new file mode 100644 index 0000000000..e085a0d26a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm.rb @@ -0,0 +1,266 @@ +# encoding: UTF-8 +# +# = net/ntlm.rb +# +# An NTLM Authentication Library for Ruby +# +# This code is a derivative of "dbf2.rb" written by yrock +# and Minero Aoki. You can find original code here: +# http://jp.rubyist.net/magazine/?0013-CodeReview +# ------------------------------------------------------------- +# Copyright (c) 2005,2006 yrock +# +# +# 2006-02-11 refactored by Minero Aoki +# ------------------------------------------------------------- +# +# All protocol information used to write this code stems from +# "The NTLM Authentication Protocol" by Eric Glass. The author +# would thank to him for this tremendous work and making it +# available on the net. +# http://davenport.sourceforge.net/ntlm.html +# ------------------------------------------------------------- +# Copyright (c) 2003 Eric Glass +# +# ------------------------------------------------------------- +# +# The author also looked Mozilla-Firefox-1.0.7 source code, +# namely, security/manager/ssl/src/nsNTLMAuthModule.cpp and +# Jonathan Bastien-Filiatrault's libntlm-ruby. +# "http://x2a.org/websvn/filedetails.php? +# repname=libntlm-ruby&path=%2Ftrunk%2Fntlm.rb&sc=1" +# The latter has a minor bug in its separate_keys function. +# The third key has to begin from the 14th character of the +# input string instead of 13th:) +#-- +# $Id: ntlm.rb,v 1.1 2006/10/05 01:36:52 koheik Exp $ +#++ + +require 'base64' +require 'openssl' +require 'openssl/digest' +require 'socket' + +# Load Order is important here +require 'net/ntlm/exceptions' +require 'net/ntlm/field' +require 'net/ntlm/int16_le' +require 'net/ntlm/int32_le' +require 'net/ntlm/int64_le' +require 'net/ntlm/string' + +require 'net/ntlm/field_set' +require 'net/ntlm/blob' +require 'net/ntlm/security_buffer' +require 'net/ntlm/message' +require 'net/ntlm/message/type0' +require 'net/ntlm/message/type1' +require 'net/ntlm/message/type2' +require 'net/ntlm/message/type3' + +require 'net/ntlm/encode_util' + +require 'net/ntlm/client' +require 'net/ntlm/channel_binding' +require 'net/ntlm/target_info' + +module Net + module NTLM + + LM_MAGIC = "KGS!@\#$%" + TIME_OFFSET = 11644473600 + MAX64 = 0xffffffffffffffff + + + class << self + + # Valid format for LAN Manager hex digest portion: 32 hexadecimal characters. + LAN_MANAGER_HEX_DIGEST_REGEXP = /[0-9a-f]{32}/i + # Valid format for NT LAN Manager hex digest portion: 32 hexadecimal characters. + NT_LAN_MANAGER_HEX_DIGEST_REGEXP = /[0-9a-f]{32}/i + # Valid format for an NTLM hash composed of `':'`. + DATA_REGEXP = /\A#{LAN_MANAGER_HEX_DIGEST_REGEXP}:#{NT_LAN_MANAGER_HEX_DIGEST_REGEXP}\z/ + + # Takes a string and determines whether it is a valid NTLM Hash + # @param [String] the string to validate + # @return [Boolean] whether or not the string is a valid NTLM hash + def is_ntlm_hash?(data) + decoded_data = data.dup + decoded_data = EncodeUtil.decode_utf16le(decoded_data) + if DATA_REGEXP.match(decoded_data) + true + else + false + end + end + + # Conver the value to a 64-Bit Little Endian Int + # @param [String] val The string to convert + def pack_int64le(val) + [val & 0x00000000ffffffff, val >> 32].pack("V2") + end + + # Builds an array of strings that are 7 characters long + # @param [String] str The string to split + # @api private + def split7(str) + s = str.dup + until s.empty? + (ret ||= []).push s.slice!(0, 7) + end + ret + end + + # Not sure what this is doing + # @param [String] str String to generate keys for + # @api private + def gen_keys(str) + split7(str).map{ |str7| + bits = split7(str7.unpack("B*")[0]).inject('')\ + {|ret, tkn| ret += tkn + (tkn.gsub('1', '').size % 2).to_s } + [bits].pack("B*") + } + end + + def apply_des(plain, keys) + dec = OpenSSL::Cipher.new("des-cbc").encrypt + dec.padding = 0 + keys.map {|k| + dec.key = k + dec.update(plain) + dec.final + } + end + + # Generates a Lan Manager Hash + # @param [String] password The password to base the hash on + def lm_hash(password) + keys = gen_keys password.upcase.ljust(14, "\0") + apply_des(LM_MAGIC, keys).join + end + + # Generate a NTLM Hash + # @param [String] password The password to base the hash on + # @option opt :unicode (false) Unicode encode the password + def ntlm_hash(password, opt = {}) + pwd = password.dup + unless opt[:unicode] + pwd = EncodeUtil.encode_utf16le(pwd) + end + OpenSSL::Digest::MD4.digest pwd + end + + # Generate a NTLMv2 Hash + # @param [String] user The username + # @param [String] password The password + # @param [String] target The domain or workstation to authenticate to + # @option opt :unicode (false) Unicode encode the domain + def ntlmv2_hash(user, password, target, opt={}) + if is_ntlm_hash? password + decoded_password = EncodeUtil.decode_utf16le(password) + ntlmhash = [decoded_password.upcase[33,65]].pack('H32') + else + ntlmhash = ntlm_hash(password, opt) + end + userdomain = user.upcase + target + unless opt[:unicode] + userdomain = EncodeUtil.encode_utf16le(userdomain) + end + OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmhash, userdomain) + end + + def lm_response(arg) + begin + hash = arg[:lm_hash] + chal = arg[:challenge] + rescue + raise ArgumentError + end + chal = NTLM::pack_int64le(chal) if chal.is_a?(Integer) + keys = gen_keys hash.ljust(21, "\0") + apply_des(chal, keys).join + end + + def ntlm_response(arg) + hash = arg[:ntlm_hash] + chal = arg[:challenge] + chal = NTLM::pack_int64le(chal) if chal.is_a?(Integer) + keys = gen_keys hash.ljust(21, "\0") + apply_des(chal, keys).join + end + + def ntlmv2_response(arg, opt = {}) + begin + key = arg[:ntlmv2_hash] + chal = arg[:challenge] + ti = arg[:target_info] + rescue + raise ArgumentError + end + chal = NTLM::pack_int64le(chal) if chal.is_a?(Integer) + + if opt[:client_challenge] + cc = opt[:client_challenge] + else + cc = rand(MAX64) + end + cc = NTLM::pack_int64le(cc) if cc.is_a?(Integer) + + if opt[:timestamp] + ts = opt[:timestamp] + else + ts = Time.now.to_i + end + # epoch -> milsec from Jan 1, 1601 + ts = 10_000_000 * (ts + TIME_OFFSET) + + blob = Blob.new + blob.timestamp = ts + blob.challenge = cc + blob.target_info = ti + + bb = blob.serialize + + OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, key, chal + bb) + bb + end + + def lmv2_response(arg, opt = {}) + key = arg[:ntlmv2_hash] + chal = arg[:challenge] + + chal = NTLM::pack_int64le(chal) if chal.is_a?(Integer) + + if opt[:client_challenge] + cc = opt[:client_challenge] + else + cc = rand(MAX64) + end + cc = NTLM::pack_int64le(cc) if cc.is_a?(Integer) + + OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, key, chal + cc) + cc + end + + def ntlm2_session(arg, opt = {}) + begin + passwd_hash = arg[:ntlm_hash] + chal = arg[:challenge] + rescue + raise ArgumentError + end + chal = NTLM::pack_int64le(chal) if chal.is_a?(Integer) + + if opt[:client_challenge] + cc = opt[:client_challenge] + else + cc = rand(MAX64) + end + cc = NTLM::pack_int64le(cc) if cc.is_a?(Integer) + + keys = gen_keys(passwd_hash.ljust(21, "\0")) + session_hash = OpenSSL::Digest::MD5.digest(chal + cc).slice(0, 8) + response = apply_des(session_hash, keys).join + [cc.ljust(24, "\0"), response] + end + end + + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/blob.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/blob.rb new file mode 100644 index 0000000000..f670eb3d39 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/blob.rb @@ -0,0 +1,28 @@ +module Net + module NTLM + + BLOB_SIGN = 0x00000101 + + class Blob < FieldSet + int32LE :blob_signature, {:value => BLOB_SIGN} + int32LE :reserved, {:value => 0} + int64LE :timestamp, {:value => 0} + string :challenge, {:value => "", :size => 8} + int32LE :unknown1, {:value => 0} + string :target_info, {:value => "", :size => 0} + int32LE :unknown2, {:value => 0} + + def parse(str, offset=0) + # 28 is the length of all fields before the variable-length + # target_info field. + if str.size > 28 + enable(:target_info) + # Grab everything except the last 4 bytes (which will be :unknown2) + self[:target_info].value = str[28..-5] + end + super + end + end + + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/channel_binding.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/channel_binding.rb new file mode 100644 index 0000000000..fda9c6355b --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/channel_binding.rb @@ -0,0 +1,65 @@ +module Net + module NTLM + class ChannelBinding + + # Creates a ChannelBinding used for Extended Protection Authentication + # @see http://blogs.msdn.com/b/openspecification/archive/2013/03/26/ntlm-and-channel-binding-hash-aka-exteneded-protection-for-authentication.aspx + # + # @param outer_channel [OpenSSL::X509::Certificate] Server certificate securing + # the outer TLS channel + # @return [NTLM::ChannelBinding] A ChannelBinding holding a token that can be + # embedded in a {Type3} message + def self.create(outer_channel) + new(outer_channel) + end + + # @param outer_channel [OpenSSL::X509::Certificate] Server certificate securing + # the outer TLS channel + def initialize(outer_channel) + @channel = outer_channel + @unique_prefix = 'tls-server-end-point' + @initiator_addtype = 0 + @initiator_address_length = 0 + @acceptor_addrtype = 0 + @acceptor_address_length = 0 + end + + attr_reader :channel, :unique_prefix, :initiator_addtype + attr_reader :initiator_address_length, :acceptor_addrtype + attr_reader :acceptor_address_length + + # Returns a channel binding hash acceptable for use as a AV_PAIR MsvAvChannelBindings + # field value as specified in the NTLM protocol + # + # @return [String] MD5 hash of gss_channel_bindings_struct + def channel_binding_token + @channel_binding_token ||= OpenSSL::Digest::MD5.new(gss_channel_bindings_struct).digest + end + + def gss_channel_bindings_struct + @gss_channel_bindings_struct ||= begin + token = [initiator_addtype].pack('I') + token << [initiator_address_length].pack('I') + token << [acceptor_addrtype].pack('I') + token << [acceptor_address_length].pack('I') + token << [application_data.length].pack('I') + token << application_data + token + end + end + + def channel_hash + @channel_hash ||= OpenSSL::Digest::SHA256.new(channel.to_der) + end + + def application_data + @application_data ||= begin + data = unique_prefix + data << ':' + data << channel_hash.digest + data + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/client.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/client.rb new file mode 100644 index 0000000000..91d0895c68 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/client.rb @@ -0,0 +1,65 @@ +module Net + module NTLM + class Client + + DEFAULT_FLAGS = NTLM::FLAGS[:UNICODE] | NTLM::FLAGS[:OEM] | + NTLM::FLAGS[:SIGN] | NTLM::FLAGS[:SEAL] | NTLM::FLAGS[:REQUEST_TARGET] | + NTLM::FLAGS[:NTLM] | NTLM::FLAGS[:ALWAYS_SIGN] | NTLM::FLAGS[:NTLM2_KEY] | + NTLM::FLAGS[:KEY128] | NTLM::FLAGS[:KEY_EXCHANGE] | NTLM::FLAGS[:KEY56] + + attr_reader :username, :password, :domain, :workstation, :flags + + # @note All string parameters should be encoded in UTF-8. The proper + # final encoding for placing in the various {Message messages} will be + # chosen based on negotiation with the server. + # + # @param username [String] + # @param password [String] + # @option opts [String] :domain where we're authenticating to + # @option opts [String] :workstation local workstation name + # @option opts [Fixnum] :flags (DEFAULT_FLAGS) see Net::NTLM::Message::Type1.flag + def initialize(username, password, opts = {}) + @username = username + @password = password + @domain = opts[:domain] || nil + @workstation = opts[:workstation] || nil + @flags = opts[:flags] || DEFAULT_FLAGS + end + + # @return [NTLM::Message] + def init_context(resp = nil, channel_binding = nil) + if resp.nil? + @session = nil + type1_message + else + @session = Client::Session.new(self, Net::NTLM::Message.decode64(resp), channel_binding) + @session.authenticate! + end + end + + # @return [Client::Session] + def session + @session + end + + def session_key + @session.exported_session_key + end + + private + + # @return [Message::Type1] + def type1_message + type1 = Message::Type1.new + type1[:flag].value = flags + type1.domain = domain if domain + type1.workstation = workstation if workstation + + type1 + end + + end + end +end + +require "net/ntlm/client/session" diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/client/session.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/client/session.rb new file mode 100644 index 0000000000..b1b496a0b7 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/client/session.rb @@ -0,0 +1,237 @@ +module Net + module NTLM + class Client::Session + + VERSION_MAGIC = "\x01\x00\x00\x00" + TIME_OFFSET = 11644473600 + MAX64 = 0xffffffffffffffff + CLIENT_TO_SERVER_SIGNING = "session key to client-to-server signing key magic constant\0" + SERVER_TO_CLIENT_SIGNING = "session key to server-to-client signing key magic constant\0" + CLIENT_TO_SERVER_SEALING = "session key to client-to-server sealing key magic constant\0" + SERVER_TO_CLIENT_SEALING = "session key to server-to-client sealing key magic constant\0" + + attr_reader :client, :challenge_message, :channel_binding + + # @param client [Net::NTLM::Client] the client instance + # @param challenge_message [Net::NTLM::Message::Type2] server message + def initialize(client, challenge_message, channel_binding = nil) + @client = client + @challenge_message = challenge_message + @channel_binding = channel_binding + end + + # Generate an NTLMv2 AUTHENTICATE_MESSAGE + # @see http://msdn.microsoft.com/en-us/library/cc236643.aspx + # @return [Net::NTLM::Message::Type3] + def authenticate! + calculate_user_session_key! + type3_opts = { + :lm_response => lmv2_resp, + :ntlm_response => ntlmv2_resp, + :domain => domain, + :user => username, + :workstation => workstation, + :flag => (challenge_message.flag & client.flags) + } + t3 = Message::Type3.create type3_opts + if negotiate_key_exchange? + t3.enable(:session_key) + rc4 = OpenSSL::Cipher.new("rc4") + rc4.encrypt + rc4.key = user_session_key + sk = rc4.update exported_session_key + sk << rc4.final + t3.session_key = sk + end + t3 + end + + def exported_session_key + @exported_session_key ||= + begin + if negotiate_key_exchange? + OpenSSL::Cipher.new("rc4").random_key + else + user_session_key + end + end + end + + def sign_message(message) + seq = sequence + sig = OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, client_sign_key, "#{seq}#{message}")[0..7] + if negotiate_key_exchange? + sig = client_cipher.update sig + sig << client_cipher.final + end + "#{VERSION_MAGIC}#{sig}#{seq}" + end + + def verify_signature(signature, message) + seq = signature[-4..-1] + sig = OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, server_sign_key, "#{seq}#{message}")[0..7] + if negotiate_key_exchange? + sig = server_cipher.update sig + sig << server_cipher.final + end + "#{VERSION_MAGIC}#{sig}#{seq}" == signature + end + + def seal_message(message) + emessage = client_cipher.update(message) + emessage + client_cipher.final + end + + def unseal_message(emessage) + message = server_cipher.update(emessage) + message + server_cipher.final + end + + private + + + def user_session_key + @user_session_key ||= nil + end + + def sequence + [raw_sequence].pack("V*") + end + + def raw_sequence + if defined? @raw_sequence + @raw_sequence += 1 + else + @raw_sequence = 0 + end + end + + def client_sign_key + @client_sign_key ||= OpenSSL::Digest::MD5.digest "#{exported_session_key}#{CLIENT_TO_SERVER_SIGNING}" + end + + def server_sign_key + @server_sign_key ||= OpenSSL::Digest::MD5.digest "#{exported_session_key}#{SERVER_TO_CLIENT_SIGNING}" + end + + def client_seal_key + @client_seal_key ||= OpenSSL::Digest::MD5.digest "#{exported_session_key}#{CLIENT_TO_SERVER_SEALING}" + end + + def server_seal_key + @server_seal_key ||= OpenSSL::Digest::MD5.digest "#{exported_session_key}#{SERVER_TO_CLIENT_SEALING}" + end + + def client_cipher + @client_cipher ||= + begin + rc4 = OpenSSL::Cipher.new("rc4") + rc4.encrypt + rc4.key = client_seal_key + rc4 + end + end + + def server_cipher + @server_cipher ||= + begin + rc4 = OpenSSL::Cipher.new("rc4") + rc4.decrypt + rc4.key = server_seal_key + rc4 + end + end + + def client_challenge + @client_challenge ||= NTLM.pack_int64le(rand(MAX64)) + end + + def server_challenge + @server_challenge ||= challenge_message[:challenge].serialize + end + + # epoch -> milsec from Jan 1, 1601 + # @see http://support.microsoft.com/kb/188768 + def timestamp + @timestamp ||= 10_000_000 * (Time.now.to_i + TIME_OFFSET) + end + + def use_oem_strings? + challenge_message.has_flag? :OEM + end + + def negotiate_key_exchange? + challenge_message.has_flag? :KEY_EXCHANGE + end + + def username + oem_or_unicode_str client.username + end + + def password + oem_or_unicode_str client.password + end + + def workstation + (client.workstation ? oem_or_unicode_str(client.workstation) : "") + end + + def domain + (client.domain ? oem_or_unicode_str(client.domain) : "") + end + + def oem_or_unicode_str(str) + if use_oem_strings? + NTLM::EncodeUtil.decode_utf16le str + else + NTLM::EncodeUtil.encode_utf16le str + end + end + + def ntlmv2_hash + @ntlmv2_hash ||= NTLM.ntlmv2_hash(username, password, domain, {:client_challenge => client_challenge, :unicode => !use_oem_strings?}) + end + + def calculate_user_session_key! + @user_session_key = OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmv2_hash, nt_proof_str) + end + + def lmv2_resp + OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmv2_hash, server_challenge + client_challenge) + client_challenge + end + + def ntlmv2_resp + nt_proof_str + blob + end + + def nt_proof_str + @nt_proof_str ||= OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmv2_hash, server_challenge + blob) + end + + def blob + @blob ||= + begin + b = Blob.new + b.timestamp = timestamp + b.challenge = client_challenge + b.target_info = target_info + b.serialize + end + end + + def target_info + @target_info ||= begin + if channel_binding + t = Net::NTLM::TargetInfo.new(challenge_message.target_info) + av_id = Net::NTLM::TargetInfo::MSV_AV_CHANNEL_BINDINGS + t.av_pairs[av_id] = channel_binding.channel_binding_token + t.to_s + else + challenge_message.target_info + end + end + end + + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/encode_util.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/encode_util.rb new file mode 100644 index 0000000000..5a13e7866f --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/encode_util.rb @@ -0,0 +1,48 @@ +module Net +module NTLM + + class EncodeUtil + if RUBY_VERSION == "1.8.7" + require "kconv" + + # Decode a UTF16 string to a ASCII string + # @param [String] str The string to convert + def self.decode_utf16le(str) + Kconv.kconv(swap16(str), Kconv::ASCII, Kconv::UTF16) + end + + # Encodes a ASCII string to a UTF16 string + # @param [String] str The string to convert + def self.encode_utf16le(str) + swap16(Kconv.kconv(str, Kconv::UTF16, Kconv::ASCII)) + end + + # Taggle the strings endianness between big/little and little/big + # @param [String] str The string to swap the endianness on + def self.swap16(str) + str.unpack("v*").pack("n*") + end + else # Use native 1.9 string encoding functions + + # Decode a UTF16 string to a ASCII string + # @param [String] str The string to convert + def self.decode_utf16le(str) + str = str.dup.force_encoding(Encoding::UTF_16LE) + str.encode(Encoding::UTF_8, Encoding::UTF_16LE).force_encoding('UTF-8') + end + + # Encodes a ASCII string to a UTF16 string + # @param [String] str The string to convert + # @note This implementation may seem stupid but the problem is that UTF16-LE and UTF-8 are incompatiable + # encodings. This library uses string contatination to build the packet bytes. The end result is that + # you can either marshal the encodings elsewhere of simply know that each time you call encode_utf16le + # the function will convert the string bytes to UTF-16LE and note the encoding as UTF-8 so that byte + # concatination works seamlessly. + def self.encode_utf16le(str) + str.dup.force_encoding('UTF-8').encode(Encoding::UTF_16LE, Encoding::UTF_8).force_encoding('UTF-8') + end + end + end + +end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/exceptions.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/exceptions.rb new file mode 100644 index 0000000000..12f52015b2 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/exceptions.rb @@ -0,0 +1,14 @@ +module Net + module NTLM + class NtlmError < StandardError; end + + class InvalidTargetDataError < NtlmError + attr_reader :data + + def initialize(msg, data) + @data = data + super(msg) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/field.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/field.rb new file mode 100644 index 0000000000..3109bd7dba --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/field.rb @@ -0,0 +1,35 @@ +module Net +module NTLM + + # base classes for primitives + # @private + class Field + attr_accessor :active, :value + + def initialize(opts) + @value = opts[:value] + @active = opts[:active].nil? ? true : opts[:active] + @size = opts[:size].nil? ? 0 : opts[:size] + end + + def size + @active ? @size : 0 + end + + # Serializer function for field data + # Exists in this class to be overridden by child classes + def serialize + raise NotImplementedError + end + + # Parser function for field data + # Exists in this class to be overridden by child classes + def parse(str, offset=0) + raise NotImplementedError + end + + end + + +end +end \ No newline at end of file diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/field_set.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/field_set.rb new file mode 100644 index 0000000000..e79cc66f12 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/field_set.rb @@ -0,0 +1,129 @@ +module Net + module NTLM + + # base class of data structure + class FieldSet + class << FieldSet + + # @macro string_security_buffer + # @method $1 + # @method $1= + # @return [String] + def string(name, opts) + add_field(name, Net::NTLM::String, opts) + end + + # @macro int16le_security_buffer + # @method $1 + # @method $1= + # @return [Int16LE] + def int16LE(name, opts) + add_field(name, Net::NTLM::Int16LE, opts) + end + + # @macro int32le_security_buffer + # @method $1 + # @method $1= + # @return [Int32LE] + def int32LE(name, opts) + add_field(name, Net::NTLM::Int32LE, opts) + end + + # @macro int64le_security_buffer + # @method $1 + # @method $1= + # @return [Int64] + def int64LE(name, opts) + add_field(name, Net::NTLM::Int64LE, opts) + end + + # @macro security_buffer + # @method $1 + # @method $1= + # @return [SecurityBuffer] + def security_buffer(name, opts) + add_field(name, Net::NTLM::SecurityBuffer, opts) + end + + def prototypes + @proto + end + + def names + return [] if @proto.nil? + @proto.map{|n, t, o| n} + end + + def types + return [] if @proto.nil? + @proto.map{|n, t, o| t} + end + + def opts + return [] if @proto.nil? + @proto.map{|n, t, o| o} + end + + private + + def add_field(name, type, opts) + (@proto ||= []).push [name, type, opts] + define_accessor name + end + + def define_accessor(name) + module_eval(<<-End, __FILE__, __LINE__ + 1) + def #{name} + self['#{name}'].value + end + + def #{name}=(val) + self['#{name}'].value = val + end + End + end + end + + def initialize + @alist = self.class.prototypes.map{ |n, t, o| [n, t.new(o)] } + end + + def parse(str, offset=0) + @alist.inject(offset){|cur, a| cur += a[1].parse(str, cur)} + end + + def serialize + @alist.map{|n, f| f.serialize }.join + end + + def size + @alist.inject(0){|sum, a| sum += a[1].size} + end + + def [](name) + a = @alist.assoc(name.to_s.intern) + raise ArgumentError, "no such field: #{name}" unless a + a[1] + end + + def []=(name, val) + a = @alist.assoc(name.to_s.intern) + raise ArgumentError, "no such field: #{name}" unless a + a[1] = val + end + + def enable(name) + self[name].active = true + end + + def disable(name) + self[name].active = false + end + + def has_disabled_fields? + @alist.any? { |name, field| !field.active } + end + end + + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/int16_le.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/int16_le.rb new file mode 100644 index 0000000000..e9fb45bf85 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/int16_le.rb @@ -0,0 +1,26 @@ +module Net + module NTLM + + class Int16LE < Field + + def initialize(opt) + super(opt) + @size = 2 + end + + def parse(str, offset=0) + if @active and str.size >= offset + @size + @value = str[offset, @size].unpack("v")[0] + @size + else + 0 + end + end + + def serialize + [@value].pack("v") + end + end + + end +end \ No newline at end of file diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/int32_le.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/int32_le.rb new file mode 100644 index 0000000000..789013388b --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/int32_le.rb @@ -0,0 +1,25 @@ +module Net + module NTLM + + class Int32LE < Field + def initialize(opt) + super(opt) + @size = 4 + end + + def parse(str, offset=0) + if @active and str.size >= offset + @size + @value = str.slice(offset, @size).unpack("V")[0] + @size + else + 0 + end + end + + def serialize + [@value].pack("V") if @active + end + end + + end +end \ No newline at end of file diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/int64_le.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/int64_le.rb new file mode 100644 index 0000000000..37bc75537d --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/int64_le.rb @@ -0,0 +1,26 @@ +module Net + module NTLM + + class Int64LE < Field + def initialize(opt) + super(opt) + @size = 8 + end + + def parse(str, offset=0) + if @active and str.size >= offset + @size + d, u = str.slice(offset, @size).unpack("V2") + @value = (u * 0x100000000 + d) + @size + else + 0 + end + end + + def serialize + [@value & 0x00000000ffffffff, @value >> 32].pack("V2") if @active + end + end + + end +end \ No newline at end of file diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/message.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/message.rb new file mode 100644 index 0000000000..eba8bc13b3 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/message.rb @@ -0,0 +1,129 @@ +module Net +module NTLM + + SSP_SIGN = "NTLMSSP\0" + + FLAGS = { + :UNICODE => 0x00000001, + :OEM => 0x00000002, + :REQUEST_TARGET => 0x00000004, + :MBZ9 => 0x00000008, + :SIGN => 0x00000010, + :SEAL => 0x00000020, + :NEG_DATAGRAM => 0x00000040, + :NETWARE => 0x00000100, + :NTLM => 0x00000200, + :NEG_NT_ONLY => 0x00000400, + :MBZ7 => 0x00000800, + :DOMAIN_SUPPLIED => 0x00001000, + :WORKSTATION_SUPPLIED => 0x00002000, + :LOCAL_CALL => 0x00004000, + :ALWAYS_SIGN => 0x00008000, + :TARGET_TYPE_DOMAIN => 0x00010000, + :NTLM2_KEY => 0x00080000, + :TARGET_INFO => 0x00800000, + :KEY128 => 0x20000000, + :KEY_EXCHANGE => 0x40000000, + :KEY56 => 0x80000000 + }.freeze + + FLAG_KEYS = FLAGS.keys.sort{|a, b| FLAGS[a] <=> FLAGS[b] } + + DEFAULT_FLAGS = { + :TYPE1 => FLAGS[:UNICODE] | FLAGS[:OEM] | FLAGS[:REQUEST_TARGET] | FLAGS[:NTLM] | FLAGS[:ALWAYS_SIGN] | FLAGS[:NTLM2_KEY], + :TYPE2 => FLAGS[:UNICODE], + :TYPE3 => FLAGS[:UNICODE] | FLAGS[:REQUEST_TARGET] | FLAGS[:NTLM] | FLAGS[:ALWAYS_SIGN] | FLAGS[:NTLM2_KEY] + } + + + # @private false + class Message < FieldSet + class << Message + def parse(str) + m = Type0.new + m.parse(str) + case m.type + when 1 + t = Type1.new.parse(str) + when 2 + t = Type2.new.parse(str) + when 3 + t = Type3.new.parse(str) + else + raise ArgumentError, "unknown type: #{m.type}" + end + t + end + + def decode64(str) + parse(Base64.decode64(str)) + end + end + + # @return [self] + def parse(str) + super + + while has_disabled_fields? && serialize.size < str.size + # enable the next disabled field + self.class.names.find { |name| !self[name].active && enable(name) } + super + end + + self + end + + def has_flag?(flag) + (self[:flag].value & FLAGS[flag]) == FLAGS[flag] + end + + def set_flag(flag) + self[:flag].value |= FLAGS[flag] + end + + def dump_flags + FLAG_KEYS.each{ |k| print(k, "=", has_flag?(k), "\n") } + end + + def serialize + deflag + super + security_buffers.map{|n, f| f.value}.join + end + + def encode64 + Base64.encode64(serialize).gsub(/\n/, '') + end + + def decode64(str) + parse(Base64.decode64(str)) + end + + alias head_size size + + def data_size + security_buffers.inject(0){|sum, a| sum += a[1].data_size} + end + + def size + head_size + data_size + end + + + def security_buffers + @alist.find_all{|n, f| f.instance_of?(SecurityBuffer)} + end + + def deflag + security_buffers.inject(head_size){|cur, a| + a[1].offset = cur + cur += a[1].data_size + } + end + + def data_edge + security_buffers.map{ |n, f| f.active ? f.offset : size}.min + end + + end +end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/message/type0.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/message/type0.rb new file mode 100644 index 0000000000..02334c0def --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/message/type0.rb @@ -0,0 +1,16 @@ +module Net + module NTLM + class Message + + # sub class definitions + class Type0 < Message + string :sign, {:size => 8, :value => SSP_SIGN} + int32LE :type, {:value => 0} + end + + + end + end +end + + diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/message/type1.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/message/type1.rb new file mode 100644 index 0000000000..83a8efd773 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/message/type1.rb @@ -0,0 +1,18 @@ +module Net + module NTLM + class Message + + # @private false + class Type1 < Message + + string :sign, {:size => 8, :value => SSP_SIGN} + int32LE :type, {:value => 1} + int32LE :flag, {:value => DEFAULT_FLAGS[:TYPE1] } + security_buffer :domain, {:value => ""} + security_buffer :workstation, {:value => Socket.gethostname } + string :os_version, {:size => 8, :value => "", :active => false } + + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/message/type2.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/message/type2.rb new file mode 100644 index 0000000000..200dd25464 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/message/type2.rb @@ -0,0 +1,102 @@ +module Net + module NTLM + class Message + + # @private false + class Type2 < Message + + string :sign, { :size => 8, :value => SSP_SIGN } + int32LE :type, { :value => 2 } + security_buffer :target_name, { :size => 0, :value => "" } + int32LE :flag, { :value => DEFAULT_FLAGS[:TYPE2] } + int64LE :challenge, { :value => 0} + int64LE :context, { :value => 0, :active => false } + security_buffer :target_info, { :value => "", :active => false } + string :os_version, { :size => 8, :value => "", :active => false } + + # Generates a Type 3 response based on the Type 2 Information + # @return [Type3] + # @option arg [String] :username The username to authenticate with + # @option arg [String] :password The user's password + # @option arg [String] :domain ('') The domain to authenticate to + # @option opt [String] :workstation (Socket.gethostname) The name of the calling workstation + # @option opt [Boolean] :use_default_target (false) Use the domain supplied by the server in the Type 2 packet + # @note An empty :domain option authenticates to the local machine. + # @note The :use_default_target has precedence over the :domain option + def response(arg, opt = {}) + usr = arg[:user] + pwd = arg[:password] + domain = arg[:domain] ? arg[:domain].upcase : "" + if usr.nil? or pwd.nil? + raise ArgumentError, "user and password have to be supplied" + end + + if opt[:workstation] + ws = opt[:workstation] + else + ws = Socket.gethostname + end + + if opt[:client_challenge] + cc = opt[:client_challenge] + else + cc = rand(MAX64) + end + cc = NTLM::pack_int64le(cc) if cc.is_a?(Integer) + opt[:client_challenge] = cc + + if has_flag?(:OEM) and opt[:unicode] + usr = NTLM::EncodeUtil.decode_utf16le(usr) + pwd = NTLM::EncodeUtil.decode_utf16le(pwd) + ws = NTLM::EncodeUtil.decode_utf16le(ws) + domain = NTLM::EncodeUtil.decode_utf16le(domain) + opt[:unicode] = false + end + + if has_flag?(:UNICODE) and !opt[:unicode] + usr = NTLM::EncodeUtil.encode_utf16le(usr) + pwd = NTLM::EncodeUtil.encode_utf16le(pwd) + ws = NTLM::EncodeUtil.encode_utf16le(ws) + domain = NTLM::EncodeUtil.encode_utf16le(domain) + opt[:unicode] = true + end + + if opt[:use_default_target] + domain = self.target_name + end + + ti = self.target_info + + chal = self[:challenge].serialize + + if opt[:ntlmv2] + ar = {:ntlmv2_hash => NTLM::ntlmv2_hash(usr, pwd, domain, opt), :challenge => chal, :target_info => ti} + lm_res = NTLM::lmv2_response(ar, opt) + ntlm_res = NTLM::ntlmv2_response(ar, opt) + elsif has_flag?(:NTLM2_KEY) + ar = {:ntlm_hash => NTLM::ntlm_hash(pwd, opt), :challenge => chal} + lm_res, ntlm_res = NTLM::ntlm2_session(ar, opt) + else + ar = {:lm_hash => NTLM::lm_hash(pwd), :challenge => chal} + lm_res = NTLM::lm_response(ar) + ar = {:ntlm_hash => NTLM::ntlm_hash(pwd, opt), :challenge => chal} + ntlm_res = NTLM::ntlm_response(ar) + end + + Type3.create({ + :lm_response => lm_res, + :ntlm_response => ntlm_res, + :domain => domain, + :user => usr, + :workstation => ws, + :flag => self.flag + }) + end + + end + + end + end +end + + diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/message/type3.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/message/type3.rb new file mode 100644 index 0000000000..88a8774f00 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/message/type3.rb @@ -0,0 +1,131 @@ +module Net + module NTLM + class Message + + # @private false + class Type3 < Message + + string :sign, {:size => 8, :value => SSP_SIGN} + int32LE :type, {:value => 3} + security_buffer :lm_response, {:value => ""} + security_buffer :ntlm_response, {:value => ""} + security_buffer :domain, {:value => ""} + security_buffer :user, {:value => ""} + security_buffer :workstation, {:value => ""} + security_buffer :session_key, {:value => "", :active => false } + int32LE :flag, {:value => 0, :active => false } + string :os_version, {:size => 8, :active => false } + + class << Type3 + # Builds a Type 3 packet + # @note All options must be properly encoded with either unicode or oem encoding + # @return [Type3] + # @option arg [String] :lm_response The LM hash + # @option arg [String] :ntlm_response The NTLM hash + # @option arg [String] :domain The domain to authenticate to + # @option arg [String] :workstation The name of the calling workstation + # @option arg [String] :session_key The session key + # @option arg [Integer] :flag Flags for the packet + def create(arg, opt ={}) + t = new + t.lm_response = arg[:lm_response] + t.ntlm_response = arg[:ntlm_response] + t.domain = arg[:domain] + t.user = arg[:user] + + if arg[:workstation] + t.workstation = arg[:workstation] + end + + if arg[:session_key] + t.enable(:session_key) + t.session_key = arg[:session_key] + end + + if arg[:flag] + t.enable(:session_key) + t.enable(:flag) + t.flag = arg[:flag] + end + t + end + end + + # @param server_challenge (see #password?) + def blank_password?(server_challenge) + password?('', server_challenge) + end + + # @param password [String] + # @param server_challenge [String] The server's {Type2#challenge challenge} from the + # {Type2} message for which this object is a response. + # @return [true] if +password+ was the password used to generate this + # {Type3} message + # @return [false] otherwise + def password?(password, server_challenge) + case ntlm_version + when :ntlm2_session + ntlm2_session_password?(password, server_challenge) + when :ntlmv2 + ntlmv2_password?(password, server_challenge) + else + raise + end + end + + # @return [Symbol] + def ntlm_version + if ntlm_response.size == 24 && lm_response[0,8] != "\x00"*8 && lm_response[8,16] == "\x00"*16 + :ntlm2_session + elsif ntlm_response.size == 24 + :ntlmv1 + elsif ntlm_response.size > 24 + :ntlmv2 + end + end + + private + + def ntlm2_session_password?(password, server_challenge) + hash = ntlm_response + _lm, empty_hash = NTLM.ntlm2_session( + { + :ntlm_hash => NTLM.ntlm_hash(password), + :challenge => server_challenge, + }, + { + :client_challenge => lm_response[0,8] + } + ) + hash == empty_hash + end + + def ntlmv2_password?(password, server_challenge) + + # The first 16 bytes of the ntlm_response are the HMAC of the blob + # that follows it. + blob = Blob.new + blob.parse(ntlm_response[16..-1]) + + empty_hash = NTLM.ntlmv2_response( + { + # user and domain came from the serialized data here, so + # they're already unicode + :ntlmv2_hash => NTLM.ntlmv2_hash(user, '', domain, :unicode => true), + :challenge => server_challenge, + :target_info => blob.target_info + }, + { + :client_challenge => blob.challenge, + # The blob's timestamp is already in milliseconds since 1601, + # so convert it back to epoch time first + :timestamp => (blob.timestamp / 10_000_000) - NTLM::TIME_OFFSET, + } + ) + + empty_hash == ntlm_response + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/security_buffer.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/security_buffer.rb new file mode 100644 index 0000000000..92645c8da2 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/security_buffer.rb @@ -0,0 +1,48 @@ + +module Net + module NTLM + + class SecurityBuffer < FieldSet + + int16LE :length, {:value => 0} + int16LE :allocated, {:value => 0} + int32LE :offset, {:value => 0} + + attr_accessor :active + def initialize(opts={}) + super() + @value = opts[:value] + @active = opts[:active].nil? ? true : opts[:active] + @size = 8 + end + + def parse(str, offset=0) + if @active and str.size >= offset + @size + super(str, offset) + @value = str[self.offset, self.length] + @size + else + 0 + end + end + + def serialize + super if @active + end + + def value + @value + end + + def value=(val) + @value = val + self.length = self.allocated = val.size + end + + def data_size + @active ? @value.size : 0 + end + end + + end +end \ No newline at end of file diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/string.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/string.rb new file mode 100644 index 0000000000..28edd9caa2 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/string.rb @@ -0,0 +1,35 @@ +module Net + module NTLM + + class String < Field + def initialize(opts) + super(opts) + @size = opts[:size] + end + + def parse(str, offset=0) + if @active and str.size >= offset + @size + @value = str[offset, @size] + @size + else + 0 + end + end + + def serialize + if @active + @value.to_s + else + "" + end + end + + def value=(val) + @value = val + @size = @value.nil? ? 0 : @value.size + @active = (@size > 0) + end + end + + end +end \ No newline at end of file diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/target_info.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/target_info.rb new file mode 100644 index 0000000000..7cc50acb10 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/target_info.rb @@ -0,0 +1,89 @@ +module Net + module NTLM + + # Represents a list of AV_PAIR structures + # @see https://msdn.microsoft.com/en-us/library/cc236646.aspx + class TargetInfo + + # Allowed AvId values for an AV_PAIR + MSV_AV_EOL = "\x00\x00".freeze + MSV_AV_NB_COMPUTER_NAME = "\x01\x00".freeze + MSV_AV_NB_DOMAIN_NAME = "\x02\x00".freeze + MSV_AV_DNS_COMPUTER_NAME = "\x03\x00".freeze + MSV_AV_DNS_DOMAIN_NAME = "\x04\x00".freeze + MSV_AV_DNS_TREE_NAME = "\x05\x00".freeze + MSV_AV_FLAGS = "\x06\x00".freeze + MSV_AV_TIMESTAMP = "\x07\x00".freeze + MSV_AV_SINGLE_HOST = "\x08\x00".freeze + MSV_AV_TARGET_NAME = "\x09\x00".freeze + MSV_AV_CHANNEL_BINDINGS = "\x0A\x00".freeze + + # @param av_pair_sequence [String] AV_PAIR list from challenge message + def initialize(av_pair_sequence) + @av_pairs = read_pairs(av_pair_sequence) + end + + attr_reader :av_pairs + + def to_s + result = '' + av_pairs.each do |k,v| + result << k + result << [v.length].pack('S') + result << v + end + result << Net::NTLM::TargetInfo::MSV_AV_EOL + result << [0].pack('S') + result.force_encoding(Encoding::ASCII_8BIT) + end + + private + + VALID_PAIR_ID = [ + MSV_AV_EOL, + MSV_AV_NB_COMPUTER_NAME, + MSV_AV_NB_DOMAIN_NAME, + MSV_AV_DNS_COMPUTER_NAME, + MSV_AV_DNS_DOMAIN_NAME, + MSV_AV_DNS_TREE_NAME, + MSV_AV_FLAGS, + MSV_AV_TIMESTAMP, + MSV_AV_SINGLE_HOST, + MSV_AV_TARGET_NAME, + MSV_AV_CHANNEL_BINDINGS + ].freeze + + def read_pairs(av_pair_sequence) + offset = 0 + result = {} + return result if av_pair_sequence.nil? + + until offset >= av_pair_sequence.length + id = av_pair_sequence[offset..offset+1] + + unless VALID_PAIR_ID.include?(id) + raise Net::NTLM::InvalidTargetDataError.new( + "Invalid AvId #{to_hex(id)} in AV_PAIR structure", + av_pair_sequence + ) + end + + length = av_pair_sequence[offset+2..offset+3].unpack('S')[0].to_i + if length > 0 + value = av_pair_sequence[offset+4..offset+4+length-1] + result[id] = value + end + + offset += 4 + length + end + + result + end + + def to_hex(str) + return nil if str.nil? + str.bytes.map {|b| '0x' + b.to_s(16).rjust(2,'0').upcase}.join('-') + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/version.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/version.rb new file mode 100644 index 0000000000..b6a2dba74f --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/net/ntlm/version.rb @@ -0,0 +1,11 @@ +module Net + module NTLM + # @private + module VERSION + MAJOR = 0 + MINOR = 6 + TINY = 3 + STRING = [MAJOR, MINOR, TINY].join('.') + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/rubyntlm.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/rubyntlm.rb new file mode 100644 index 0000000000..969c19c714 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubyntlm-0.6.3/lib/rubyntlm.rb @@ -0,0 +1 @@ +require 'net/ntlm' \ No newline at end of file