沙尘暴/cookiepunch

在标记达到浏览器之前阻止元素(如iframes和scripts),并在浏览器中提供对话框以重新启用它们。

安装: 47,982

依赖: 0

建议者: 0

安全: 0

星级: 5

观察者: 8

分支: 3

开放问题: 1

类型:neos-package

4.4.3 2023-10-25 14:59 UTC

README

这个Neos包提供了一种在标记达到浏览器之前阻止元素(如script标签和iframe)的通用方法,因此提供了一种阻止cookies或其他跟踪用户行为概念的通用方法。它集成了Klaro作为显示cookie同意并在用户同意后取消阻止元素组的前端界面。

特性

  • 在将标记发送到客户端之前阻止元素的eel助手(脚本和iframe)
  • 用于放置任何标记部分的上下文同意的eel助手
  • 通过支持用于在标记中定位元素的模式的yaml配置,配置阻止的简单方法
  • 不显示初始横幅/模态框的上下文同意模式
  • 通过Yaml和/或Fusion进行本地化支持
  • 数据源提供所有服务,例如作为检查器中的下拉菜单
  • Klaro提供的出色的cookie同意❤️,直接捆绑在此包中
    • 支持元素的取消阻止
    • 支持上下文同意,通过直接在元素上同意而无需打开同意模态框,临时/永久取消阻止内容
    • 你绝对需要在GitHub上查看他们的项目;)

安装

composer require sandstorm/cookiepunch

这将在外部的composer.json/lock中将依赖项放入(通常在您的仓库根目录或/app)。 重要: 如果您想在您的Flow包内部声明CookiePunch设置,您还需要将composer依赖项添加到包内的composer.json中,以确保正确的流包和配置加载顺序。

DistributionPackages/Your.SitePackage/package.json

    ...
    
    "require": {
        ...
        
        "sandstorm/cookiepunch": "*",
        
        ...
    },
    
    ...

基本配置和用法

步骤1:添加同意模态框

.../Resources/Private/Fusion中创建一个新的fusion文件CookiePunch.fusion,内容如下

prototype(Neos.Neos:Page) {
    head.javascripts.cookiepunchConsent = Sandstorm.CookiePunch:Consent
    # Block Global
    @process.blockTags = ${CookiePunch.blockTags(["iframe","script"], value, !node.context.inBackend)}
}

这将向您的页面添加所需的js和css。如果您重新加载页面,您应该看到同意模态框。现在所有<iframe><script>标签都将被阻止。支持的标签是["iframe", "script", "audio", "video", "source", "track", "img", "embed", "input"]

!node.context.inBackend禁用Neos后端中的阻止。

打开或重新加载您的页面。如果阻止工作正常,您的页面应该看起来破损,抱歉;)

您可以在浏览器检查器的控制台中输入klaro.show()以验证Klaro是否工作。在接下来的步骤中,我们将配置将在同意模态框中显示的purposesservices

让我们开始修复您的页面;)

步骤2:永远不要阻止您自己的javascript

您可能有一些脚本,您永远不想阻止,因为您的页面将无法使用。它们通常被称为main.jsapp.jsindex.js等。

renderer = Neos.Fusion:Tag {
    tagName = "script"
    attributes.src = "resource://Vendor.Example/Public/JavaScript/index.js"
    @process.neverBlockTags = ${CookiePunch.neverBlockTags(["script"],value)}
}
renderer = afx`
    <script src={props.src} type="application/javascript" @process.neverBlockTags={CookiePunch.neverBlockTags(["script"], value)}></script>
`

您也可以使用下一节中描述的技术来永远不阻止脚本,但对于技术上需要由网站使用的脚本,eel助手可以以更灵活的方式使用,并为您的代码添加更多语义。“嘿,我检查了这段代码,它不应该被阻止!”

步骤3:通过yaml配置阻止

Configuration/中创建一个Settings.CookiePunch.yaml

提示:将本包中的schema.json文件添加到您的IDE中,并选择它用于Settings.CookiePunch.yaml。这将使配置CookiePunch变得更加容易,并为您提供自动完成功能。

Sandstorm:
  CookiePunch:
    consent:
      purposes:
        mediaembeds:
          title: Media Embeds
          description: Some Description
      services:
        anchor:
          title: Anchor FM
          description: Podcast Player
          purposes:
            - mediaembeds
    blocking:
      tagPatterns:
        script:
          "Packages/Neos.Neos":
            block: false
          "Packages/Unikka.Slick":
            block: false
        iframe:
          "https://anchor.fm":
            service: anchor

此配置分为两部分。

