html-pipeline 3.0.0.pre3 → 3.0.0.pre5

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: 613a099c0290d87932d2bbaf78052d8c472518bb911d82fe651ad78a3cc32ee9
4
- data.tar.gz: d03826dc83afb689e87395d3a365a24fd5b3608e3a29b632a79a5928acb84a2b
3
+ metadata.gz: 76b152d297b41b59af64604d1e0b034734c3ce6f3de999b1e614de96f500ecab
4
+ data.tar.gz: 5d06fbfb10d4390bec9b0c7efffadea4c0e7cf1aaf8ff4e57b23c4b2599bd928
5
5
  SHA512:
6
- metadata.gz: 35ce289f0ca10929fba016a5dd0d7c0a6bf0d8f8d4390385590c0937190df67605b96b474a477a54feb5192a54fc5b299940d264483700a9c5deac04cff1b9e1
7
- data.tar.gz: dbddce89afcb5f0291d28c9b24b4a2e4f25ea847d8960dc06a11f0c6cfd6cf2feb169f406fd69ca5f25a3eabc4338ce0cf7f2b94fa2147c682135bb6dee70728
6
+ metadata.gz: b4e943345b5febc342cd26417419982be10d2bc1e393e5783c280e06333db6d0e74a92b7d3fc173e84139fa9bc34f534f8823518b2a54ce7911e2e3e94d8dd86
7
+ data.tar.gz: 7f0fcf7e8821f86acd723a402b5911a3d667a09dd1013ae452a5494395f7535cc30a3bf1b5dca5aaac2c6bb54c103ad62d5ffdaf7f52c4ece182f553ddc810fd
@@ -15,6 +15,3 @@ updates:
15
15
  time: "09:00"
16
16
  timezone: "Etc/UTC"
17
17
  open-pull-requests-limit: 10
18
- allow:
19
- - dependency-name: "*"
20
- dependency-type: "production"
@@ -9,26 +9,5 @@ permissions:
9
9
 
10
10
  jobs:
11
11
  dependabot:
12
- name: Dependabot
13
- runs-on: ubuntu-latest
14
-
15
- if: ${{ github.actor == 'dependabot[bot]' }}
16
- steps:
17
- - name: Fetch Dependabot metadata
18
- id: dependabot-metadata
19
- uses: dependabot/fetch-metadata@v1
20
- with:
21
- github-token: "${{ secrets.GITHUB_TOKEN }}"
22
-
23
- - name: Approve Dependabot PR
24
- if: ${{steps.dependabot-metadata.outputs.update-type != 'version-update:semver-major'}}
25
- run: gh pr review --approve "$PR_URL"
26
- env:
27
- PR_URL: ${{github.event.pull_request.html_url}}
28
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29
-
30
- - name: Merge Dependabot PR
31
- run: gh pr merge --auto --squash "$PR_URL"
32
- env:
33
- PR_URL: ${{ github.event.pull_request.html_url }}
34
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
12
+ uses: yettoapp/actions/.github/workflows/automerge_dependabot.yml@main
13
+ secrets: inherit
@@ -0,0 +1,22 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+
6
+ permissions:
7
+ contents: read
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - uses: actions/checkout@v3
15
+
16
+ - name: Set up Ruby
17
+ uses: yettoapp/actions/setup-languages@main
18
+ with:
19
+ ruby: true
20
+
21
+ - name: Run tests
22
+ run: bundle exec rake test
@@ -13,11 +13,11 @@ jobs:
13
13
  runs-on: ubuntu-latest
14
14
  steps:
15
15
  - uses: actions/checkout@v3
16
- - uses: ruby/setup-ruby@v1
16
+
17
+ - name: Set up Ruby
18
+ uses: yettoapp/actions/setup-languages@main
17
19
  with:
18
- ruby-version: 3.1.0
19
- rubygems: latest
20
- bundler-cache: true
21
- - run: bundle install
20
+ ruby: true
21
+
22
22
  - name: Rubocop
23
23
  run: bundle exec rake rubocop
