summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2018-05-04 10:18:45 +0200
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2018-05-21 00:41:42 +0200
commit0bbdef986d8eecf4fabe9a372e33626dbdfeb36b (patch)
tree72e52401c9bf5503e0581a0f522a350311e29a0e
parent9bd4236e1b3bee332439eef50e12d4481340c3eb (diff)
config: Add the foundation for GDPR privacy configuration
See #4616
-rw-r--r--config/configProvider.go17
-rw-r--r--config/privacy/privacyConfig.go85
-rw-r--r--config/privacy/privacyConfig_test.go93
-rw-r--r--hugolib/config_test.go22
-rw-r--r--hugolib/hugo_sites_build.go4
-rw-r--r--hugolib/site.go21
-rw-r--r--hugolib/site_url_test.go2
7 files changed, 239 insertions, 5 deletions
diff --git a/config/configProvider.go b/config/configProvider.go
index 471ce9a1d..335294d73 100644
--- a/config/configProvider.go
+++ b/config/configProvider.go
@@ -13,6 +13,12 @@
package config
+import (
+ "strings"
+
+ "github.com/spf13/viper"
+)
+
// Provider provides the configuration settings for Hugo.
type Provider interface {
GetString(key string) string
@@ -25,3 +31,14 @@ type Provider interface {
Set(key string, value interface{})
IsSet(key string) bool
}
+
+// FromConfigString creates a config from the given YAML, JSON or TOML config. This is useful in tests.
+func FromConfigString(config, configType string) (Provider, error) {
+ v := viper.New()
+ v.SetConfigType(configType)
+ if err := v.ReadConfig(strings.NewReader(config)); err != nil {
+ return nil, err
+ }
+ return v, nil
+
+}
diff --git a/config/privacy/privacyConfig.go b/config/privacy/privacyConfig.go
new file mode 100644
index 000000000..c93137da4
--- /dev/null
+++ b/config/privacy/privacyConfig.go
@@ -0,0 +1,85 @@
+// Copyright 2018 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package privacy
+
+import (
+ "github.com/gohugoio/hugo/config"
+ "github.com/mitchellh/mapstructure"
+)
+
+const privacyConfigKey = "privacy"
+
+// Service is the common values for a service in a policy definition.
+type Service struct {
+ Disable bool
+}
+
+// Config is a privacy configuration for all the relevant services in Hugo.
+type Config struct {
+ Disqus Disqus
+ GoogleAnalytics GoogleAnalytics
+ Instagram Instagram
+ SpeakerDeck SpeakerDeck
+ Tweet Tweet
+ Vimeo Vimeo
+ YouTube YouTube
+}
+
+// Disqus holds the privacy configuration settings related to the Disqus template.
+type Disqus struct {
+ Service `mapstructure:",squash"`
+}
+
+// GoogleAnalytics holds the privacy configuration settings related to the Google Analytics template.
+type GoogleAnalytics struct {
+ Service `mapstructure:",squash"`
+}
+
+// Instagram holds the privacy configuration settings related to the Instagram shortcode.
+type Instagram struct {
+ Service `mapstructure:",squash"`
+}
+
+// SpeakerDeck holds the privacy configuration settings related to the SpeakerDeck shortcode.
+type SpeakerDeck struct {
+ Service `mapstructure:",squash"`
+}
+
+// Tweet holds the privacy configuration settingsrelated to the Tweet shortcode.
+type Tweet struct {
+ Service `mapstructure:",squash"`
+}
+
+// Vimeo holds the privacy configuration settingsrelated to the Vimeo shortcode.
+type Vimeo struct {
+ Service `mapstructure:",squash"`
+}
+
+// YouTube holds the privacy configuration settingsrelated to the YouTube shortcode.
+type YouTube struct {
+ Service `mapstructure:",squash"`
+ NoCookie bool
+}
+
+func DecodeConfig(cfg config.Provider) (pc Config, err error) {
+ if !cfg.IsSet(privacyConfigKey) {
+ return
+ }
+
+ m := cfg.GetStringMap(privacyConfigKey)
+
+ err = mapstructure.WeakDecode(m, &pc)
+
+ return
+}
diff --git a/config/privacy/privacyConfig_test.go b/config/privacy/privacyConfig_test.go
new file mode 100644
index 000000000..9b0d75e31
--- /dev/null
+++ b/config/privacy/privacyConfig_test.go
@@ -0,0 +1,93 @@
+// Copyright 2018 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package privacy
+
+import (
+ "testing"
+
+ "github.com/gohugoio/hugo/config"
+ "github.com/spf13/viper"
+ "github.com/stretchr/testify/require"
+)
+
+func TestDecodeConfigFromTOML(t *testing.T) {
+ assert := require.New(t)
+
+ tomlConfig := `
+
+someOtherValue = "foo"
+
+[privacy]
+[privacy.disqus]
+disable = true
+[privacy.googleAnalytics]
+disable = true
+[privacy.instagram]
+disable = true
+[privacy.speakerDeck]
+disable = true
+[privacy.tweet]
+disable = true
+[privacy.vimeo]
+disable = true
+[privacy.youtube]
+disable = true
+noCookie = true
+`
+ cfg, err := config.FromConfigString(tomlConfig, "toml")
+ assert.NoError(err)
+
+ pc, err := DecodeConfig(cfg)
+ assert.NoError(err)
+ assert.NotNil(pc)
+
+ assert.True(pc.Disqus.Disable)
+ assert.True(pc.GoogleAnalytics.Disable)
+ assert.True(pc.Instagram.Disable)
+ assert.True(pc.SpeakerDeck.Disable)
+ assert.True(pc.Tweet.Disable)
+ assert.True(pc.Vimeo.Disable)
+
+ assert.True(pc.YouTube.NoCookie)
+ assert.True(pc.YouTube.Disable)
+}
+
+func TestDecodeConfigFromTOMLCaseInsensitive(t *testing.T) {
+ assert := require.New(t)
+
+ tomlConfig := `
+
+someOtherValue = "foo"
+
+[Privacy]
+[Privacy.YouTube]
+NoCOOKIE = true
+`
+ cfg, err := config.FromConfigString(tomlConfig, "toml")
+ assert.NoError(err)
+
+ pc, err := DecodeConfig(cfg)
+ assert.NoError(err)
+ assert.NotNil(pc)
+ assert.True(pc.YouTube.NoCookie)
+}
+
+func TestDecodeConfigDefault(t *testing.T) {
+ assert := require.New(t)
+
+ pc, err := DecodeConfig(viper.New())
+ assert.NoError(err)
+ assert.NotNil(pc)
+ assert.False(pc.YouTube.NoCookie)
+}
diff --git a/hugolib/config_test.go b/hugolib/config_test.go
index 441bcf541..8bf7ea8b3 100644
--- a/hugolib/config_test.go
+++ b/hugolib/config_test.go
@@ -365,3 +365,25 @@ map[string]interface {}{
}`, got["menu"])
}
+
+func TestPrivacyConfig(t *testing.T) {
+ t.Parallel()
+
+ assert := require.New(t)
+
+ tomlConfig := `
+
+someOtherValue = "foo"
+
+[privacy]
+[privacy.youtube]
+noCookie = true
+`
+
+ b := newTestSitesBuilder(t)
+ b.WithConfigFile("toml", tomlConfig)
+ b.Build(BuildCfg{SkipRender: true})
+
+ assert.True(b.H.Sites[0].Info.PrivacyConfig.YouTube.NoCookie)
+
+}
diff --git a/hugolib/hugo_sites_build.go b/hugolib/hugo_sites_build.go
index e1e4a6056..e22aabfc5 100644
--- a/hugolib/hugo_sites_build.go
+++ b/hugolib/hugo_sites_build.go
@@ -168,7 +168,9 @@ func (h *HugoSites) assemble(config *BuildCfg) error {
if len(h.Sites) > 1 {
// The first is initialized during process; initialize the rest
for _, site := range h.Sites[1:] {
- site.initializeSiteInfo()
+ if err := site.initializeSiteInfo(); err != nil {
+ return err
+ }
}
}
diff --git a/hugolib/site.go b/hugolib/site.go
index 989238bed..0ee0db4a7 100644
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -27,6 +27,8 @@ import (
"strings"
"time"
+ "github.com/gohugoio/hugo/config/privacy"
+
"github.com/gohugoio/hugo/resource"
"golang.org/x/sync/errgroup"
@@ -386,6 +388,12 @@ type SiteInfo struct {
preserveTaxonomyNames bool
Data *map[string]interface{}
+ // This contains all privacy related settings that can be used to
+ // make the YouTube template etc.GDPR compliant.
+ // It is mostly in use by Hugo's built-in, but is also available
+ // for end users with {{ .Site.PrivacyConfig.YouTube.NoCookie }} etc.
+ PrivacyConfig privacy.Config
+
owner *HugoSites
s *Site
multilingual *Multilingual
@@ -1028,14 +1036,13 @@ func (s *Site) Initialise() (err error) {
}
func (s *Site) initialize() (err error) {
- defer s.initializeSiteInfo()
s.Menus = Menus{}
if err = s.checkDirectories(); err != nil {
return err
}
- return
+ return s.initializeSiteInfo()
}
// HomeAbsURL is a convenience method giving the absolute URL to the home page.
@@ -1058,7 +1065,7 @@ func (s *SiteInfo) SitemapAbsURL() string {
return p
}
-func (s *Site) initializeSiteInfo() {
+func (s *Site) initializeSiteInfo() error {
var (
lang = s.Language
languages helpers.Languages
@@ -1113,6 +1120,11 @@ func (s *Site) initializeSiteInfo() {
}
}
+ privacyConfig, err := privacy.DecodeConfig(lang)
+ if err != nil {
+ return err
+ }
+
s.Info = SiteInfo{
Title: lang.GetString("title"),
Author: lang.GetStringMap("author"),
@@ -1139,6 +1151,7 @@ func (s *Site) initializeSiteInfo() {
Data: &s.Data,
owner: s.owner,
s: s,
+ PrivacyConfig: privacyConfig,
}
rssOutputFormat, found := s.outputFormats[KindHome].GetByName(output.RSSFormat.Name)
@@ -1146,6 +1159,8 @@ func (s *Site) initializeSiteInfo() {
if found {
s.Info.RSSLink = s.permalink(rssOutputFormat.BaseFilename())
}
+
+ return nil
}
func (s *Site) dataDir() string {
diff --git a/hugolib/site_url_test.go b/hugolib/site_url_test.go
index 2be615963..5b9d19e0d 100644
--- a/hugolib/site_url_test.go
+++ b/hugolib/site_url_test.go
@@ -55,7 +55,7 @@ func TestShouldNotAddTrailingSlashToBaseURL(t *testing.T) {
d := deps.DepsCfg{Cfg: cfg, Fs: fs}
s, err := NewSiteForCfg(d)
require.NoError(t, err)
- s.initializeSiteInfo()
+ require.NoError(t, s.initializeSiteInfo())
if s.Info.BaseURL() != template.URL(this.expected) {
t.Errorf("[%d] got %s expected %s", i, s.Info.BaseURL(), this.expected)