consent将直接用于配置klaro同意显示的内容。klaro区分purposesservices。一个purpose是一组多个services。检查同意,以查看配置更改如何在浏览器中反映。

blocking用于通过模式查找标签,例如"Packages/Unikka.Slick",然后在后端通过“打破”标签来阻止它们。您可以使用service: myservice定义一个服务,而不是使用block: ...。这样klaro就可以在用户给出同意后解除内容限制。

匹配模式与标签

针对标签配置了阻塞模式。我们目前支持阻塞<script><iframe>标签。

让我们看看上面示例中的Packages/Neos.Neos模式。此模式将匹配以下所有标签

<script src="/foo/bar/Packages/Neos.Neos/baz/index.js"/>
<script data-foo="Neos.Neos"/>
<script Neos.Neosisawesome src="/some/source/main.js"/>

标签是一个字符串,如果它包含给定的模式,则会匹配。您也可以匹配字符串中的foo或其他任何内容。内部使用strpos()

此模式永远不会被阻止

"Packages/Neos.Neos":
  block: false

此模式始终会被阻止,且不能通过同意解除

如果编辑器可以放置任何HTML内容,并且您想始终阻止某些标签,则可能很有用。

"https://really-stuff.bad":
  block: true

此模式将被阻止,且用户可以使用同意解除它

"https://anchor.fm":
  service: anchor

步骤4:提供您的隐私声明链接

默认URL是/privacy。这可以更改。

通过配置作为字符串

Sandstorm:
  CookiePunch:
    consent:
      privacyPolicyUrl: /different-privacy

通过配置使用XLF文件

Sandstorm:
  CookiePunch:
    consent:
      privacyPolicyUrl: Vendor.Site:Main:privacyPolicyUrl

通过融合覆盖配置原型

prototype(Sandstorm.CookiePunch:Config) {
    consent.privacyPolicyUrl = Neos.Neos:NodeUri {
        node = ${q(site).find('[instanceof Vendor.Site:PrivacyPage]').get(0)}
    }
}
prototype(Sandstorm.CookiePunch:Config) {
    consent.privacyPolicyUrl = ${q(site).find('[instanceof Vendor.Site:Homepage]').property("privacyPolicyUrl")}
    consent.privacyPolicyUrl.@process.convert = Neos.Neos:ConvertUris
}

检查浏览器中的同意模态,看看链接是否存在!

步骤5:样式

通过yaml配置(klaro css变量)

查看支持的Klaro css变量

完整的yaml配置可以在Examples/Settings.CookiePunch.Styling.yaml中找到

Sandstorm:
  CookiePunch:
    consent:
      styling:
        font-family: "Work Sans,Helvetica Neue,Helvetica,Arial,sans-serif"
        green1: "red"
        green2: "green"
        green3: "blue"
        border-radius: "0"

手动样式

请注意,这可能在更新CookiePunch(它还将更新klaro.js)时中断。

首先,我们必须完全禁用css noCSS = true

prototype(Neos.Neos:Page) {
    head.javascripts.cookiepunchConsent = Sandstorm.CookiePunch:Consent {
        noCSS = true
    }
    # Block Global
    @process.blockTags = ${CookiePunch.blockTags(["iframe","script"], value, !node.context.inBackend)}
}

现在不会将任何样式应用于同意UI。所有样式都必须由您来完成。为了使这更容易,您可以在以下位置找到原始klaro样式:Resources/Private/KlaroCss/klaro.css

步骤6:允许用户稍后打开同意模态

您可以在Neos中放置一个链接,例如在隐私声明中某处,将href指向#open_cookie_punch_modal。这将由点击事件监听器捕获并打开模态。浏览器不会重新加载页面,因为我们内部使用event.preventDefault()

或者您可以在JavaScript中调用klaro.show()

高级用法

同意选项的完整列表

查看同意选项的注解yaml

大多数内联注释都是直接从klaro的注解config.js中复制的,以方便您;)

服务选项的完整列表

查看服务选项的注解yaml

大多数内联注释都是直接从klaro的注解config.js中复制的,以方便您;)

更改默认阻塞行为

prototype(Neos.Neos:Page) {
    head.javascripts.cookiepunchConsent = Sandstorm.CookiePunch:Consent
    # Block Global
    @process.blockTags = ${CookiePunch.blockTags(["iframe","script", "img"], value, !node.context.inBackend)}
}