@@ -0,0 +1,19 @@
1
+ name: Release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ push:
6
+ branches:
7
+ - main
8
+ paths:
9
+ - "lib/html_pipeline/version.rb"
10
+
11
+ jobs:
12
+ ruby:
13
+ uses: yettoapp/actions/.github/workflows/ruby_gem_release.yml@main
14
+ secrets:
15
+ rubygems_api_key: ${{ secrets.RUBYGEMS_API_BOT_KEY }}
16
+ gh_token: ${{ secrets.GITHUB_TOKEN }}
17
+ with:
18
+ gem_name: html-pipeline
19
+ version_filepath: lib/html_pipeline/version.rb
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.2.1
@@ -0,0 +1,8 @@
1
+ {
2
+ "[markdown]": {
3
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
4
+ },
5
+ "[ruby]": {
6
+ "editor.defaultFormatter": "Shopify.ruby-lsp"
7
+ }
8
+ }
data/Gemfile CHANGED
@@ -28,7 +28,7 @@ end
28
28
 
29
29
  group :test do
30
30
  gem "commonmarker", "~> 1.0.0.pre7", require: false
31
- gem "gemoji", "~> 3.0", require: false
31
+ gem "gemoji", "~> 4.1", require: false
32
32
  gem "gemojione", "~> 4.3", require: false
33
33
 
34
34
  gem "minitest"
@@ -38,5 +38,5 @@ group :test do
38
38
  gem "nokogiri", "~> 1.13"
39
39
 
40
40
  gem "minitest-focus", "~> 1.1"
41
- gem "rouge", "~> 3.1", require: false
41
+ gem "rouge", "~> 4.1", require: false
42
42
  end
data/README.md CHANGED
@@ -1,23 +1,31 @@
1
- # HTMLPipeline
1
+ # HTML-Pipeline
2
2
 
3
3
  > **Note**
4
- > This README refers to the behavior in the new 3.0.0.pre1 gem.
4
+ > This README refers to the behavior in the new 3.0.0.pre gem.
5
5
 
6
6
  HTML processing filters and utilities. This module is a small
7
7
  framework for defining CSS-based content filters and applying them to user
8
8
  provided content.
9
9
 
