class RailsDevSsl::CLI

Public Instance Methods

add_ca_to_keychain() click to toggle source
# File lib/rails_dev_ssl.rb, line 47
def add_ca_to_keychain
  puts 'Adding rootCA.pem to system keychain'
  `sudo -p 'sudo password:' security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain #{File.join(dir, 'rootCA.pem')}`
end
display_certificate() click to toggle source
# File lib/rails_dev_ssl.rb, line 24
def display_certificate
  raise 'Certificate missing. Have you generated the certificate already?' unless File.exist?(File.join(dir, 'server.crt'))

  puts `openssl x509 -text -in #{File.join(dir, 'server.crt')} -noout`
end
generate_certificates() click to toggle source
# File lib/rails_dev_ssl.rb, line 32
def generate_certificates
  raise "Directory (#{dir}) doesn't exist" unless Dir.exist?(dir)

  generate_config unless File.exist?(File.join(dir, 'server.csr.cnf'))
  begin
    temp_file = password_file
    safe_path = Shellwords.escape(temp_file.path)
    generate_ca(safe_path)
    generate_crt_and_key(options['pem-file'], safe_path)
  ensure
    temp_file.close!
  end
end
generate_config() click to toggle source
# File lib/rails_dev_ssl.rb, line 65
def generate_config
  unless options['non-interactive']
    country = ask("Enter the country of your organization [#{default_config[:C]}]")
    state = ask("Enter the state of province of your organization [#{default_config[:ST]}]")
    city = ask("Enter the city of your organization [#{default_config[:L]}]")
    org = ask("Enter your organization name [#{default_config[:O]}]")
    email = ask("Enter your email [#{default_config[:emailAddress]}]")
    domain = ask("Enter your local SSL domain [#{default_config[:CN]}]")
    @@config = { C: country, ST: state, L: city, O: org, emailAddress: email, CN: domain }
  end
  write_config_file
end
generate_v3_ext_file() click to toggle source
# File lib/rails_dev_ssl.rb, line 79
    def generate_v3_ext_file
      raise 'server.csr.cnf missing. run rails_dev_ssl generate_config first' unless File.exist?(File.join(dir, 'server.csr.cnf'))

      puts "\n*** generating v3.ext"
      configs = <<~CONFIG
        authorityKeyIdentifier=keyid,issuer
        basicConstraints=CA:FALSE
        keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
        subjectAltName = @alt_names

        [alt_names]
        DNS.1 = #{config['CN']}
      CONFIG
      File.open(File.join(dir, 'v3.ext'), 'w') { |file| file.write(configs) }
    end
setup(dir = File.join(Dir.pwd, 'ssl')) click to toggle source
# File lib/rails_dev_ssl.rb, line 18
def setup(dir = File.join(Dir.pwd, 'ssl'))
  @@dir = dir
  Dir.mkdir(@@dir) unless Dir.exist?(@@dir)
end

Private Instance Methods

ask(question) click to toggle source
# File lib/rails_dev_ssl.rb, line 97
def ask(question)
  puts question
  $stdin.gets.chomp
end
config() click to toggle source
# File lib/rails_dev_ssl.rb, line 102
def config
  @config ||= if File.exist?(File.join(dir, 'server.csr.cnf'))
                OpenSSL::Config.load(File.join(dir, 'server.csr.cnf'))['dn']
              else
                default_config.merge(@@config.delete_if { |_k, v| v == '' })
  end
end
default_config() click to toggle source
# File lib/rails_dev_ssl.rb, line 110
def default_config
  {
    C: 'US',
    ST: 'California',
    L: 'San Francisco',
    O: 'My Organization',
    emailAddress: 'rails-dev-ssl-user@example.com',
    CN: 'localhost.ssl'
  }
end
dir() click to toggle source
# File lib/rails_dev_ssl.rb, line 121
def dir
  # TODO: read this from an environment variable
  setup if @@dir == ''
  @@dir
end
generate_ca(password_file_path) click to toggle source
# File lib/rails_dev_ssl.rb, line 127
def generate_ca(password_file_path)
  puts "\n*** generating rootCA.key"
  `openssl genrsa -des3 -out #{File.join(dir, 'rootCA.key')} -passout file:#{password_file_path} 2048` unless File.exist?(File.join(dir, 'rootCA.key'))

  puts "\n*** generating rootCA.pem"
  `openssl req -x509 -new -nodes -key #{File.join(dir, 'rootCA.key')} -sha256 -days 1024 -out #{File.join(dir, 'rootCA.pem')} -passin file:#{password_file_path} -config #{File.join(dir, 'server.csr.cnf')}` unless File.exist?(File.join(dir, 'rootCA.pem'))
end
generate_crt_and_key(_pem_file = false, password_file_path) click to toggle source
# File lib/rails_dev_ssl.rb, line 135
def generate_crt_and_key(_pem_file = false, password_file_path)
  puts "\n*** generating server.key"
  `openssl req -new -sha256 -nodes -out #{File.join(dir, 'server.csr')} -newkey rsa:2048 -keyout #{File.join(dir, 'server.key')} -config #{File.join(dir, 'server.csr.cnf')} -passin file:#{password_file_path}`

  generate_v3_ext_file unless File.exist?(File.join(dir, 'v3.ext'))

  puts "\n*** generating server.crt"
  `openssl x509 -req -in #{File.join(dir, 'server.csr')} -CA #{File.join(dir, 'rootCA.pem')} -CAkey #{File.join(dir, 'rootCA.key')} -CAcreateserial -out #{File.join(dir, 'server.crt')} -days 500 -sha256 -extfile #{File.join(dir, 'v3.ext')} -passin file:#{password_file_path}`
  # remove intermediary file
  File.delete(File.join(dir, 'server.csr'))
end
password_file(password = temp_password) click to toggle source
# File lib/rails_dev_ssl.rb, line 147
def password_file(password = temp_password)
  file = Tempfile.new('some_file')
  file.write(password)
  file.close
  file
end
temp_password() click to toggle source
# File lib/rails_dev_ssl.rb, line 154
def temp_password
  # We don't really care what the password is since this is only used on localhost
  @temp_password ||= SecureRandom.hex(64)
end
write_config_file() click to toggle source
# File lib/rails_dev_ssl.rb, line 159
    def write_config_file
      puts "\n*** Writing server.csr.cnf"
      config_options = <<~CONFIG
        [req]
        default_bits = 2048
        prompt = no
        default_md = sha256
        distinguished_name = dn

        [dn]
        C=#{config[:C]}
        ST=#{config[:ST]}
        L=#{config[:L]}
        O=#{config[:O]}
        OU=Test Domain
        emailAddress=#{config[:emailAddress]}
        CN=#{config[:CN]}
      CONFIG
      File.open(File.join(dir, 'server.csr.cnf'), 'w') { |file| file.write(config_options) }
    end