Skip to content
1 change: 1 addition & 0 deletions Manifest.txt
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ lib/publify_core/text_filter/markdown.rb
lib/publify_core/text_filter/markdown_smartquotes.rb
lib/publify_core/text_filter/none.rb
lib/publify_core/text_filter/smartypants.rb
lib/publify_core/text_transformer.rb
lib/publify_core/version.rb
lib/publify_guid.rb
lib/publify_plugins.rb
Expand Down
2 changes: 1 addition & 1 deletion app/models/article.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class Article < Content
def set_permalink
return if draft? || permalink.present?

self.permalink = title.to_permalink
self.permalink = PublifyCore::TextTransformer.to_permalink(title)
end

def has_child?
Expand Down
2 changes: 1 addition & 1 deletion app/models/content_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def excerpt_text(length = 160)
html(:all)
end

text = text.strip_html
text = PublifyCore::TextTransformer.strip_html(text)

text.slice(0, length) +
(text.length > length ? "..." : "")
Expand Down
7 changes: 5 additions & 2 deletions app/models/note.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ def link_to_mentioned_user(base_url, login)
end

def set_permalink
self.permalink = "#{id}-#{body.to_permalink[0..79]}" if permalink.blank?
if permalink.blank?
base_permalink = PublifyCore::TextTransformer.to_permalink(body)[0..79]
self.permalink = "#{id}-#{base_permalink}"
end
save
end

Expand Down Expand Up @@ -122,7 +125,7 @@ def truncate(message, length)
end

def twitter_message
base_message = body.strip_html
base_message = PublifyCore::TextTransformer.strip_html(body)
if too_long?("#{base_message} (#{short_link})")
max_length = 140 - "... (#{redirect.from_url})".length - 1
"#{truncate(base_message, max_length)}... (#{redirect.from_url})"
Expand Down
2 changes: 1 addition & 1 deletion app/models/page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Page < Content
after_save :shorten_url

def set_permalink
self.name = title.to_permalink if name.blank?
self.name = PublifyCore::TextTransformer.to_permalink(title) if name.blank?
end

content_fields :body
Expand Down
2 changes: 1 addition & 1 deletion app/models/post_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ def name_is_not_read
end

def sanitize_title
self.permalink = name.to_permalink
self.permalink = PublifyCore::TextTransformer.to_permalink(name)
end
end
4 changes: 2 additions & 2 deletions app/models/tag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def self.create_from_article!(article)
x.first.tr("\"'", "")
end
tagwords.uniq.each do |tagword|
tagname = tagword.to_url
tagname = PublifyCore::TextTransformer.to_url(tagword)
tags << article.blog.tags.find_or_create_by(name: tagname) do |tag|
tag.display_name = tagword
end
Expand All @@ -35,7 +35,7 @@ def self.create_from_article!(article)

def ensure_naming_conventions
self.display_name = name if display_name.blank?
self.name = display_name.to_url if display_name.present?
self.name = PublifyCore::TextTransformer.to_url(display_name) if display_name.present?
end

def self.find_all_with_content_counters
Expand Down
2 changes: 1 addition & 1 deletion app/views/admin/notes/_note.html.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<tr>
<td>
<%= h(note.body.strip_html.slice(0..140)) %>
<%= h(note.excerpt_text(140)) %>
</td>
<td>
<%= author_link(note) %><br>
Expand Down
7 changes: 7 additions & 0 deletions lib/publify_core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
require "publify_core/text_filter/markdown_smartquotes"
require "publify_core/text_filter/smartypants"
require "publify_core/string_ext"
require "publify_core/text_transformer"

require "bootstrap"
require "carrierwave"
Expand Down Expand Up @@ -44,4 +45,10 @@ module PublifyCore

# Mime type is fully determined by url
Engine.config.action_dispatch.ignore_accept_header = true

def self.deprecator
@deprecator ||= ActiveSupport::Deprecation.new("10.1", "PublifyCore")
end

deprecator.deprecate_methods PublifyCore::StringExt, :to_permalink, :to_url, :strip_html
end
33 changes: 3 additions & 30 deletions lib/publify_core/string_ext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,20 @@
# FIXME: Replace with helpers and/or methods provided by Rails
module PublifyCore
module StringExt
ACCENTS = { %w(á à â ä ã Ã Ä Â À) => "a",
%w(é è ê ë Ë É È Ê) => "e",
%w(í ì î ï I Î Ì) => "i",
%w(ó ò ô ö õ Õ Ö Ô Ò) => "o",
["œ"] => "oe",
["ß"] => "ss",
%w(ú ù û ü U Û Ù) => "u",
%w(ç Ç) => "c" }.freeze

