validate snippets

Validating HTML Emails with Nokogiri, Tidy, and validator.w3.org

Tagged devise, emails, nokogiri, validate, tidy  Languages ruby
# We're validating the HTML generated by the Devise mailer
user = User.new email: 'xxx@xxx'
mail = Devise.mailer.confirmation_instructions(user, self).deliver
html = mail.html_part.body.to_s

Validate with tidy:

File.open('/tmp/html-validation.html', 'w') { |f| f << html }
unless system "tidy -errors -q -f /tmp/validation-errors.txt /tmp/html-validation.html"
  fail "Validation failed:\n #{File.read('/tmp/validation-errors.txt')}"
end

Remember to install tidy first:

$ sudo apt-get install tidy

Validate with Nokogiri is not so fun or accurate:

# Validate XML
doc = Nokogiri.XML(html)
doc.errors

# Validate against a schema, if you want
xsd = Nokogiri::XML::Schema(open('http://www.w3.org/2002/08/xhtml/xhtml1-strict.xsd'))
xsd.validate(doc)

For validation with w3.org, see this script

Validating HTML with validator.w3.org and Ruby

Tagged ruby, w3, validate, html  Languages ruby
require "net/http"

def validate(html)
  response = Net::HTTP.start("validator.w3.org") do |r|
    query = "output=json&fragment=" + CGI.escape(html)
    r.post2("/check", query)
  end
  if "Invalid" == response["x-w3c-validator-status"]
    File.open('/tmp/html-validation.html', 'w') { |f| f << html }
    JSON.parse(response.body)
  end
end

# List all validation errors
html = File.read('/tmp/html-validation.html')
if errors = validate(html)
  puts errors
end

How to check if an IP address is private (IPv6, IPv4, cidr)

Tagged ip, private, validate, cidr, ipv4, ipv6  Languages ruby
require 'resolv'
require 'ipaddr'

class PrivateIP
  # https://en.wikipedia.org/wiki/Private_network#Private_IPv4_address_spaces
  IPV4_NETWORKS = %w[0.0.0.0/8
  10.0.0.0/8
  100.64.0.0/10
  127.0.0.0/8
  169.254.0.0/16
  172.16.0.0/12
  192.0.0.0/24
  192.0.0.0/29
  192.0.0.8/32
  192.0.0.9/32
  192.0.0.170/32
  192.0.0.171/32
  192.0.2.0/24
  192.31.196.0/24
  192.52.193.0/24
  192.88.99.0/24
  192.168.0.0/16
  192.175.48.0/24
  198.18.0.0/15
  198.51.100.0/24
  203.0.113.0/24
  240.0.0.0/4
  255.255.255.255/32
  224.0.0.0/24
  239.0.0.0/8].map { |cidr| IPAddr.new(cidr) }

  # https://en.wikipedia.org/wiki/Unique_local_address
  IPV6_NETWORKS = %w[fd00::/8
  fc00::/8
  0000:0000:0000:0000:0000:0000:0000:0000/64].map { |cidr| IPAddr.new(cidr) }

  class InvalidHost < ArgumentError; end

  # Examples:
  # private?('127.0.0.1') => true
  # private?('localhost') => true
  # private?('google.com') => false
  def self.private?(ip_or_host)
    address = IPAddr.new(ip_or_host)
    if address.ipv4?
      IPV4_NETWORKS.any? { |cidr| cidr.include?(ip_or_host) }
    elsif address.ipv6?
      IPV6_NETWORKS.any? { |cidr| cidr.include?(ip_or_host) }
    else
      false
    end
  rescue IPAddr::InvalidAddressError
    private_host?(ip_or_host)
  end

  # Example: private_host?('localhost') => true
  def self.private_host?(host)
    host_ips(host).any? do |type, ips|
      ips.any? { |ip| private?(ip) }
    end
  end

  # Example: host_ips('localhost') => {ipv4: ['127.0.0.1'], ipv6: []}
  def self.host_ips(host)
    ipv4 = Resolv::DNS.new.getresources(host, Resolv::DNS::Resource::IN::A)
    ipv6 = Resolv::DNS.new.getresources(host, Resolv::DNS::Resource::IN::AAAA)
    raise InvalidHost, "unknown host: #{host}" if ipv4.empty? && ipv6.empty?
    { ipv4: ipv4.map { |r| r.address.to_s },
      ipv6: ipv6.map { |r| r.address.to_s } }
  end
end
require 'test_helper'
require 'private_ip'

class PrivateIPTest < ActiveSupport::TestCase
  test "private?" do
    assert PrivateIP.private?('localhost')
    assert PrivateIP.private?('127.0.0.1')
    assert PrivateIP.private?('0.0.0.0')
    refute PrivateIP.private?('google.com')
    refute PrivateIP.private?('209.216.230.240')
  end

  test "private? (IPV6)" do
    assert PrivateIP.private?('fd7b:5886:20a0:11a0:1111:2222:3333:4444')
    assert PrivateIP.private?('::1') # Try http://[::1]:3000 in browser
    assert PrivateIP.private?('::')
    assert PrivateIP.private?('0:0:0:0:0:0:0:1')
  end

  test "private? (CIDR)" do
    PrivateIP::IPV4_NETWORKS.each do |cidr|
      assert PrivateIP.private?(cidr.to_s)
    end
    PrivateIP::IPV6_NETWORKS.each do |cidr|
      assert PrivateIP.private?(cidr.to_s)
    end
  end

  test "private_host?" do
    assert PrivateIP.private_host?('localhost')
    refute PrivateIP.private_host?('google.com')
  end

  test "host_ips" do
    assert_equal({ ipv4: ["127.0.0.1"], ipv6: [] }, PrivateIP.host_ips('localhost'))
    assert_equal({ ipv4: ["209.216.230.240"], ipv6: []}, PrivateIP.host_ips('news.ycombinator.com'))
  end

  test "host_ips (invalid)" do
    assert_raise PrivateIP::InvalidHost do
      PrivateIP.host_ips('https://google.com')
    end
    assert_raise PrivateIP::InvalidHost do
      PrivateIP.host_ips('127.0.0.1')
    end
    assert_raise PrivateIP::InvalidHost do
      PrivateIP.host_ips('::1')
    end
    assert_raise PrivateIP::InvalidHost do
      PrivateIP.host_ips('[::1]')
    end
    assert_raise PrivateIP::InvalidHost do
      PrivateIP.host_ips('::')
    end
  end
end