CookiePunch.blockTags(["iframe","script", "img"] 告诉 CookiePunch 要查找哪些标签。默认情况下,所有 <iframe><script><img> 标签都将被阻止。然而,对于图像,你可能不想阻止所有标签,而是决定要阻止哪种模式。为此,你可以使用 "*": false 模式来更改 img 标签的默认阻止行为。

Sandstorm:
   CookiePunch:
     blocking:
       tagPatterns:
         img:
           "*":
             block: false
           "tracking-pixel-url":
             service: myservice

阻止渲染的融合子树

在运行 eel-helpers 为 Neos.Neos:Page 时,已经阻止的标记将不会被再次阻止。这意味着我们可以挂钩到插件来阻止它们并将它们附加到同意模态中的服务。

这种技术对于阻止无法通过模式匹配的行内 <script>...</script> 标签特别有用。

// Plugin Implementation Example
prototype(Vendor.Plugin.FooTube:Embed) < prototype(Neos.Fusion:Component) {
    renderer = afx`
      <div>
        <iframe src="..."></iframe>
        <script type="text/javascript">...</script>
      </div>
    `
}
// CookiePunch.fusion
prototype(Vendor.Plugin.FooTube:Embed) {
  // tags in this part of the tree will be blocked first
  @process.blockTags = ${CookiePunch.blockTags(["iframe","script"], value, !node.context.inBackend, "footube")}
}

prototype(Neos.Neos:Page) {
  head.javascripts.cookiepunchConsent = Sandstorm.CookiePunch:Consent
  // at last all remaining tags will be blocked according to the config
  // already blocked tags will be ignored
  @process.blockTags = ${CookiePunch.blockTags(["iframe","script"], value, !node.context.inBackend)}
}

为非 iframe 元素添加上下文同意

当你阻止一个 <script> 标签时,你可能会遇到一个损坏的 UI,因为一些样式可能没有被应用,一些标记可能没有被创建。你可以使用以下 eel-helper 来包装渲染的融合树的一部分,这样 klaro 就可以“替换”损坏的内容并添加上下文同意。

// CookiePunch.fusion
prototype(Vendor.Plugin.FooTube:Embed) {
  @process.blockTags = ${CookiePunch.blockTags(["script"], value, !node.context.inBackend, "footube")}
  @process.addContextualConsent = ${CookiePunch.addContextualConsent("footube", value, !node.context.inBackend)}
}

另一个用例是带有或不带有嵌套 <source> 标签的 <audio><video> 标签。你可能想阻止它们,这样访客的 IP 地址就不会在没有同意的情况下发送到第三方服务器。

prototype(Vendor:Component.ThirdpartyAudio) < prototype(Neos.Fusion:Component) {
  thirdpartySrc = ''
  
  renderer = afx`
    <audio>
      <source src={props.thirdpartySrc}/>
    </audio>
  `
  @process.blockTags = ${CookiePunch.blockTags(["source"], value, !node.context.inBackend, "thirdpartymedia")}
  @process.addContextualConsent = ${CookiePunch.addContextualConsent("thirdpartymedia", value, !node.context.inBackend)}
}

让编辑器在检查器中选择服务

如果你允许你的编辑器放置 HTML(例如,如果你使用 Neos.NodeTypes.Html:Html 节点类型),则编辑器可以放置可能设置 cookie 的标记。使用默认配置,CookiePunch 将阻止此内容。如果标记与 yaml 配置中的任何模式不匹配,则无法取消阻止此内容。

你可以在 NodeTypes.yaml 中添加 Sandstorm.CookiePunch:Mixin.ConsentServices 来在检查器中获得下拉列表。

"Neos.NodeTypes.Html:Html":
  superTypes:
    "Sandstorm.CookiePunch:Mixin.ConsentServices": true

你还需要为此添加实际阻止。

prototype(Neos.NodeTypes.Html:Html) {
  @process.blockTags = ${CookiePunch.blockTags(["iframe","script"], value, !node.context.inBackend, q(node).property("consentServices"))}
  // you can wrap the html element with a `<div data-name="myservice">...</div>` to make sure 
  // the contextual consent is displayed correctly 
  @process.contextualConsent = ${CookiePunch.addContextualConsent(q(node).property("consentServices"))}
}

让编辑器更改同意文本

你可以通过覆盖融合原型中的相应路径 Sandstorm.CookiePunch:Config.Translations 来覆盖相应的路径,使用内容节点文本属性中的文本属性。如果属性包含标记,则需要更改同意的配置。

Sandstorm:
  CookiePunch:
    consent:
      # Setting this to true will render the descriptions of the consent
      # modal and consent notice are HTML. Use with care.
      htmlTexts: true

翻译

Klaro 已经为许多语言提供了翻译。这些翻译作为 XLIFF 文件在 Resources/Private/Translations 中提供。

你可以通过以下方式覆盖翻译

  • 创建你自己的 XLIFF 文件,覆盖默认文件
  • 在 yaml 配置中提供/覆盖一个翻译键而不是实际文本(例如,用于服务的标题)
  • 通过覆盖融合原型中的相应路径 Sandstorm.CookiePunch:Config.TranslationsSandstorm.CookiePunch:Config

示例:翻译服务标签

你的 Settings.CookiePunch.yml 中的服务标签可以翻译如下

services:
  youtube:
    title: Youtube
    description: Vendor.Site:CookiePunch:services.youtube.description

其中

  • Vendor:Site 是你的站点包密钥
  • CookiePunch 是包含翻译的 xml 文件名(你可以在这里选择任何名称,只需确保它与文件名匹配即可)。见此

Screenshot 2022-06-07 at 14 37 57

  • 并且在这些文件中,你需要使用冒号后面的键(在这里:services.youtube.description)。
            <trans-unit id="services.youtube.description">
                <source>Erlaubt die Einbindung von Youtube-Videos.</source>
            </trans-unit>

同意模态中服务的条件渲染

你可以这样评估 cookie 模态中的切换是否应在运行时渲染

Sandstorm:
  CookiePunch:
    consent:
      services:
        youtube:
          title: Youtube
          description: ...
          purposes:
            - mediaembeds
          when: "${q(site).find('[instanceof Vendor.Site:YouTube]').count() > 0}"
        googleAnalytics:
          title: Google Analytics
          description: ...
          purposes:
            - analytics
          when: "${q(site).property('googleAnalyticsAccountKey')}"

这对于多站点设置和防止不必要的同意切换被渲染很有用,例如,如果没有向内容中添加过任何 YouTube 视频。

注意

  1. 你需要使用一个评估为布尔值的 eel 表达式。
  2. 如果没有添加 when 条件,默认为 when: ${true},这意味着将始终为此服务渲染同意切换。
  3. 当使用 q(...) 查询内容存储库时,仅允许 sitedocumentNodenode 不可用)。
  4. Klaro会将用户的同意存储在cookie中,如果用户之前已经同意,那么例如在移除和重新添加YouTube视频时,用户将不会被再次要求同意cookie。

