Class: Ronin::DB::URL

Inherits:
ActiveRecord::Base
  • Object
show all
Includes:
Model, Model::Importable, Model::LastScannedAt
Defined in:
lib/ronin/db/url.rb

Overview

Represents parsed URLs.

Constant Summary collapse

SCHEMES =

Mapping of URL Schemes and URI classes

{
  'https' => ::URI::HTTPS,
  'http'  => ::URI::HTTP,
  'ftp'   => ::URI::FTP
}

Instance Attribute Summary collapse

Attributes included from Model::LastScannedAt

#last_scanned_at

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Model::LastScannedAt

included

Methods included from Model::Importable

included

Methods included from Model

included

Instance Attribute Details

#advisoriesArray<Advisory>

The advisories that the URLs is vulnerable to.

Returns:

Since:

  • 0.2.0



141
# File 'lib/ronin/db/url.rb', line 141

has_many :advisories, through: :vulnerabilities

#created_atTime (readonly)

Defines the created_at timestamp

Returns:

  • (Time)


98
# File 'lib/ronin/db/url.rb', line 98

attribute :created_at, :datetime

#credentialsArray<Credentials>

The credentials that will work with this URL.

Returns:

  • (Array<Credentials>)


117
# File 'lib/ronin/db/url.rb', line 117

has_many :credentials, through: :web_credentials

#fragmentString?

The fragment of the URL.

Returns:

  • (String, nil)


92
# File 'lib/ronin/db/url.rb', line 92

attribute :fragment, :string

#host_nameHostName

The host name of the URL

Returns:



67
# File 'lib/ronin/db/url.rb', line 67

belongs_to :host_name, required: true

#idInteger

The primary key of the URL.

Returns:

  • (Integer)


54
# File 'lib/ronin/db/url.rb', line 54

attribute :id, :integer

#notesArray<Note>

The associated notes.

Returns:

Since:

  • 0.2.0



149
# File 'lib/ronin/db/url.rb', line 149

has_many :notes, dependent: :destroy

#pathString

The path of the URL.

Returns:

  • (String)


80
# File 'lib/ronin/db/url.rb', line 80

attribute :path, :string

#portPort?

The port of the URL.

Returns:



73
74
# File 'lib/ronin/db/url.rb', line 73

belongs_to :port, optional:   true,
class_name: 'Port'

#queryString?

The query string part of the URL.

Returns:

  • (String, nil)


86
# File 'lib/ronin/db/url.rb', line 86

attribute :query, :string

#query_paramsArray<URLQueryParam>

The query params of the URL.

Returns:



104
105
# File 'lib/ronin/db/url.rb', line 104

has_many :query_params, class_name: 'URLQueryParam',
dependent:  :destroy

#schemeURLScheme

The scheme of the URL.

Returns:



60
61
# File 'lib/ronin/db/url.rb', line 60

belongs_to :scheme, required:   true,
class_name: 'URLScheme'

#vulnerabilitiesArray<Vulnerability>

The vulnerabilities which reference the URL.

Returns:

Since:

  • 0.2.0



133
# File 'lib/ronin/db/url.rb', line 133

has_many :vulnerabilities, dependent: :destroy

#web_credentialsArray<WebCredential>

Any credentials used with the URL.

Returns:



111
# File 'lib/ronin/db/url.rb', line 111

has_many :web_credentials, dependent: :destroy

#web_vulnsArray<WebVuln>

The web vulnerabilities which reference the URL.

Returns:

Since:

  • 0.2.0



125
# File 'lib/ronin/db/url.rb', line 125

has_many :web_vulns, dependent: :destroy

Class Method Details

.httpArray<URL>

Searches for all URLs using HTTP.

Returns:

  • (Array<URL>)

    The matching URLs.



159
160
161
# File 'lib/ronin/db/url.rb', line 159

def self.http
  joins(:scheme).where(scheme: {name: 'http'})
end

.httpsArray<URL>

Searches for all URLs using HTTPS.

Returns:

  • (Array<URL>)

    The matching URLs.



171
172
173
# File 'lib/ronin/db/url.rb', line 171

