i18n_feedback 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: db55035ed25835495f5e4840e9b3e6663a7e745d52600803207e8e38b7f92dcf
4
- data.tar.gz: 82cd102f8766cbab2de69c3c69fe56b6fefd8e27efb4f1e897b2556e9ef76510
3
+ metadata.gz: ab6f3f1bb7c4568e3491627e947cf38424ec76f0c21cff477bee95440c4df762
4
+ data.tar.gz: 8440049b960f561014f0217caf61395de948a0f665dc580b39e97f07bc55dddf
5
5
  SHA512:
6
- metadata.gz: 886de0912affd3a3d0e9ed7a20bca10605b6d2da21cb8446028049e0568cefe74ea2c57ee28f083cb29010220eabb3790cd0eec0e0af478ded46f45761a66ef2
7
- data.tar.gz: 94e65e65440bf08316bf2b55eacdc8af421dfad8072ac62b1172b93bb8b93ed4974f3b31d2051ba11bb9c4e708299a7a97a4a7bfa60d0fe4606312a888439844
6
+ metadata.gz: b0cafcd664c77f1f39c1a2029fe3f22d3e8d3dc3753c40a3d087a31d3b11c7bedaa73d2e22ddcc4abf9106a45510dcc63f2b287874555d439f536e09f7018c6f
7
+ data.tar.gz: d402186abbb1c9437feee55e52110ddb11b82332f29d7d3443524b204eaa2a30dff4691ef2edcae7a28cfc71bae80eabd0b2b62283c0224167ddaaf9c02cefe6
data/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.2.0]
6
+
7
+ - Stamp the injected widget scripts with the request's Content-Security-Policy
8
+ nonce when one is present, so the tool works under a nonce-based CSP (including
9
+ `strict-dynamic`). No-op for apps without a CSP nonce.
10
+
5
11
  ## [0.1.0]
6
12
 
7
13
  - Initial release.
data/README.md CHANGED
@@ -35,11 +35,11 @@ It is meant for development and staging, never production.
35
35
 
36
36
  ## Installation
37
37
 
38
- Add the gem (from source until it is published on RubyGems):
38
+ Add the gem:
39
39
 
40
40
  ```ruby
41
41
  # Gemfile
42
- gem "i18n_feedback", github: "yshmarov/i18n-feedback"
42
+ gem "i18n_feedback"
43
43
  ```
44
44
 
45
45
  ```bash
@@ -11,7 +11,8 @@ module I18nFeedback
11
11
  Widget.snippet(
12
12
  endpoint: I18nFeedback.config.suggestions_endpoint,
13
13
  locale: I18n.locale,
14
- active: I18nFeedback::Marking.enabled?
14
+ active: I18nFeedback::Marking.enabled?,
15
+ nonce: (content_security_policy_nonce if respond_to?(:content_security_policy_nonce))
15
16
  ).html_safe
16
17
  end
17
18
  end
@@ -30,7 +30,7 @@ module I18nFeedback
30
30
  headers = persist_choice(headers, override) if available && !override.nil?
31
31
 
32
32
  if available && I18nFeedback.config.auto_inject && html?(headers) && !request.xhr?
33
- status, headers, body = inject(status, headers, body, marking)
33
+ status, headers, body = inject(status, headers, body, marking, csp_nonce(env))
34
34
  end
35
35
 
36
36
  [status, headers, body]
@@ -44,6 +44,17 @@ module I18nFeedback
44
44
  !request.cookies[COOKIE].to_s.empty?
45
45
  end
46
46
 
47
+ # The request's CSP nonce, so the injected scripts run under a nonce-based
48
+ # Content-Security-Policy. Reads the value Rails memoizes on the env, which is
49
+ # the same nonce the CSP header uses. nil when the app sets no nonce.
50
+ def csp_nonce(env)
51
+ return nil unless defined?(ActionDispatch::Request)
52
+
53
+ ActionDispatch::Request.new(env).content_security_policy_nonce
54
+ rescue StandardError
55
+ nil
56
+ end
57
+
47
58
  def toggle_override(request)
48
59
  param = I18nFeedback.config.toggle_param
49
60
  return nil unless request.params.key?(param)
@@ -80,7 +91,7 @@ module I18nFeedback
80
91
  headers['Content-Type'] || headers['content-type']
81
92
  end
82
93
 
83
- def inject(status, headers, body, marking)
94
+ def inject(status, headers, body, marking, nonce)
84
95
  html = +''
85
96
  body.each { |part| html << part.to_s }
86
97
  body.close if body.respond_to?(:close)
@@ -88,7 +99,8 @@ module I18nFeedback
88
99
  snippet = Widget.snippet(
89
100
  endpoint: I18nFeedback.config.suggestions_endpoint,
90
101
  locale: I18n.locale,
91
- active: marking
102
+ active: marking,
103
+ nonce: nonce
92
104
  )
93
105
  html = html.include?('</body>') ? html.sub('</body>', "#{snippet}</body>") : html + snippet
94
106
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module I18nFeedback
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
@@ -17,8 +17,10 @@ module I18nFeedback
17
17
  end
18
18
 
19
19
  # The two <script> tags to place before </body>: one carrying the runtime
20
- # config, one carrying the widget itself.
21
- def snippet(endpoint:, locale:, active:)
20
+ # config, one carrying the widget itself. `nonce:` stamps both tags so the
21
+ # widget runs under a nonce-based Content-Security-Policy (e.g. one using
22
+ # 'strict-dynamic'); pass nil when the app has no CSP nonce.
23
+ def snippet(endpoint:, locale:, active:, nonce: nil)
22
24
  config = {
23
25
  endpoint: endpoint,
24
26
  locale: locale.to_s,
@@ -26,9 +28,10 @@ module I18nFeedback
26
28
  showPill: I18nFeedback.config.show_pill ? true : false,
27
29
  pillLabel: I18nFeedback.config.pill_label
28
30
  }
31
+ nonce_attr = nonce ? %( nonce="#{nonce}") : ''
29
32
 
30
- %(<script data-i18n-feedback>window.__i18nFeedback=#{config.to_json};</script>) +
31
- %(<script data-i18n-feedback-widget>#{javascript}</script>)
33
+ %(<script data-i18n-feedback#{nonce_attr}>window.__i18nFeedback=#{config.to_json};</script>) +
34
+ %(<script data-i18n-feedback-widget#{nonce_attr}>#{javascript}</script>)
32
35
  end
33
36
  end
34
37
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: i18n_feedback
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yaroslav Shmarov