重要

您需要根据Sandstorm.CookiePunch:Consent配置缓存设置,如下所示(使用上面的配置示例,根据您的使用情况进行调整)

prototype(Sandstorm.CookiePunch:Consent) {
    @cache {
        mode = 'cached'
        entryIdentifier {
            node = ${node}
        }
        entryTags {
            1 = ${Neos.Caching.nodeTag(node)}
            // RootPage being the nodetype of the site node (used as `q(site)` in the `when` settings key example above)
            2 = ${Neos.Caching.nodeTypeTag('Vendor.Site:RootPage')}  // flush when the googleAnalyticsAccountKey changes
            3 = ${Neos.Caching.nodeTypeTag('Vendor.Site:YouTube')} // flush when a youtube video is added or removed
        }
    }
}

防止空cookie模态

如果您想防止当所有'when'配置键评估为false时,您的用户看到空的CookieConsent模态,您可以在您的项目中像这样覆盖原型

prototype(Sandstorm.CookiePunch:Consent) {
    // only render if there is at least one service that has not been filtered out by its 'when' config key
    @if.hasServices = ${Array.length(this.servicesRemainingAfterWhenConditions) > 0}
}

上下文同意仅模式

如果您不想最初显示cookie横幅或模态,您可以使用contextualConsentOnly全局模式,该模式在版本 4.4.0中引入。

Sandstorm:
  CookiePunch:
    consent:
      contextualConsentOnly: true
      mustConsent: false

故障排除

iframe在解除阻止后工作,但大小或位置不正确

请检查

  • 您是否阻止了一个iframe,因为它添加了cookie?
  • 您是否有JavaScript代码操作这个iframe?
  • JavaScript在iframe被阻止时没有阻止吗?
  • 在您同意后,页面重新加载是否解决了问题?

这可能就是问题

  • JavaScript在页面加载时运行一次,但iframe仍然是“损坏的”(可能大小不正确)。
  • JavaScript进行了一些样式魔法,将iframe扩展到页面的可用宽度。
  • JavaScript需要在iframe处于未阻止状态时运行,否则计算将失败。

如何修复

  • 虽然它没有添加任何cookie,但也请阻止JavaScript。
  • 将其附加到与iframe相同的服务。
  • 这样,JavaScript将在iframe解除阻止后运行。

从版本3迁移到4

现在您可以阻止更多标签。这就是我们为什么将Eel助手通用化的原因。