def self.https
  joins(:scheme).where(scheme: {name: 'https'})
end

.import(uri) ⇒ URL

Creates a new URL.

Parameters:

  • uri (String, URI::HTTP)

    The URI to create the URL from.

Returns:

  • (URL)

    The new URL.



385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
# File 'lib/ronin/db/url.rb', line 385

def self.import(uri)
  uri = URI(uri)

  # find or create the URL scheme, host_name and port
  scheme    = URLScheme.find_or_create_by(name: uri.scheme)
  host_name = HostName.find_or_create_by(name: uri.host)
  port      = if uri.port
                Port.find_or_create_by(
                  protocol: :tcp,
                  number:   uri.port
                )
              end
  path      = normalized_path(uri)
  query     = uri.query
  fragment  = uri.fragment

  # try to query a pre-existing URI then fallback to creating the URL
  # with query params.
  return find_or_create_by(
    scheme:       scheme,
    host_name:    host_name,
    port:         port,
    path:         path,
    query:        query,
    fragment:     fragment
  ) do |new_url|
    if uri.respond_to?(:query_params)
      # find or create the URL query params
      uri.query_params.each do |name,value|
        new_url.query_params << URLQueryParam.new(
          name:  URLQueryParamName.find_or_create_by(name: name),
          value: value
        )
      end
    end
  end
end

.lookup(url) ⇒ URL?

Searches for a URL.

Parameters:

  • url (URI::HTTP, String)

    The URL to search for.

Returns:

  • (URL, nil)

    The matching URL.



354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'lib/ronin/db/url.rb', line 354

def self.lookup(url)
  uri = URI(url)

  # create the initial query
  query = joins(:scheme, :host_name).where(
    scheme:    {name: uri.scheme},
    host_name: {name: uri.host},
    path:      normalized_path(uri),
    query:     uri.query,
    fragment:  uri.fragment
  )

  if uri.port
    # query the port
    query = query.joins(:port).where(port: {number: uri.port})
  end

  return query.first
end

.normalized_path(uri) ⇒ String?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Normalizes the path of a URI.

Parameters:

  • uri (URI)

    The URI containing the path.

Returns:

  • (String, nil)

    The normalized path.



505
506
507
508
509
510
511
512
513
514
515
# File 'lib/ronin/db/url.rb', line 505

def self.normalized_path(uri)
  case uri
  when ::URI::HTTP
    # map empty HTTP paths to '/'
    unless uri.path.empty? then uri.path
    else                        '/'
    end
  else
    uri.path
  end
end

.with_basename(basename) ⇒ Array<URL>

Searches for all URLs sharing a common base name.

Parameters:

  • basename (String)

    The base name to search for.

Returns:

  • (Array<URL>)

    The URL with the common base name.



263
264
265
266
267
# File 'lib/ronin/db/url.rb', line 263

def self.with_basename(basename)
  path_column = self.arel_table[:path]

  where(path_column.matches("%/#{basename}"))
end

.with_directory(root_dir) ⇒ Array<URL>

Searches for all URLs sharing a common sub-directory.

Parameters:

  • root_dir (String)

    The sub-directory to search for.

Returns:

  • (Array<URL>)

    The URL with the common sub-directory.



246
247
248
249
250
# File 'lib/ronin/db/url.rb', line 246

def self.with_directory(root_dir)
  path_column = self.arel_table[:path]

  where(path: root_dir).or(where(path_column.matches("#{root_dir}/%")))
end

.with_file_ext(ext) ⇒ Array<URL>

Searches for all URLs with a common file-extension.

Parameters:

  • ext (String)

    The file extension to search for.

Returns:

  • (Array<URL>)

    The URLs with the common file-extension.



280
281
282
283
284
# File 'lib/ronin/db/url.rb', line 280

def self.with_file_ext(ext)
  path_column = self.arel_table[:path]

  where(path_column.matches("%.#{sanitize_sql_like(ext)}"))
end

.with_fragment(fragment) ⇒ Array<URL>

Searches for all URLs with the exact fragment.

Parameters:

  • fragment (String)

    The fragment to search for.

Returns:

  • (Array<URL>)

    The URL with the matching fragment.



