diff --git a/CHANGELOG.md b/CHANGELOG.md index a2b0b76a..d10c5e35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ master === +* The preview server can now serve over HTTPS using the `--https` flag. It will use an automatic self-signed cert which can be overridden using `--ssl_certificate` and `--ssl_private_key`. These settings can also be set in `config.rb` + 3.3.11 === * Add `srcset` option to `image_tag`. Also enables them in Markdown. @@ -22,7 +24,7 @@ master 3.3.8 === * Define a mime type for sourcemaps. #1451 -* Asset hashing for image references in srcset +* Asset hashing for image references in srcset * Import patch to bugfix from Padrino Helpers #1401 * Better URI encoding and decoding #1406 * Update version of i18n diff --git a/middleman-core/lib/middleman-core/application.rb b/middleman-core/lib/middleman-core/application.rb index b0928a63..3173b139 100644 --- a/middleman-core/lib/middleman-core/application.rb +++ b/middleman-core/lib/middleman-core/application.rb @@ -75,6 +75,18 @@ module Middleman # @return [Fixnum] config.define_setting :port, 4567, 'The preview server port' + # Whether to serve the preview server over HTTPS. + # @return [Boolean] + config.define_setting :https, false, 'Serve the preview server over SSL/TLS' + + # The (optional) path to the SSL cert to use for the preview server. + # @return [String] + config.define_setting :ssl_certificate, nil, 'Path to an X.509 certificate to use for the preview server' + + # The (optional) private key for the certificate in :ssl_certificate. + # @return [String] + config.define_setting :ssl_private_key, nil, "Path to an RSA private key for the preview server's certificate" + # Name of the source directory # @return [String] config.define_setting :source, 'source', 'Name of the source directory' diff --git a/middleman-core/lib/middleman-core/cli/server.rb b/middleman-core/lib/middleman-core/cli/server.rb index cf3afafc..d9abc43e 100644 --- a/middleman-core/lib/middleman-core/cli/server.rb +++ b/middleman-core/lib/middleman-core/cli/server.rb @@ -18,6 +18,13 @@ module Middleman::Cli method_option :port, aliases: '-p', desc: 'The port Middleman will listen on' + method_option :https, + type: :boolean, + desc: 'Serve the preview server over SSL/TLS' + method_option :ssl_certificate, + desc: 'Path to an X.509 certificate to use for the preview server' + method_option :ssl_private_key, + desc: "Path to an RSA private key for the preview server's certificate" method_option :verbose, type: :boolean, default: false, @@ -63,6 +70,9 @@ module Middleman::Cli params = { port: options['port'], host: options['host'], + https: options['https'], + ssl_certificate: options['ssl_certificate'], + ssl_private_key: options['ssl_private_key'], environment: options['environment'], debug: options['verbose'], instrumenting: options['instrument'], diff --git a/middleman-core/lib/middleman-core/preview_server.rb b/middleman-core/lib/middleman-core/preview_server.rb index bc611378..42730788 100644 --- a/middleman-core/lib/middleman-core/preview_server.rb +++ b/middleman-core/lib/middleman-core/preview_server.rb @@ -1,4 +1,6 @@ require 'webrick' +require 'webrick/https' +require 'openssl' require 'middleman-core/meta_pages' require 'middleman-core/logger' @@ -6,17 +8,22 @@ require 'middleman-core/logger' module Middleman module PreviewServer class << self - attr_reader :app, :host, :port + attr_reader :app, :host, :port, :ssl_certificate, :ssl_private_key delegate :logger, to: :app + def https? + @https + end + # Start an instance of Middleman::Application # @return [void] def start(opts={}) @options = opts mount_instance(new_app) - logger.info "== The Middleman is standing watch at http://#{host}:#{port}" - logger.info "== Inspect your site configuration at http://#{host}:#{port}/__middleman/" + scheme = https? ? 'https' : 'http' + logger.info "== The Middleman is standing watch at #{scheme}://#{host}:#{port}" + logger.info "== Inspect your site configuration at #{scheme}://#{host}:#{port}/__middleman/" @initialized ||= false return if @initialized @@ -106,10 +113,17 @@ module Middleman config[:environment] = opts[:environment].to_sym if opts[:environment] config[:host] = opts[:host] if opts[:host] config[:port] = opts[:port] if opts[:port] + config[:https] = opts[:https] unless opts[:https].nil? + config[:ssl_certificate] = opts[:ssl_certificate] if opts[:ssl_certificate] + config[:ssl_private_key] = opts[:ssl_private_key] if opts[:ssl_private_key] end @host = @app.config[:host] @port = @app.config[:port] + @https = @app.config[:https] + + @ssl_certificate = @app.config[:ssl_certificate] + @ssl_private_key = @app.config[:ssl_private_key] @app end @@ -173,6 +187,22 @@ module Middleman DoNotReverseLookup: true } + if https? + http_opts[:SSLEnable] = true + + if ssl_certificate || ssl_private_key + raise "You must provide both :ssl_certificate and :ssl_private_key" unless ssl_private_key && ssl_certificate + http_opts[:SSLCertificate] = OpenSSL::X509::Certificate.new File.read ssl_certificate + http_opts[:SSLPrivateKey] = OpenSSL::PKey::RSA.new File.read ssl_private_key + else + # use a generated self-signed cert + http_opts[:SSLCertName] = [ + %w(CN localhost), + %w(CN #{host}) + ].uniq + end + end + if is_logging http_opts[:Logger] = FilteredWebrickLog.new else