def to_permalink
string = self
ACCENTS.each do |key, value|
string = string.tr(key.join, value)
end
string = string.tr("'", "-")
string.gsub(/<[^>]*>/, "").to_url
PublifyCore::TextTransformer.to_permalink(self)
end

# Returns a-string-with-dashes when passed 'a string with dashes'.
# All special chars are stripped in the process
def to_url
return if nil?

s = downcase.tr("\"'", "")
s = s.gsub(/\P{Word}/, " ")
s.strip.tr_s(" ", "-").tr(" ", "-").sub(/^$/, "-")
PublifyCore::TextTransformer.to_url(self)
end

def to_title(item, settings, params)
TitleBuilder.new(self).build(item, settings, params)
end

# Strips any html markup from a string
TYPO_TAG_KEY = TYPO_ATTRIBUTE_KEY = /[\w:_-]+/
TYPO_ATTRIBUTE_VALUE = /(?:[A-Za-z0-9]+|(?:'[^']*?'|"[^"]*?"))/
TYPO_ATTRIBUTE = /(?:#{TYPO_ATTRIBUTE_KEY}(?:\s*=\s*#{TYPO_ATTRIBUTE_VALUE})?)/
TYPO_ATTRIBUTES = /(?:#{TYPO_ATTRIBUTE}(?:\s+#{TYPO_ATTRIBUTE})*)/
TAG = %r{<[!/?\[]?(?:#{TYPO_TAG_KEY}|--)(?:\s+#{TYPO_ATTRIBUTES})?\s*(?:[!/?\]]+|--)?>}

def strip_html
gsub(TAG, "").gsub(/\s+/, " ").strip
PublifyCore::TextTransformer.strip_html(self)
end
end
end
Expand Down
45 changes: 45 additions & 0 deletions lib/publify_core/text_transformer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# frozen_string_literal: true

module PublifyCore
module TextTransformer
module_function

ACCENTS = { %w(á à â ä ã Ã Ä Â À) => "a",
%w(é è ê ë Ë É È Ê) => "e",
%w(í ì î ï I Î Ì) => "i",
%w(ó ò ô ö õ Õ Ö Ô Ò) => "o",
["œ"] => "oe",
["ß"] => "ss",
%w(ú ù û ü U Û Ù) => "u",
%w(ç Ç) => "c" }.freeze

def to_permalink(string)
ACCENTS.each do |key, value|
string = string.tr(key.join, value)
end
string = string.tr("'", "-")
to_url(string.gsub(/<[^>]*>/, ""))

Check failure

Code scanning / CodeQL

Polynomial regular expression used on uncontrolled data High

This
regular expression
that depends on a
library input
may run slow on strings starting with '<' and with many repetitions of '<'.

Check failure

Code scanning / CodeQL

Incomplete multi-character sanitization High

This string may still contain
<script
, which may cause an HTML element injection vulnerability.
end

# Returns a-string-with-dashes when passed 'a string with dashes'.
# All special chars are stripped in the process
def to_url(string)
return if string.nil?

s = string.downcase.tr("\"'", "")
s = s.gsub(/\P{Word}/, " ")
s.strip.tr_s(" ", "-").tr(" ", "-").sub(/^$/, "-")
end

# Strips any html markup from a string
TYPO_TAG_KEY = TYPO_ATTRIBUTE_KEY = /[\w:_-]+/
TYPO_ATTRIBUTE_VALUE = /(?:[A-Za-z0-9]+|(?:'[^']*?'|"[^"]*?"))/
TYPO_ATTRIBUTE = /(?:#{TYPO_ATTRIBUTE_KEY}(?:\s*=\s*#{TYPO_ATTRIBUTE_VALUE})?)/
TYPO_ATTRIBUTES = /(?:#{TYPO_ATTRIBUTE}(?:\s+#{TYPO_ATTRIBUTE})*)/
TAG = %r{<[!/?\[]?(?:#{TYPO_TAG_KEY}|--)(?:\s+#{TYPO_ATTRIBUTES})?\s*(?:[!/?\]]+|--)?>}

def strip_html(string)
string.gsub(TAG, "").gsub(/\s+/, " ").strip
end
end
end
10 changes: 0 additions & 10 deletions spec/models/article_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -132,16 +132,6 @@
expect(not_found).to be_nil
end

it "test_strip_title" do
expect("Article-3".to_url).to eq "article-3"
expect("Article 3!?#".to_url).to eq "article-3"
expect("There is Sex in my Violence!".to_url).to eq "there-is-sex-in-my-violence"
expect("-article-".to_url).to eq "article"
expect("Lorem ipsum dolor sit amet, consectetaur adipisicing elit".to_url)
.to eq "lorem-ipsum-dolor-sit-amet-consectetaur-adipisicing-elit"
expect("My Cat's Best Friend".to_url).to eq "my-cats-best-friend"
end

describe "#set_permalink" do
it "works for simple cases" do
a = blog.articles.build(title: "Article 3!", state: :published)
Expand Down
20 changes: 15 additions & 5 deletions spec/publify_core/string_ext_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,36 @@
require "rails_helper"

RSpec.describe PublifyCore::StringExt do
include ActiveSupport::Testing::Deprecation

describe "#to_permalink" do
it "builds a nice permalink from an accentuated string" do
expect("L'été s'ra chaud, l'été s'ra chaud".to_permalink)
.to eq("l-ete-s-ra-chaud-l-ete-s-ra-chaud")
assert_deprecated(/to_permalink/, PublifyCore.deprecator) do
expect("L'été s'ra chaud, l'été s'ra chaud".to_permalink)
.to eq("l-ete-s-ra-chaud-l-ete-s-ra-chaud")
end
end
end

describe "to_url" do
it "gives a proper space-less, trimmed URL" do
expect(" this is a sentence ".to_url).to eq("this-is-a-sentence")
assert_deprecated(/to_url/, PublifyCore.deprecator) do
expect(" this is a sentence ".to_url).to eq("this-is-a-sentence")
end
end
end

describe "strip_html" do
it "renders text only" do
expect("<a href='http://myblog.com'>my blog</a>".strip_html).to eq("my blog")
assert_deprecated(/strip_html/, PublifyCore.deprecator) do
expect("<a href='http://myblog.com'>my blog</a>".strip_html).to eq("my blog")
end
end

it "does not remove a > from a numeric comparison" do
expect("5 < 6 > 4".strip_html).to eq("5 < 6 > 4")
assert_deprecated(/strip_html/, PublifyCore.deprecator) do
expect("5 < 6 > 4".strip_html).to eq("5 < 6 > 4")
end
end
end
end
43 changes: 43 additions & 0 deletions spec/publify_core/text_transformer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# frozen_string_literal: true

require "rails_helper"

RSpec.describe PublifyCore::TextTransformer do
describe "#to_permalink" do
it "builds a nice permalink from an accentuated string" do
expect(described_class.to_permalink("L'été s'ra chaud, l'été s'ra chaud"))
.to eq("l-ete-s-ra-chaud-l-ete-s-ra-chaud")
end
end

describe "to_url" do
it "gives a proper space-less, trimmed URL" do
expect(described_class.to_url(" this is a sentence ")).to eq("this-is-a-sentence")
end

it "test_strip_title" do
aggregate_failures do
expect(described_class.to_url("Article-3")).to eq "article-3"
expect(described_class.to_url("Article 3!?#")).to eq "article-3"
expect(described_class.to_url("There is Sex in my Violence!"))
.to eq "there-is-sex-in-my-violence"
expect(described_class.to_url("-article-")).to eq "article"
expect(described_class.to_url("Lorem ipsum dolor sit amet," \
" consectetaur adipisicing elit"))
.to eq "lorem-ipsum-dolor-sit-amet-consectetaur-adipisicing-elit"
expect(described_class.to_url("My Cat's Best Friend")).to eq "my-cats-best-friend"
end
end
end

describe "strip_html" do
it "renders text only" do
expect(described_class.strip_html("<a href='http://myblog.com'>my blog</a>"))
.to eq("my blog")
end

it "does not remove a > from a numeric comparison" do
expect(described_class.strip_html("5 < 6 > 4")).to eq("5 < 6 > 4")
end
end
end