231
232
233
# File 'lib/ronin/db/url.rb', line 231

def self.with_fragment(fragment)
  where(fragment: fragment)
end

.with_host_name(name) ⇒ Array<URL>

Searches for URLs with specific host name(s).

Parameters:

  • name (String, Array<String>)

    The host name(s) to search for.

Returns:

  • (Array<URL>)

    The matching URLs.



186
187
188
# File 'lib/ronin/db/url.rb', line 186

def self.with_host_name(name)
  joins(:host_name).where(host_name: {name: name})
end

.with_path(path) ⇒ Array<URL>

Searches for all URLs with the exact path.

Parameters:

  • path (String)

    The path to search for.

Returns:

  • (Array<URL>)

    The URL with the matching path.



216
217
218
# File 'lib/ronin/db/url.rb', line 216

def self.with_path(path)
  where(path: path)
end

.with_port_number(number) ⇒ Array<URL>

Searches for URLs with the specific port number(s).

Parameters:

  • number (Integer, Array<Integer>)

    The port number(s) to search for.

Returns:

  • (Array<URL>)

    The matching URLs.



201
202
203
# File 'lib/ronin/db/url.rb', line 201

def self.with_port_number(number)
  joins(:port).where(port: {number: number})
end

.with_query_param(name, value) ⇒ Array<URL>

Searches for URLs with the given query param name and value.

Parameters:

  • name (String, Array<String>)

    The query param name to search for.

  • value (String, Array<String>)

    The query param value to search for.

Returns:

  • (Array<URL>)

    The URLs with the given query param.



300
301
302
303
304
305
306
307
# File 'lib/ronin/db/url.rb', line 300

def self.with_query_param(name,value)
  joins(query_params: :name).where(
    query_params: {
      ronin_url_query_param_names:  {name: name},
      value: value
    }
  )
end

.with_query_param_name(name) ⇒ Array<URL>

Search for all URLs with a given query param name.

Parameters:

  • name (Array<String>, String)

    The query param name to search for.

Returns:

  • (Array<URL>)

    The URLs with the given query param name.



320
321
322
323
324
325
326
# File 'lib/ronin/db/url.rb', line 320

def self.with_query_param_name(name)
  joins(query_params: [:name]).where(
    query_params: {
      ronin_url_query_param_names: {name: name}
    }
  )
end

.with_query_param_value(value) ⇒ Array<URL>

Search for all URLs with a given query param value.

Parameters:

  • value (Array<String>, String)

    The query param value to search for.

Returns:

  • (Array<URL>)

    The URLs with the given query param value.



339
340
341
# File 'lib/ronin/db/url.rb', line 339

def self.with_query_param_value(value)
  joins(:query_params).where(query_params: {value: value})
end

Instance Method Details

#hostString

The host name of the URL.

Returns:

  • (String)

    The address of host name.



431
432
433
# File 'lib/ronin/db/url.rb', line 431

def host
  self.host_name.name
end

#port_numberInteger?

The port number used by the URL.

Returns:

  • (Integer, nil)

    The port number.



443
444
445
# File 'lib/ronin/db/url.rb', line 443

def port_number
  self.port.number if self.port
end

#to_sString

Converts the URL to a String.

Returns:

  • (String)

    The string form of the URL.



490
491
492
# File 'lib/ronin/db/url.rb', line 490

def to_s
  self.to_uri.to_s
end

#to_uriURI::HTTP, URI::HTTPS

Builds a URI object from the URL.

Returns:

  • (URI::HTTP, URI::HTTPS)

    The URI object created from the URL attributes.



455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
# File 'lib/ronin/db/url.rb', line 455

def to_uri
  # map the URL scheme to a URI class
  url_class = SCHEMES.fetch(self.scheme.name,::URI::Generic)

  scheme = if self.scheme
             self.scheme.name
           end

  host = if self.host_name
           self.host_name.name
         end

  port = if self.port
           self.port.number
         end

  # build the URI
  return url_class.build(
    scheme:   scheme,
    host:     host,
    port:     port,
    path:     self.path,
    query:    self.query,
    fragment: self.fragment
  )
end