From 24cbe98ac2b8161eaa09c231f991b7f37f5470ff Mon Sep 17 00:00:00 2001 From: Tom van den Berg Date: Mon, 1 Jun 2020 15:31:36 +0200 Subject: [PATCH 1/3] Add feature to have chrome ignore certificate errors when printing using an URL. --- cmd/gotenberg/main.go | 2 +- internal/pkg/chrome/chrome.go | 19 ++++++++++++------- internal/pkg/conf/conf.go | 19 +++++++++++++++++++ test/cmd/chrome.go | 2 +- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/cmd/gotenberg/main.go b/cmd/gotenberg/main.go index 4759d7d6..c9fa4e0b 100644 --- a/cmd/gotenberg/main.go +++ b/cmd/gotenberg/main.go @@ -28,7 +28,7 @@ func main() { systemLogger.DebugOpf(op, "configuration: %+v", config) if !config.DisableGoogleChrome() { // start Google Chrome headless. - if err := chrome.Start(systemLogger); err != nil { + if err := chrome.Start(systemLogger, config.IgnoreCertificateErrors()); err != nil { systemLogger.FatalOp(op, err) } } diff --git a/internal/pkg/chrome/chrome.go b/internal/pkg/chrome/chrome.go index a2250cfc..adf9a03f 100644 --- a/internal/pkg/chrome/chrome.go +++ b/internal/pkg/chrome/chrome.go @@ -16,11 +16,11 @@ import ( ) // Start starts Google Chrome headless in background. -func Start(logger xlog.Logger) error { +func Start(logger xlog.Logger, urlIgnoreCertificateErrors bool) error { const op string = "chrome.Start" logger.DebugOp(op, "starting new Google Chrome headless process on port 9222...") resolver := func() error { - cmd, err := cmd(logger) + cmd, err := cmd(logger, urlIgnoreCertificateErrors) if err != nil { return err } @@ -32,7 +32,7 @@ func Start(logger xlog.Logger) error { // if the process failed to start correctly, // we have to restart it. if !isViable(logger) { - return restart(logger, cmd.Process) + return restart(logger, cmd.Process, urlIgnoreCertificateErrors) } return nil } @@ -42,7 +42,7 @@ func Start(logger xlog.Logger) error { return nil } -func cmd(logger xlog.Logger) (*exec.Cmd, error) { +func cmd(logger xlog.Logger, urlIgnoreCertificateErrors bool) (*exec.Cmd, error) { const op string = "chrome.cmd" binary := "google-chrome-stable" args := []string{ @@ -66,6 +66,11 @@ func cmd(logger xlog.Logger) (*exec.Cmd, error) { "--mute-audio", "--no-first-run", } + + if urlIgnoreCertificateErrors { + args = append(args, "--ignore-certificate-errors") + } + cmd, err := xexec.Command(logger, binary, args...) if err != nil { return nil, xerror.New(op, err) @@ -93,7 +98,7 @@ func kill(logger xlog.Logger, proc *os.Process) error { return nil } -func restart(logger xlog.Logger, proc *os.Process) error { +func restart(logger xlog.Logger, proc *os.Process, urlIgnoreCertificateErrors bool) error { const op string = "chrome.restart" logger.DebugOp(op, "restarting Google Chrome headless process using port 9222...") resolver := func() error { @@ -101,7 +106,7 @@ func restart(logger xlog.Logger, proc *os.Process) error { if err := kill(logger, proc); err != nil { return err } - cmd, err := cmd(logger) + cmd, err := cmd(logger, urlIgnoreCertificateErrors) if err != nil { return err } @@ -113,7 +118,7 @@ func restart(logger xlog.Logger, proc *os.Process) error { // if the process failed to restart correctly, // we have to restart it again. if !isViable(logger) { - return restart(logger, cmd.Process) + return restart(logger, cmd.Process, urlIgnoreCertificateErrors) } return nil } diff --git a/internal/pkg/conf/conf.go b/internal/pkg/conf/conf.go index 45d1bce1..73757f2d 100644 --- a/internal/pkg/conf/conf.go +++ b/internal/pkg/conf/conf.go @@ -40,6 +40,8 @@ const ( // DefaultGoogleChromeRpccBufferSizeEnvVar contains the name // of the environment variable "DEFAULT_GOOGLE_CHROME_RPCC_BUFFER_SIZE". DefaultGoogleChromeRpccBufferSizeEnvVar string = "DEFAULT_GOOGLE_CHROME_RPCC_BUFFER_SIZE" + // Allow self signed certificates when using a remote url + URLIgnoreCertificateErrorsEnvVar string = "URL_IGNORE_CERTIFICATE_ERRORS" ) // Config contains the application @@ -53,6 +55,7 @@ type Config struct { defaultListenPort int64 disableGoogleChrome bool disableUnoconv bool + urlIgnoreCertificateErrors bool logLevel xlog.Level rootPath string maximumGoogleChromeRpccBufferSize int64 @@ -75,6 +78,7 @@ func DefaultConfig() Config { rootPath: "/", maximumGoogleChromeRpccBufferSize: 104857600, // ~100 MB defaultGoogleChromeRpccBufferSize: 1048576, // 1 MB + urlIgnoreCertificateErrors: false, } } @@ -188,6 +192,14 @@ func FromEnv() (Config, error) { if err != nil { return c, err } + urlIgnoreCertificateErrors, err := xassert.BoolFromEnv( + URLIgnoreCertificateErrorsEnvVar, + c.urlIgnoreCertificateErrors, + ) + c.urlIgnoreCertificateErrors = urlIgnoreCertificateErrors + if err != nil { + return c, err + } return c, nil } result, err := resolver() @@ -274,3 +286,10 @@ func (c Config) MaximumGoogleChromeRpccBufferSize() int64 { func (c Config) DefaultGoogleChromeRpccBufferSize() int64 { return c.defaultGoogleChromeRpccBufferSize } + +// IgnoreCertificateErrors returns true if +// Google Chrome should ignore certificate errors +// in case of self signed certificates for example. +func (c Config) IgnoreCertificateErrors() bool { + return c.urlIgnoreCertificateErrors +} diff --git a/test/cmd/chrome.go b/test/cmd/chrome.go index 73d96474..ad5e5e7c 100644 --- a/test/cmd/chrome.go +++ b/test/cmd/chrome.go @@ -14,7 +14,7 @@ func main() { systemLogger.FatalOp(op, err) } // start Google Chrome headless. - if err := chrome.Start(systemLogger); err != nil { + if err := chrome.Start(systemLogger, config.IgnoreCertificateErrors()); err != nil { systemLogger.FatalOp(op, err) } } From 1e6926ee2dde094b384c458173cdeee0cf15ac94 Mon Sep 17 00:00:00 2001 From: Tom van den Berg Date: Tue, 2 Jun 2020 16:06:17 +0200 Subject: [PATCH 2/3] Add ignoreCertificateErrors tests + docs --- .../docs/content/03-environment-variables.md | 4 ++ docs/index.html | 22 +++++++---- internal/pkg/conf/conf_test.go | 38 +++++++++++++++++++ 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/build/docs/content/03-environment-variables.md b/build/docs/content/03-environment-variables.md index b1522740..61ef06b4 100644 --- a/build/docs/content/03-environment-variables.md +++ b/build/docs/content/03-environment-variables.md @@ -58,6 +58,10 @@ The hard limit is 100 MB and is defined by Google Chrome itself. > The default Google Chrome rpcc buffer size may also be overridden per request thanks to the form field `googleChromeRpccBufferSize`. > See the [rpcc buffer size section](#html.rpcc_buffer_size). +## Ignore certificate errors + +By default Chrome will not accept certificate errors when using the URL print method. Setting this environment variable to `"1"` will allow insecure connections to be used. In dev environment for example. Be careful with this! Do not use in production. + ## Disable LibreOffice (unoconv) You may also disable LibreOffice (unoconv) with `DISABLE_UNOCONV`. diff --git a/docs/index.html b/docs/index.html index 1ad30e01..f09933dc 100755 --- a/docs/index.html +++ b/docs/index.html @@ -167,14 +167,14 @@ $ make publish GOTENBERG_USER_GID=You may also add it in your Docker Compose stack:

-
version: '3'
+
version: '3'
 
-services:
+services:
 
   # your other services
 
-  gotenberg:
-    image: thecodingmachine/gotenberg:6
+  gotenberg:
+    image: thecodingmachine/gotenberg:6
 
@@ -332,6 +332,12 @@ The hard limit is 100 MB and is defined by Google Chrome itself.

See the rpcc buffer size section.

+

Ignore certificate errors

+ +

By default the chrome instance will not accept certificate errors when using the URL print method. Setting this environment variable to "1" will allow insecure connections to be used. In dev environment for example. Be careful with this! Do not use in production.

+

Disable LibreOffice (unoconv)

@@ -1700,14 +1706,14 @@ if the API is under heavy load.

For instance, using the following Docker Compose file:

-
version: '3'
+
version: '3'
 
-services:
+services:
 
   # your other services
 
-  gotenberg:
-    image: thecodingmachine/gotenberg:6
+  gotenberg:
+    image: thecodingmachine/gotenberg:6
 

You may now launch your services using:

diff --git a/internal/pkg/conf/conf_test.go b/internal/pkg/conf/conf_test.go index 678ac2aa..b7855023 100644 --- a/internal/pkg/conf/conf_test.go +++ b/internal/pkg/conf/conf_test.go @@ -380,6 +380,43 @@ func TestDefaultGoogleChromeRpccBufferSizeFromEnv(t *testing.T) { os.Unsetenv(DefaultGoogleChromeRpccBufferSizeEnvVar) } +func TestIgnoreCertificateErrorsFromEnv(t *testing.T) { + var ( + expected Config + result Config + err error + ) + // URL_IGNORE_CERTIFICATE_ERRORS correctly set to true. + os.Setenv(URLIgnoreCertificateErrorsEnvVar, "1") + expected = DefaultConfig() + expected.urlIgnoreCertificateErrors = true + result, err = FromEnv() + assert.Nil(t, err) + assert.Equal(t, expected, result) + os.Unsetenv(URLIgnoreCertificateErrorsEnvVar) + // URL_IGNORE_CERTIFICATE_ERRORS correctly set to false. + os.Setenv(URLIgnoreCertificateErrorsEnvVar, "0") + expected = DefaultConfig() + expected.urlIgnoreCertificateErrors = false + result, err = FromEnv() + assert.Nil(t, err) + assert.Equal(t, expected, result) + os.Unsetenv(URLIgnoreCertificateErrorsEnvVar) + // URL_IGNORE_CERTIFICATE_ERRORS wrongly set. + os.Setenv(URLIgnoreCertificateErrorsEnvVar, "foo") + expected = DefaultConfig() + result, err = FromEnv() + test.AssertError(t, err) + assert.Equal(t, expected, result) + os.Unsetenv(URLIgnoreCertificateErrorsEnvVar) + // URL_IGNORE_CERTIFICATE_ERRORS not set at all. + expected = DefaultConfig() + expected.urlIgnoreCertificateErrors = false + result, err = FromEnv() + assert.Nil(t, err) + assert.Equal(t, expected, result) +} + func TestGetters(t *testing.T) { result := DefaultConfig() assert.Equal(t, result.maximumWaitTimeout, result.MaximumWaitTimeout()) @@ -394,4 +431,5 @@ func TestGetters(t *testing.T) { assert.Equal(t, result.rootPath, result.RootPath()) assert.Equal(t, result.maximumGoogleChromeRpccBufferSize, result.MaximumGoogleChromeRpccBufferSize()) assert.Equal(t, result.defaultGoogleChromeRpccBufferSize, result.DefaultGoogleChromeRpccBufferSize()) + assert.Equal(t, result.urlIgnoreCertificateErrors, result.IgnoreCertificateErrors()) } From 4d46b98e7fb35b4fa8df134199af290801901696 Mon Sep 17 00:00:00 2001 From: tomjvdberg <47381148+tomjvdberg@users.noreply.github.com> Date: Mon, 8 Jun 2020 08:31:57 +0200 Subject: [PATCH 3/3] Apply suggestions from code review Co-authored-by: Julien Neuhart --- .../docs/content/03-environment-variables.md | 6 ++-- cmd/gotenberg/main.go | 2 +- internal/pkg/chrome/chrome.go | 16 +++++----- internal/pkg/conf/conf.go | 22 +++++++------- internal/pkg/conf/conf_test.go | 30 +++++++++---------- test/cmd/chrome.go | 2 +- 6 files changed, 39 insertions(+), 39 deletions(-) diff --git a/build/docs/content/03-environment-variables.md b/build/docs/content/03-environment-variables.md index 61ef06b4..de22646d 100644 --- a/build/docs/content/03-environment-variables.md +++ b/build/docs/content/03-environment-variables.md @@ -58,9 +58,11 @@ The hard limit is 100 MB and is defined by Google Chrome itself. > The default Google Chrome rpcc buffer size may also be overridden per request thanks to the form field `googleChromeRpccBufferSize`. > See the [rpcc buffer size section](#html.rpcc_buffer_size). -## Ignore certificate errors +## Google Chrome ignore certificate errors -By default Chrome will not accept certificate errors when using the URL print method. Setting this environment variable to `"1"` will allow insecure connections to be used. In dev environment for example. Be careful with this! Do not use in production. +When performing a [URL](#url) conversion, Google Chrome will not accept certificate errors . + +You may allow insecure connections by setting `GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS` variable to `"1"`. **You should be careful with this feature and only enable it in your development environment.** ## Disable LibreOffice (unoconv) diff --git a/cmd/gotenberg/main.go b/cmd/gotenberg/main.go index c9fa4e0b..6f0135f2 100644 --- a/cmd/gotenberg/main.go +++ b/cmd/gotenberg/main.go @@ -28,7 +28,7 @@ func main() { systemLogger.DebugOpf(op, "configuration: %+v", config) if !config.DisableGoogleChrome() { // start Google Chrome headless. - if err := chrome.Start(systemLogger, config.IgnoreCertificateErrors()); err != nil { + if err := chrome.Start(systemLogger, config.GoogleChromeIgnoreCertificateErrors()); err != nil { systemLogger.FatalOp(op, err) } } diff --git a/internal/pkg/chrome/chrome.go b/internal/pkg/chrome/chrome.go index adf9a03f..07a3df1b 100644 --- a/internal/pkg/chrome/chrome.go +++ b/internal/pkg/chrome/chrome.go @@ -16,11 +16,11 @@ import ( ) // Start starts Google Chrome headless in background. -func Start(logger xlog.Logger, urlIgnoreCertificateErrors bool) error { +func Start(logger xlog.Logger, ignoreCertificateErrors bool) error { const op string = "chrome.Start" logger.DebugOp(op, "starting new Google Chrome headless process on port 9222...") resolver := func() error { - cmd, err := cmd(logger, urlIgnoreCertificateErrors) + cmd, err := cmd(logger, ignoreCertificateErrors) if err != nil { return err } @@ -32,7 +32,7 @@ func Start(logger xlog.Logger, urlIgnoreCertificateErrors bool) error { // if the process failed to start correctly, // we have to restart it. if !isViable(logger) { - return restart(logger, cmd.Process, urlIgnoreCertificateErrors) + return restart(logger, cmd.Process, ignoreCertificateErrors) } return nil } @@ -42,7 +42,7 @@ func Start(logger xlog.Logger, urlIgnoreCertificateErrors bool) error { return nil } -func cmd(logger xlog.Logger, urlIgnoreCertificateErrors bool) (*exec.Cmd, error) { +func cmd(logger xlog.Logger, ignoreCertificateErrors bool) (*exec.Cmd, error) { const op string = "chrome.cmd" binary := "google-chrome-stable" args := []string{ @@ -67,7 +67,7 @@ func cmd(logger xlog.Logger, urlIgnoreCertificateErrors bool) (*exec.Cmd, error) "--no-first-run", } - if urlIgnoreCertificateErrors { + if ignoreCertificateErrors { args = append(args, "--ignore-certificate-errors") } @@ -98,7 +98,7 @@ func kill(logger xlog.Logger, proc *os.Process) error { return nil } -func restart(logger xlog.Logger, proc *os.Process, urlIgnoreCertificateErrors bool) error { +func restart(logger xlog.Logger, proc *os.Process, ignoreCertificateErrors bool) error { const op string = "chrome.restart" logger.DebugOp(op, "restarting Google Chrome headless process using port 9222...") resolver := func() error { @@ -106,7 +106,7 @@ func restart(logger xlog.Logger, proc *os.Process, urlIgnoreCertificateErrors bo if err := kill(logger, proc); err != nil { return err } - cmd, err := cmd(logger, urlIgnoreCertificateErrors) + cmd, err := cmd(logger, ignoreCertificateErrors) if err != nil { return err } @@ -118,7 +118,7 @@ func restart(logger xlog.Logger, proc *os.Process, urlIgnoreCertificateErrors bo // if the process failed to restart correctly, // we have to restart it again. if !isViable(logger) { - return restart(logger, cmd.Process, urlIgnoreCertificateErrors) + return restart(logger, cmd.Process, ignoreCertificateErrors) } return nil } diff --git a/internal/pkg/conf/conf.go b/internal/pkg/conf/conf.go index 73757f2d..3f3cbe99 100644 --- a/internal/pkg/conf/conf.go +++ b/internal/pkg/conf/conf.go @@ -40,8 +40,9 @@ const ( // DefaultGoogleChromeRpccBufferSizeEnvVar contains the name // of the environment variable "DEFAULT_GOOGLE_CHROME_RPCC_BUFFER_SIZE". DefaultGoogleChromeRpccBufferSizeEnvVar string = "DEFAULT_GOOGLE_CHROME_RPCC_BUFFER_SIZE" - // Allow self signed certificates when using a remote url - URLIgnoreCertificateErrorsEnvVar string = "URL_IGNORE_CERTIFICATE_ERRORS" + // GoogleChromeIgnoreCertificateErrorsEnvVar contains the name + // of the environment variable "GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS". + GoogleChromeIgnoreCertificateErrorsEnvVar string = "GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS" ) // Config contains the application @@ -55,7 +56,7 @@ type Config struct { defaultListenPort int64 disableGoogleChrome bool disableUnoconv bool - urlIgnoreCertificateErrors bool + googleChromeIgnoreCertificateErrors bool logLevel xlog.Level rootPath string maximumGoogleChromeRpccBufferSize int64 @@ -78,7 +79,7 @@ func DefaultConfig() Config { rootPath: "/", maximumGoogleChromeRpccBufferSize: 104857600, // ~100 MB defaultGoogleChromeRpccBufferSize: 1048576, // 1 MB - urlIgnoreCertificateErrors: false, + googleChromeIgnoreCertificateErrors: false, } } @@ -192,11 +193,11 @@ func FromEnv() (Config, error) { if err != nil { return c, err } - urlIgnoreCertificateErrors, err := xassert.BoolFromEnv( - URLIgnoreCertificateErrorsEnvVar, - c.urlIgnoreCertificateErrors, + googleChromeIgnoreCertificateErrors, err := xassert.BoolFromEnv( + GoogleChromeIgnoreCertificateErrorsEnvVar, + c.googleChromeIgnoreCertificateErrors, ) - c.urlIgnoreCertificateErrors = urlIgnoreCertificateErrors + c.googleChromeIgnoreCertificateErrors = googleChromeIgnoreCertificateErrors if err != nil { return c, err } @@ -287,9 +288,6 @@ func (c Config) DefaultGoogleChromeRpccBufferSize() int64 { return c.defaultGoogleChromeRpccBufferSize } -// IgnoreCertificateErrors returns true if -// Google Chrome should ignore certificate errors -// in case of self signed certificates for example. -func (c Config) IgnoreCertificateErrors() bool { +func (c Config) GoogleChromeIgnoreCertificateErrors() bool { return c.urlIgnoreCertificateErrors } diff --git a/internal/pkg/conf/conf_test.go b/internal/pkg/conf/conf_test.go index b7855023..1fbb1cf7 100644 --- a/internal/pkg/conf/conf_test.go +++ b/internal/pkg/conf/conf_test.go @@ -380,38 +380,38 @@ func TestDefaultGoogleChromeRpccBufferSizeFromEnv(t *testing.T) { os.Unsetenv(DefaultGoogleChromeRpccBufferSizeEnvVar) } -func TestIgnoreCertificateErrorsFromEnv(t *testing.T) { +func TestGoogleChromeIgnoreCertificateErrorsFromEnv(t *testing.T) { var ( expected Config result Config err error ) - // URL_IGNORE_CERTIFICATE_ERRORS correctly set to true. - os.Setenv(URLIgnoreCertificateErrorsEnvVar, "1") + // GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS correctly set to true. + os.Setenv(GoogleChromeIgnoreCertificateErrorsEnvVar, "1") expected = DefaultConfig() - expected.urlIgnoreCertificateErrors = true + expected.googleChromeIgnoreCertificateErrors = true result, err = FromEnv() assert.Nil(t, err) assert.Equal(t, expected, result) - os.Unsetenv(URLIgnoreCertificateErrorsEnvVar) - // URL_IGNORE_CERTIFICATE_ERRORS correctly set to false. - os.Setenv(URLIgnoreCertificateErrorsEnvVar, "0") + os.Unsetenv(GoogleChromeIgnoreCertificateErrorsEnvVar) + // GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS correctly set to false. + os.Setenv(GooleChromeIgnoreCertificateErrorsEnvVar, "0") expected = DefaultConfig() - expected.urlIgnoreCertificateErrors = false + expected.googleChromeIgnoreCertificateErrors = false result, err = FromEnv() assert.Nil(t, err) assert.Equal(t, expected, result) - os.Unsetenv(URLIgnoreCertificateErrorsEnvVar) - // URL_IGNORE_CERTIFICATE_ERRORS wrongly set. - os.Setenv(URLIgnoreCertificateErrorsEnvVar, "foo") + os.Unsetenv(GoogleChromeIgnoreCertificateErrorsEnvVar) + // GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS wrongly set. + os.Setenv(GoogleChromeIgnoreCertificateErrorsEnvVar, "foo") expected = DefaultConfig() result, err = FromEnv() test.AssertError(t, err) assert.Equal(t, expected, result) - os.Unsetenv(URLIgnoreCertificateErrorsEnvVar) - // URL_IGNORE_CERTIFICATE_ERRORS not set at all. + os.Unsetenv(GoogleChromeIgnoreCertificateErrorsEnvVar) + // GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS not set at all. expected = DefaultConfig() - expected.urlIgnoreCertificateErrors = false + expected.googleChromeIgnoreCertificateErrors = false result, err = FromEnv() assert.Nil(t, err) assert.Equal(t, expected, result) @@ -431,5 +431,5 @@ func TestGetters(t *testing.T) { assert.Equal(t, result.rootPath, result.RootPath()) assert.Equal(t, result.maximumGoogleChromeRpccBufferSize, result.MaximumGoogleChromeRpccBufferSize()) assert.Equal(t, result.defaultGoogleChromeRpccBufferSize, result.DefaultGoogleChromeRpccBufferSize()) - assert.Equal(t, result.urlIgnoreCertificateErrors, result.IgnoreCertificateErrors()) + assert.Equal(t, result.googleChromeIgnoreCertificateErrors, result.GoogleChromeIgnoreCertificateErrors()) } diff --git a/test/cmd/chrome.go b/test/cmd/chrome.go index ad5e5e7c..82234f3e 100644 --- a/test/cmd/chrome.go +++ b/test/cmd/chrome.go @@ -14,7 +14,7 @@ func main() { systemLogger.FatalOp(op, err) } // start Google Chrome headless. - if err := chrome.Start(systemLogger, config.IgnoreCertificateErrors()); err != nil { + if err := chrome.Start(systemLogger, config.GoogleChromeIgnoreCertificateErrors()); err != nil { systemLogger.FatalOp(op, err) } }