旧版本

    @process.blockIframes = ${CookiePunch.blockIframes(value, !node.context.inBackend)}
    @process.blockScripts = ${CookiePunch.blockScripts(value, !node.context.inBackend)}
    @process.neverBlockScripts = ${CookiePunch.neverBlockScripts(value)}
    @process.neverBlockIframes = ${CookiePunch.neverBlockIframes(value)}

新版本

    @process.blockTags = ${CookiePunch.blockTags(["iframe", "script"],value, !node.context.inBackend)}
    @process.neverBlockTags = ${CookiePunch.neverBlockTags(["iframe", "script"],value, !node.context.inBackend)}

从版本2迁移到3

我们改变了配置目的的格式,以便提供Klaro.js提供的更多功能。现在,我们支持每个目的的titledescription

旧版本

Sandstorm:
  CookiePunch:
    consent:
      purposes:
        mediaembeds: Media Embeds

新版本

Sandstorm:
  CookiePunch:
    consent:
      purposes:
        title: Media Embeds
        description: Some Description

从版本1迁移到2

提示:将此包中的schema.json文件添加到您的IDE中,并将其选择为yaml文件。这将使迁移更容易,并在迁移时提供自动完成和验证。

有关通过更改服务器上的标记来阻止标签的所有内容都已移动到配置中的Sandstorm/CookiePunch/blocking/...

有关同意的渲染以及klaro的配置的所有内容都已移动到配置中的Sandstorm/CookiePunch/consent/...

阻止模式

旧版本

Sandstorm:
  CookiePunch:
    mode:
      blockAllScripts: true
      blockAllIframes: true

新版本

Sandstorm:
  CookiePunch:
    blocking:
      tagPatterns:
        script:
          "*":
            block: true
        iframe:
          "*":
            block: true

阻止模式

旧版本

Sandstorm:
  CookiePunch:
    elements:
      block: true # default blocking mode for all tags
      group: default # default group for all blocked tags
      patterns:
        "Packages/Neos.Neos":
          type: script
          block: false
        "https://anchor.fm":
          type: iframe
          block: true

新版本

Sandstorm:
  CookiePunch:
    blocking:
      tagPatterns:
        script:
          # "*":
          #   service: default -> see explanation
          "Packages/Neos.Neos":
            block: false
        iframe:
          # "*":
          #   service: default -> see explanation
          "https://anchor.fm":
            service: mediaembeds

重要:仅在罕见情况下使用通配符模式*。考虑一下,您是否真的需要更改默认阻止行为并创建一个通用的服务default,因为这违背了记录用于此页面的服务目的。

模式应该要么有block: true|false要么有service: "nameofservice"

组 -> 服务

我们将命名更改以匹配klaro的API。有关同意的所有内容都可以在这里配置。

Sandstorm/CookiePunch/consent/...

旧版本

Sandstorm:
  CookiePunch:
    groups:
      anchor:
        title: Anchor FM
        description: Podcast Player

新版本

Sandstorm:
  CookiePunch:
    consent:
      services:
        anchor:
          title: Anchor FM
          description: Podcast Player

每个组的同意选项 -> 服务

由于我们已经在Sandstorm/CookiePunch/consent/...中,所以我们删除了额外的consent嵌套级别。一个服务的所有选项都与同意有关。

旧版本

anchor:
  title: Anchor FM
  description: Podcast Player
  purposes:
    - mediaembeds
  consent:
    required: true

新版本

anchor:
  title: Anchor FM
  description: Podcast Player
  purposes:
    - mediaembeds
  required: true

有关服务的更多同意选项,请参阅高级配置的文档。

样式

如果您有自定义样式,它可能会因为klaro.js包中的更改而损坏。此包不再提供SCSS文件。有关更多信息,请参阅样式部分。

贡献

您需要一个正在运行的Neos发行版,并安装此包。

PHP代码 -> 阻止

您可以在更改标记处理时运行测试。

运行 ./bin/phpunit -c Build/BuildEssentials/PhpUnit/UnitTests.xml DistributionPackages/Sandstorm.CookiePunch/Tests/Unit/

或者功能测试,当更改条件同意渲染时

运行 ./bin/phpunit -c Build/BuildEssentials/PhpUnit/FunctionalTests.xml DistributionPackages/Sandstorm.CookiePunch/Tests/Functional/

融合,XLF 和 TypeScript

运行 nvm use && yarn 安装所有依赖,运行 yarn run watch 开始开发 TypeScript。

我们使用 NodeJs 自动根据原始 Klaro 翻译生成 XLS 和融合文件。您可以通过运行 build:translations 重新编译这些文件。

完成时,请记得运行 yarn run build

查看 package.json 获取更多有用的脚本。