publify_core 9.2.6 → 9.2.9

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of publify_core might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: da6da95f7716a807eb81fc3c6684945b4afeb75dae12256d6e8e0341dacc8108
4
- data.tar.gz: 16590e78cb4f249017cad7df86fb72fb6ebfc90eb3c9a55d9fdac017a708c203
3
+ metadata.gz: 72e8560336bbbbfd2c517840b744e34509782d0f4d6db7cde5ee607230770b65
4
+ data.tar.gz: 886335b6900c26cfc579bf4197304b0e30cb8eedbe4c362a5394d153cb746487
5
5
  SHA512:
6
- metadata.gz: 9ba6b4fb3315f76bb3ffba8f2c423fe4d0a2a57fda992a1bf0ce92df49dad52f78e0d72955a75dfcac58ab2a693ecc46f419dbb1c59678ceb86ed8f0c280140d
7
- data.tar.gz: 4704c65615d660a2a10f8827970710baeb5438917adeb8d37e7a10a1534626b08b1a45049486398163739c23929d5629d71a41198d28dd46572e5aa3d6260f4d
6
+ metadata.gz: 695ae9d70e7cb24e7b10b4c2efaaff9d13e32bdcde17e5fcc4be6aab288f5d8d1a0b74465b54f79dd28cf1fbc55a3c7f0e80d02074e8706e863bbba15ddd0368
7
+ data.tar.gz: 3044549f33cfe4db50562be0d0441e3fc952b433181eefc861768cbeb3072b11be25780c40b2977572ce69d38df945af520c09343d294920eccdf17198b9d143
data/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 9.2.9 / 2022-05-22
4
+
5
+ * Fix admin article access control [#1065](https://github.com/publify/publify/pull/1065)
6
+ * Refuse html files as resources even if declared to be plain text [#1066](https://github.com/publify/publify/pull/1066)
7
+
8
+ ## 9.2.8 / 2022-05-14
9
+
10
+ * Fix password protected article reveal [#1049](https://github.com/publify/publify/pull/1049)
11
+ * Disallow comments on draft articles [#1048](https://github.com/publify/publify/pull/1048)
12
+ * Clean up Feedback validation [#1051](https://github.com/publify/publify/pull/1051)
13
+ * Disallow images in comments [#1054](https://github.com/publify/publify/pull/1054)
14
+ * Fix password reset process [#1055](https://github.com/publify/publify/pull/1055)
15
+ * Hide bodies of password-protected articles in search results [#1057](https://github.com/publify/publify/pull/1057)
16
+ * Provide correct `article_id` input in bulkops form [#1058](https://github.com/publify/publify/pull/1058)
17
+ * Do not create article meta description for password-protected articles [#1061](https://github.com/publify/publify/pull/1061)
18
+
19
+ ## 9.2.7 / 2022-02-07
20
+
21
+ * Fix setting the article password from the Admin [#1044](https://github.com/publify/publify/pull/1044)
22
+
3
23
  ## 9.2.6 / 2022-01-07
4
24
 
5
25
  * Add documentation about use of the media library
@@ -0,0 +1,9 @@
1
+ // Show and hide spinners on Ajax requests.
2
+ $(document).ready(function() {
3
+ $('form.check_password').on('ajax:complete',
4
+ function(evt, xhr, stat) {
5
+ var form = evt.currentTarget;
6
+ var elem = document.getElementById(form.dataset["update"]);
7
+ elem.outerHTML = xhr.responseText;
8
+ })
9
+ });
@@ -7,5 +7,6 @@
7
7
  //= require jquery_ujs
8
8
  //= require lightbox
9
9
  //= require observe
10
+ //= require check_password
10
11
  //
11
12
  //= require_self
@@ -58,9 +58,9 @@ class Admin::ContentController < Admin::BaseController
58
58
  end
59
59
 
60
60
  def update
61
- return unless access_granted?(params[:id])
61
+ id = params[:id]
62
+ return unless access_granted?(id)
62
63
 
63
- id = params[:article][:id] || params[:id]
64
64
  @article = Article.find(id)
65
65
 
66
66
  if params[:article][:draft]
@@ -101,6 +101,7 @@ class Admin::ContentController < Admin::BaseController
101
101
  return false unless request.xhr?
102
102
 
103
103
  id = params[:article][:id] || params[:id]
104
+ return if id && !access_granted?(id)
104
105
 
105
106
  article_factory = Article::Factory.new(this_blog, current_user)
106
107
  @article = article_factory.get_or_build_from(id)
@@ -131,7 +132,7 @@ class Admin::ContentController < Admin::BaseController
131
132
  end
132
133
  end
133
134
 
134
- protected
135
+ private
135
136
 
136
137
  def fetch_fresh_or_existing_draft_for_article
137
138
  return unless @article.published? && @article.id
@@ -146,8 +147,6 @@ class Admin::ContentController < Admin::BaseController
146
147
 
147
148
  attr_accessor :resources, :resource
148
149
 
149
- private
150
-
151
150
  def load_resources
152
151
  @post_types = PostType.all
153
152
  @macros = TextFilterPlugin.macro_filters
@@ -180,6 +179,7 @@ class Admin::ContentController < Admin::BaseController
180
179
  :body_and_extended,
181
180
  :draft,
182
181
  :extended,
182
+ :password,
183
183
  :permalink,
184
184
  :published_at,
185
185
  :text_filter_name,
@@ -166,7 +166,10 @@ class ArticlesController < ContentController
166
166
  format.html do
167
167
  @comment = Comment.new
168
168
  @page_title = this_blog.article_title_template.to_title(@article, this_blog, params)
169
- @description = this_blog.article_desc_template.to_title(@article, this_blog, params)
169
+ if @article.password.blank?
170
+ @description = this_blog.article_desc_template.
171
+ to_title(@article, this_blog, params)
172
+ end
170
173
 
171
174
  @keywords = @article.tags.map(&:name).join(", ")
172
175
  render "articles/#{@article.post_type}"
@@ -7,11 +7,6 @@ class CommentsController < BaseController
7
7
  options = new_comment_defaults.merge comment_params.to_h
8
8
  @comment = @article.add_comment(options)
9
9
 
10
- unless current_user.nil? || session[:user_id].nil?
11
- # maybe useless, but who knows ?
12
- @comment.user_id = current_user.id if current_user.id == session[:user_id]
13
- end
14
-
15
10
  remember_author_info_for @comment
16
11
 
17
12
  partial = "/articles/comment_failed"
@@ -33,7 +28,7 @@ class CommentsController < BaseController
33
28
  @comment = @article.comments.build(comment_params)
34
29
  end
35
30
 
36
- protected
31
+ private
37
32
 
38
33
  def recaptcha_ok_for?(comment)
39
34
  use_recaptcha = comment.blog.use_recaptcha
@@ -43,7 +38,7 @@ class CommentsController < BaseController
43
38
  def new_comment_defaults
44
39
  { ip: request.remote_ip,
45
40
  author: "Anonymous",
46
- user: @current_user,
41
+ user: current_user,
47
42
  user_agent: request.env["HTTP_USER_AGENT"],
48
43
  referrer: request.env["HTTP_REFERER"],
49
44
  permalink: @article.permalink_url }.stringify_keys
@@ -204,7 +204,7 @@ class Article < Content
204
204
  end
205
205
 
206
206
  def comments_closed?
207
- !(allow_comments? && in_feedback_window?)
207
+ !(allow_comments? && published? && in_feedback_window?)
208
208
  end
209
209
 
210
210
  def html_urls
@@ -216,7 +216,7 @@ class Article < Content
216
216
  end
217
217
 
218
218
  def pings_closed?
219
- !(allow_pings? && in_feedback_window?)
219
+ !(allow_pings? && published? && in_feedback_window?)
220
220
  end
221
221
 
222
222
  # check if time to comment is open or not
@@ -38,7 +38,7 @@ class Comment < Feedback
38
38
  really_send_notifications
39
39
  end
40
40
 
41
- protected
41
+ private
42
42
 
43
43
  def article_allows_feedback?
44
44
  return true if article.allow_comments?
@@ -47,6 +47,14 @@ class Comment < Feedback
47
47
  false
48
48
  end
49
49
 
50
+ def blog_allows_feedback?
51
+ true
52
+ end
53
+
54
+ def check_article_closed_for_feedback
55
+ errors.add(:article, "Comment are closed") if article.comments_closed?
56
+ end
57
+
50
58
  def originator
51
59
  author
52
60
  end
@@ -11,11 +11,12 @@ class Feedback < ApplicationRecord
11
11
  include PublifyGuid
12
12
  include ContentBase
13
13
 
14
+ validate :article_allows_this_feedback, on: :create
14
15
  validate :feedback_not_closed, on: :create
15
16
  validates :article, presence: true
16
17
 
17
18
  before_save :correct_url, :classify_content
18
- before_create :create_guid, :article_allows_this_feedback
19
+ before_create :create_guid
19
20
 
20
21
  # TODO: Rename so it doesn't sound like only approved ham
21
22
  scope :ham, -> { where(state: %w(presumed_ham ham)) }
@@ -66,6 +67,10 @@ class Feedback < ApplicationRecord
66
67
  page(page).per(per_page)
67
68
  end
68
69
 
70
+ def self.allowed_tags
71
+ @allowed_tags ||= Rails::Html::SafeListSanitizer.allowed_tags - ["img"]
72
+ end
73
+
69
74
  def parent
70
75
  article
71
76
  end
@@ -85,7 +90,7 @@ class Feedback < ApplicationRecord
85
90
 
86
91
  def html_postprocess(_field, html)
87
92
  helper = ContentTextHelpers.new
88
- helper.sanitize(helper.auto_link(html))
93
+ helper.sanitize(helper.auto_link(html), tags: self.class.allowed_tags)
89
94
  end
90
95
 
91
96
  def correct_url
@@ -98,10 +103,6 @@ class Feedback < ApplicationRecord
98
103
  article && blog_allows_feedback? && article_allows_feedback?
99
104
  end
100
105
 
101
- def blog_allows_feedback?
102
- true
103
- end
104
-
105
106
  def akismet_options
106
107
  { type: self.class.to_s.downcase,
107
108
  author: originator,
@@ -200,7 +201,7 @@ class Feedback < ApplicationRecord
200
201
  end
201
202
 
202
203
  def feedback_not_closed
203
- errors.add(:article_id, "Comment are closed") if article.comments_closed?
204
+ check_article_closed_for_feedback
204
205
  end
205
206
 
206
207
  def send_notifications
@@ -24,10 +24,14 @@ class Trackback < Feedback
24
24
  def blog_allows_feedback?
25
25
  return true unless blog.global_pings_disable
26
26
 
27
- errors.add(:article, "Pings are disabled")
27
+ errors.add(:base, "Pings are disabled")
28
28
  false
29
29
  end
30
30
 
31
+ def check_article_closed_for_feedback
32
+ errors.add(:article, "Pings are closed") if article.pings_closed?
33
+ end
34
+
31
35
  def originator
32
36
  blog_name
33
37
  end
@@ -4,7 +4,7 @@ require "marcel"
4
4
 
5
5
  class ResourceUploader < CarrierWave::Uploader::Base
6
6
  include CarrierWave::MiniMagick
7
- before :cache, :check_image_content_type!
7
+ before :cache, :check_content_type!
8
8
 
9
9
  def content_type_allowlist
10
10
  [%r{image/}, %r{audio/}, %r{video/}, "text/plain"]
@@ -37,26 +37,24 @@ class ResourceUploader < CarrierWave::Uploader::Base
37
37
  content_type&.include?("image")
38
38
  end
39
39
 
40
- def check_image_content_type!(new_file)
41
- if image?(new_file)
42
- magic_type = mime_magic_content_type(new_file)
43
- if magic_type != new_file.content_type
44
- raise CarrierWave::IntegrityError, "has MIME type mismatch"
45
- end
40
+ def check_content_type!(new_file)
41
+ detected_type = if image? new_file
42
+ file_content_content_type(new_file)
43
+ else
44
+ file_content_type(new_file)
45
+ end
46
+ if detected_type != new_file.content_type
47
+ raise CarrierWave::IntegrityError, "has MIME type mismatch"
46
48
  end
47
49
  end
48
50
 
49
51
  private
50
52
 
51
- # NOTE: This method was adapted from MagicMimeBlacklist#extract_content_type
52
- # from CarrierWave 1.0.0 and SanitizedFile#mime_magic_content_type from CarrierWave 0.11.2
53
- def mime_magic_content_type(new_file)
54
- content_type = nil
55
-
56
- File.open(new_file.path) do |fd|
57
- content_type = Marcel::MimeType.for(fd)
58
- end
53
+ def file_content_content_type(new_file)
54
+ Marcel::MimeType.for Pathname.new(new_file.path)
55
+ end
59
56
 
60
- content_type
57
+ def file_content_type(new_file)
58
+ Marcel::MimeType.for Pathname.new(new_file.path), name: new_file.filename
61
59
  end
62
60
  end
@@ -1,12 +1,13 @@
1
1
  <% content_for :page_heading do %>
2
- <h2 class="page-title">
3
- <%= t('.comments_for_html', title: @article.title) %>
4
- </h2>
2
+ <h2 class="page-title">
3
+ <%= t('.comments_for_html', title: @article.title) %>
4
+ </h2>
5
5
  <% end %>
6
6
 
7
7
  <%= form_tag({ action: 'bulkops' }, { class: 'form-inline' }) do %>
8
8
 
9
- <%= hidden_field 'article_id', @article.id %>
9
+ <%= hidden_field_tag 'article_id', @article.id %>
10
+
10
11
  <%= render 'button', position: 'top' %>
11
12
 
12
13
  <br class='clear' />
@@ -40,6 +40,7 @@
40
40
  </td>
41
41
  </tr>
42
42
  <% end %>
43
+
43
44
  <% @feedback.each do |comment| %>
44
45
  <%= render 'feedback', comment: comment %>
45
46
  <% end %>
@@ -1,10 +1,8 @@
1
1
  <div id='content-<%= article.id %>'>
2
2
  <p>This post is password protected. Please fill in your password or login to view the content</p>
3
- <%= form_for(article, remote: true,
4
- url: { controller: 'articles', action: 'check_password' },
5
- update: "content-#{article.id}") do |f| %>
3
+ <%= form_tag(check_password_url, remote: true, class: "check_password", data: { update: "content-#{article.id}" }) do %>
6
4
  <%= password_field(:article, :password) %>
7
- <input type='hidden' name='article[id]' value='<%= article.id %>' />
5
+ <%= hidden_field(:article, :id) %>
8
6
  <%= submit_tag(t('.submit') + '!', name: 'check_password') %>
9
7
  <% end %>
10
8
  </div>
@@ -1,7 +1,9 @@
1
1
  <% for article in @articles %>
2
2
  <div class="post">
3
3
  <h2><%= link_to_permalink article, article.title %></h2>
4
- <%= article.html(:body).gsub(%r{</?[^>]*>}, '').slice(0..300) %>...
4
+ <% if article.password.blank? %>
5
+ <%= article.html(:body).gsub(%r{</?[^>]*>}, '').slice(0..300) %>...
6
+ <% end %>
5
7
  </div>
6
8
  <% end %>
7
9
 
@@ -1,6 +1,6 @@
1
1
  <% require 'devise/version' %>
2
- <%# TODO: Link user to blog so we can do @resource.blog
3
- blog = Blog.first %>
2
+ <%# TODO: Link user to blog so we can do @resource.blog %>
3
+ <% blog = Blog.first %>
4
4
  <p><%= t('.greeting', recipient: @resource.login, default: "Hello #{@resource.login}!") %></p>
5
5
 
6
6
  <p><%= t('.instruction', default: 'Someone has requested a link to change your password, and you can do this through the link below.') %></p>
@@ -3,7 +3,7 @@
3
3
  <% end %>
4
4
 
5
5
  <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %>
6
- <%= devise_error_messages! %>
6
+ <%= render "devise/shared/error_messages", resource: resource %>
7
7
  <fieldset>
8
8
  <%= f.hidden_field :reset_password_token %>
9
9
 
@@ -3,7 +3,7 @@
3
3
  <% end %>
4
4
 
5
5
  <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %>
6
- <%= devise_error_messages! %>
6
+ <%= render "devise/shared/error_messages", resource: resource %>
7
7
  <fieldset>
8
8
 
9
9
  <div class='form-group'>
data/config/routes.rb CHANGED
@@ -36,10 +36,11 @@ Rails.application.routes.draw do
36
36
  get "/pages/*name", to: "articles#view_page", format: false
37
37
  get "previews(/:id)", to: "articles#preview", format: false
38
38
  get "previews_pages(/:id)", to: "articles#preview_page", format: false
39
- get "check_password", to: "articles#check_password", format: false
40
39
  get "articles/markup_help/:id", to: "articles#markup_help", format: false
41
40
  get "articles/tag", to: "articles#tag", format: false
42
41
 
42
+ post "check_password", to: "articles#check_password", format: false
43
+
43
44
  # SetupController
44
45
  get "/setup", to: "setup#index", format: false
45
46
  post "/setup", to: "setup#create", format: false
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PublifyCore
4
- VERSION = "9.2.6"
4
+ VERSION = "9.2.9"
5
5
  end
@@ -31,7 +31,7 @@ class SpamProtection
31
31
  end
32
32
  end
33
33
 
34
- protected
34
+ private
35
35
 
36
36
  def scan_ip(ip_address)
37
37
  logger.info("[SP] Scanning IP #{ip_address}")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: publify_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.2.6
4
+ version: 9.2.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matijs van Zuijlen
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2022-01-07 00:00:00.000000000 Z
14
+ date: 2022-05-22 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: aasm
@@ -579,6 +579,7 @@ files:
579
579
  - app/assets/javascripts/bootstrap/modal.js
580
580
  - app/assets/javascripts/bootstrap/tab.js
581
581
  - app/assets/javascripts/bootstrap/transition.js
582
+ - app/assets/javascripts/check_password.js
582
583
  - app/assets/javascripts/cookies.js
583
584
  - app/assets/javascripts/datetimepicker.js
584
585
  - app/assets/javascripts/lang/da_DK.js