10
- [Although this project was started at GitHub](https://github.com/blog/1311-html-pipeline-chainable-content-filters), they no longer do. This gem must be considered standalone and independent from GitHub.
11
-
12
- - [Installation](#installation)
13
- - [Usage](#usage)
14
- - [More Examples](#more-examples)
15
- - [Filters](#filters)
16
- - [Dependencies](#dependencies)
17
- - [Documentation](#documentation)
18
- - [Instrumenting](#instrumenting)
19
- - [Third Party Extensions](#third-party-extensions)
20
- - [FAQ](#faq)
10
+ [Although this project was started at GitHub](https://github.com/blog/1311-html-pipeline-chainable-content-filters), they no longer use it. This gem must be considered standalone and independent from GitHub.
11
+
12
+ - [HTML-Pipeline](#html-pipeline)
13
+ - [Installation](#installation)
14
+ - [Usage](#usage)
15
+ - [More Examples](#more-examples)
16
+ - [Filters](#filters)
17
+ - [TextFilters](#textfilters)
18
+ - [ConvertFilter](#convertfilter)
19
+ - [Sanitization](#sanitization)
20
+ - [NodeFilters](#nodefilters)
21
+ - [Dependencies](#dependencies)
22
+ - [Documentation](#documentation)
23
+ - [Instrumenting](#instrumenting)
24
+ - [Third Party Extensions](#third-party-extensions)
25
+ - [FAQ](#faq)
26
+ - [1. Why doesn't my pipeline work when there's no root element in the document?](#1-why-doesnt-my-pipeline-work-when-theres-no-root-element-in-the-document)
27
+ - [2. How do I customize an allowlist for `SanitizationFilter`s?](#2-how-do-i-customize-an-allowlist-for-sanitizationfilters)
28
+ - [Contributors](#contributors)
21
29
 
22
30
  ## Installation
23
31
 
@@ -231,6 +239,7 @@ end
231
239
  For more information on how to write effective `NodeFilter`s, refer to the provided filters, and see the underlying lib, [Selma](https://www.github.com/gjtorikian/selma) for more information.
232
240
 
233
241
  - `AbsoluteSourceFilter`: replace relative image urls with fully qualified versions
242
+ - `AssetProxyFilter`: replace image links with an encoded link to an asset server
234
243
  - `EmojiFilter`: converts `:<emoji>:` to [emoji](http://www.emoji-cheat-sheet.com/)
235
244
  - (Note: the included `MarkdownFilter` will already convert emoji)
236
245
  - `HttpsFilter`: Replacing http urls with https versions
@@ -25,7 +25,7 @@ Gem::Specification.new do |gem|
25
25
  "rubygems_mfa_required" => "true",
26
26
  }
27
27
 
28
- gem.add_dependency("selma", "~> 0.0.1")
28
+ gem.add_dependency("selma", "~> 0.1")
29
29
  gem.add_dependency("zeitwerk", "~> 2.5")
30
30
 
31
31
  gem.post_install_message = <<~MSG
@@ -12,6 +12,6 @@ class HTMLPipeline
12
12
  def call(text, context: {}, result: {})
13
13
  new(context: context, result: result).call(text)
14
14
  end
15
- end
15
+ end
16
16
  end
17
17
  end
@@ -49,7 +49,7 @@ class HTMLPipeline
49
49
  def call(input, context: {})
50
50
  raise NoMethodError
51
51
  end
52
- end
52
+ end
53
53
  # Make sure the context has everything we need. Noop: Subclasses can override.
54
54
  def validate; end
55
55
 
@@ -4,6 +4,19 @@ require "uri"
4
4
 
5
5
  class HTMLPipeline
6
6
  class NodeFilter
7
+ # HTML Filter for replacing relative and root relative image URLs with
8
+ # fully qualified URLs
9
+ #
10
+ # This is useful if an image is root relative but should really be going
11
+ # through a cdn, or if the content for the page assumes the host is known
12
+ # i.e. scraped webpages and some RSS feeds.
13
+ #
14
+ # Context options:
15
+ # :image_base_url - Base URL for image host for root relative src.
16
+ # :image_subpage_url - For relative src.
17
+ #
18
+ # This filter does not write additional information to the context.
19
+ # Note: This filter would need to be run before AssetProxyFilter.
7
20
  class AbsoluteSourceFilter < NodeFilter
8
21
  SELECTOR = Selma::Selector.new(match_element: "img")
9
22
 
@@ -11,19 +24,6 @@ class HTMLPipeline
11
24
  SELECTOR
12
25
  end
13
26
 
14
- # HTML Filter for replacing relative and root relative image URLs with
15
- # fully qualified URLs
16
- #
17
- # This is useful if an image is root relative but should really be going
18
- # through a cdn, or if the content for the page assumes the host is known
19
- # i.e. scraped webpages and some RSS feeds.
20
- #
21
- # Context options:
22
- # :image_base_url - Base URL for image host for root relative src.
23
- # :image_subpage_url - For relative src.
24
- #
25
- # This filter does not write additional information to the context.
26
- # This filter would need to be run before CamoFilter.
27
27
  def handle_element(element)
28
28
  src = element["src"]
29
29
  return if src.nil? || src.empty?
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openssl"
4
+
5
+ class HTMLPipeline
6
+ class NodeFilter
7
+ # Proxy images/assets to another server, such as
8
+ # [cactus/go-camo](https://github.com/cactus/go-camo#).
9
+ # Reduces mixed content warnings as well as hiding the customer's
10
+ # IP address when requesting images.
11
+ # Copies the original img `src` to `data-canonical-src` then replaces the
12
+ # `src` with a new url to the proxy server.
13
+ #
14
+ # Based on https://github.com/gjtorikian/html-pipeline/blob/v2.14.3/lib/html/pipeline/camo_filter.rb
15
+ class AssetProxyFilter < NodeFilter
16
+ SELECTOR = Selma::Selector.new(match_element: "img")
17
+
18
+ def selector
19
+ SELECTOR
20
+ end
21
+
22
+ def handle_element(element)
23
+ original_src = element["src"]
24
+ return unless original_src
25
+
26
+ begin
27
+ uri = URI.parse(original_src)
28
+ rescue StandardError
29
+ return
30
+ end
31
+
32
+ return if uri.host.nil? && !original_src.start_with?("///")
33
+ return if asset_host_allowed?(uri.host)
34
+
35
+ element["src"] = asset_proxy_url(original_src)
36
+ element["data-canonical-src"] = original_src
37
+ end
38
+
39
+ def validate
40
+ needs(:asset_proxy, :asset_proxy_secret_key)
41
+ end
42
+
43
+ def asset_host_allowed?(host)
44
+ context[:asset_proxy_domain_regexp] ? context[:asset_proxy_domain_regexp].match?(host) : false
45
+ end
46
+
47
+ class << self
48
+ # This helps setup the context. It's not needed if you're always providing
49
+ # all the necessary keys in the context. One example would be to override
50
+ # this and pull the settings from a set of global application settings.
51
+ def transform_context(context, proxy_settings = {})
52
+ context[:asset_proxy] = proxy_settings[:url] if proxy_settings[:url]
53
+ context[:asset_proxy_secret_key] = proxy_settings[:secret_key] if proxy_settings[:secret_key]
54
+
55
+ allowlist = determine_allowlist(proxy_settings)
56
+ context[:asset_proxy_domain_regexp] ||= compile_allowlist(allowlist)
57
+
58
+ context
59
+ end
60
+
61
+ def compile_allowlist(domain_list)
62
+ return if domain_list.empty?
63
+
64
+ escaped = domain_list.map { |domain| Regexp.escape(domain).gsub("\\*", ".*?") }
65
+ Regexp.new("^(#{escaped.join("|")})$", Regexp::IGNORECASE)
66
+ end
67
+
68
+ def determine_allowlist(proxy_settings)
69
+ proxy_settings[:allowlist] || []
70
+ end
71
+ end
72
+
73
+ private def asset_proxy_url(url)
74
+ "#{context[:asset_proxy]}/#{asset_url_hash(url)}/#{hexencode(url)}"
75
+ end
76
+
77
+ private def asset_url_hash(url)
78
+ OpenSSL::HMAC.hexdigest("sha1", context[:asset_proxy_secret_key], url)
79
+ end
80
+
81
+ private def hexencode(str)
82
+ str.unpack1("H*")
83
+ end
84
+ end
85
+ end
86
+ end
@@ -38,7 +38,7 @@ class HTMLPipeline
38
38
  yield match, login
39
39
  end
40
40
  end
41
- end
41
+ end
42
42
  # Hash that contains all of the mention patterns used by the pipeline
43
43
  MENTION_PATTERNS = Hash.new do |hash, key|
44
44
  hash[key] = %r{
@@ -35,7 +35,7 @@ class HTMLPipeline
35
35
  yield match, org, team
36
36
  end
37
37
  end
38
- end
38
+ end
39
39
 
40
40
  # Default pattern used to extract team names from text. The value can be
41
41
  # overridden by providing the team_pattern variable in the context. To
@@ -183,6 +183,6 @@ class HTMLPipeline
183
183
  sanitization_config = Selma::Sanitizer.new(config)
184
184
  Selma::Rewriter.new(sanitizer: sanitization_config).rewrite(html)
185
185
  end
186
- end
186
+ end
187
187
  end
188
188
  end
@@ -16,6 +16,6 @@ class HTMLPipeline
16
16
  def call(input, context: {}, result: {})
17
17
  new(input, context: context, result: result).call
18
18
  end
19
- end
19
+ end
20
20
  end
21
21
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class HTMLPipeline
4
- VERSION = "3.0.0.pre3"
4
+ VERSION = "3.0.0.pre5"
5
5
  end
data/lib/html_pipeline.rb CHANGED
@@ -81,7 +81,7 @@ class HTMLPipeline
81
81
  def define_dependency_loaded_method(name, value)
82
82
  self.class.define_method(:"#{name}_loaded?", -> { value })
83
83
  end
84
- end
84
+ end
85
85
  # Public: Returns an Array of Filter objects for this Pipeline.
86
86
  attr_reader :text_filters, :node_filters
87
87
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: html-pipeline
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0.pre3
4
+ version: 3.0.0.pre5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garen J. Torikian
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-15 00:00:00.000000000 Z
11
+ date: 2023-06-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: selma
@@ -16,14 +16,15 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.0.1
19
+ version: '0.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.0.1
26
+ version: '0.1'
27
+ force_ruby_platform: false
27
28
  - !ruby/object:Gem::Dependency
28
29
  name: zeitwerk
29
30
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +39,7 @@ dependencies:
38
39
  - - "~>"
39
40
  - !ruby/object:Gem::Version
40
41
  version: '2.5'
42
+ force_ruby_platform: false
41
43
  description: HTML processing filters and utilities
42
44
  email:
43
45
  - gjtorikian@gmail.com
@@ -48,11 +50,13 @@ files:
48
50
  - ".github/FUNDING.yml"
49
51
  - ".github/dependabot.yml"
50
52
  - ".github/workflows/automerge.yml"
53
+ - ".github/workflows/ci.yml"
51
54
  - ".github/workflows/lint.yml"
52
- - ".github/workflows/tag_and_release.yml"
53
- - ".github/workflows/test.yml"
55
+ - ".github/workflows/publish.yml"
54
56
  - ".gitignore"
55
57
  - ".rubocop.yml"
58
+ - ".ruby-version"
59
+ - ".vscode/settings.json"
56
60
  - CHANGELOG.md
57
61
  - Gemfile
58
62
  - LICENSE.txt
@@ -67,6 +71,7 @@ files:
67
71
  - lib/html_pipeline/filter.rb
68
72
  - lib/html_pipeline/node_filter.rb
69
73
  - lib/html_pipeline/node_filter/absolute_source_filter.rb
74
+ - lib/html_pipeline/node_filter/asset_proxy_filter.rb
70
75
  - lib/html_pipeline/node_filter/emoji_filter.rb
71
76
  - lib/html_pipeline/node_filter/https_filter.rb
72
77
  - lib/html_pipeline/node_filter/image_max_width_filter.rb
@@ -106,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
111
  - !ruby/object:Gem::Version
107
112
  version: 3.3.22
108
113
  requirements: []
109
- rubygems_version: 3.3.26
114
+ rubygems_version: 3.4.13
110
115
  signing_key:
111
116
  specification_version: 4
112
117
  summary: Helpers for processing content through a chain of filters
@@ -1,70 +0,0 @@
1
- name: Tag and Release
2
-
3
- on:
4
- workflow_dispatch:
5
- push:
6
- branches:
7
- - main
8
- paths:
9
- - "lib/html_pipeline/version.rb"
10
-
11
- jobs:
12
- release:
13
- env:
14
- GEM_NAME: html-pipeline
15
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
16
- GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_API_BOT_KEY }}
17
- runs-on: ubuntu-latest
18
- steps:
19
- - uses: actions/checkout@v3
20
-
21
- - name: Set up Ruby 3.1
22
- uses: ruby/setup-ruby@v1
23
- with:
24
- ruby-version: 3.1
25
- bundler-cache: true
26
-
27
- - name: Configure Git
28
- run: |
29
- git config --local user.email "actions@github.com"
30
- git config --local user.name "Actions Auto Build"
31
-
32
- - name: Get current version
33
- id: version-label
34
- run: |
35
- VERSION=$(grep VERSION lib/html_pipeline/version.rb | head -n 1 | cut -d'"' -f2)
36
- echo "version=${VERSION}" >> $GITHUB_OUTPUT
37
-
38
- - name: Create tag
39
- run: |
40
- git tag -a v${{ steps.version-label.outputs.version }} -m "Release v${{ steps.version-label.outputs.version }}"
41
- git push origin --tags
42
-
43
- - name: Generate CHANGELOG.md
44
- id: changelog
45
- run: script/generate_changelog
46
-
47
- - name: Commit & Push Changelog
48
- run: |
49
- git config --local user.email "actions@github.com"
50
- git config --local user.name "Actions Auto Build"
51
- git add -f CHANGELOG.md
52
- git commit -m "docs: update changelog" || true
53
- git push
54
-
55
- - name: Publish release
56
- env:
57
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
58
- run: |
59
- gh release create v${{ steps.version-label.outputs.version }} --generate-notes
60
-
61
- - name: Publish to RubyGems
62
- run: |
63
- mkdir -p $HOME/.gem
64
- touch $HOME/.gem/credentials
65
- chmod 0600 $HOME/.gem/credentials
66
- printf -- "---\n:rubygems_api_key: ${RUBYGEMS_API_BOT_KEY}\n" > $HOME/.gem/credentials
67
- bundle exec rake package
68
- for gem in pkg/html-pipeline-${{ steps.version-label.outputs.version }}*.gem ; do
69
- gem push "$gem" --host https://rubygems.org
70
- done
@@ -1,33 +0,0 @@
1
- name: Tests
2
-
3
- on:
4
- pull_request:
5
-
6
- permissions:
7
- contents: read
8
-
9
- jobs:
10
- test:
11
- runs-on: ubuntu-latest
12
-
13
- strategy:
14
- fail-fast: true
15
- matrix:
16
- ruby-version:
17
- - 3.1.0
18
-
19
- steps:
20
- - uses: actions/checkout@v3
21
-
22
- - name: Set up Ruby ${{ matrix.ruby-version }}
23
- uses: ruby/setup-ruby@v1
24
- with:
25
- ruby-version: ${{ matrix.ruby-version }}
26
- rubygems: latest
27
- bundler-cache: true
28
-
29
- - name: Install dependencies
30
- run: bundle install
31
-
32
- - name: Run tests
33
- run: bundle exec rake test