camaleon_cms 2.7.4 → 2.7.5
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.
Potentially problematic release.
This version of camaleon_cms might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/app/assets/javascripts/camaleon_cms/admin/_posttype.js +7 -6
- data/app/assets/javascripts/camaleon_cms/admin/nav_menu.js +20 -29
- data/app/controllers/camaleon_cms/admin/media_controller.rb +6 -19
- data/app/controllers/camaleon_cms/admin/settings_controller.rb +2 -1
- data/app/decorators/camaleon_cms/category_decorator.rb +2 -1
- data/app/decorators/camaleon_cms/post_type_decorator.rb +2 -1
- data/app/decorators/camaleon_cms/site_decorator.rb +2 -1
- data/app/mailers/camaleon_cms/html_mailer.rb +5 -2
- data/app/validators/camaleon_cms/post_uniq_validator.rb +4 -3
- data/app/validators/camaleon_cms/user_url_validator.rb +207 -0
- data/config/locales/camaleon_cms/admin/en.yml +11 -1
- data/lib/camaleon_cms/version.rb +1 -1
- metadata +32 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db43005ef92c135dec7d3ef6871aeac761dd01d904e3f5707bee706f2dd65aa3
|
4
|
+
data.tar.gz: e99b9643fba7ab169ede5758bedfd1b8c7c569c7972363782f79ec91770da3da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7e4d609bf25dfbfe2c994f1393dbfe7bc9aa060f07e10bd6446f3273fbecc1646868a1efcae9b14dd32dd206c64a986e0210ea1199c3f1e2cda680953824ada2
|
7
|
+
data.tar.gz: fb39191112e373c198578073e5b317bd94749b4ef2956afd2e3baa07a98e91d3a30af9c1f5c9e98822f9338a8ab5f86aea6be405335a71794c55317bc68e285e
|
@@ -9,18 +9,18 @@ window.cama_init_posttype_form = function() {
|
|
9
9
|
|
10
10
|
item.parent().siblings().find('input').prop('disabled', $(this).is(':checked'))
|
11
11
|
if ($(this).is(':checked'))
|
12
|
-
|
12
|
+
item.prop('checked', true).prop('disabled', false)
|
13
13
|
else
|
14
|
-
|
14
|
+
item.prop('disabled', true)
|
15
15
|
}).trigger('change')
|
16
16
|
|
17
17
|
form.find('[name="meta[has_picture]"]').change(function() {
|
18
18
|
const items = form.find('.picture_settings input')
|
19
19
|
|
20
20
|
if ($(this).is(':checked'))
|
21
|
-
|
21
|
+
items.prop('disabled', false)
|
22
22
|
else
|
23
|
-
|
23
|
+
items.prop('disabled', true)
|
24
24
|
}).trigger('change')
|
25
25
|
|
26
26
|
// toggle single and multiple categories checkbox
|
@@ -28,9 +28,10 @@ window.cama_init_posttype_form = function() {
|
|
28
28
|
'input:checkbox[name="meta[has_category]"], input:checkbox[name="meta[has_single_category]"]'
|
29
29
|
)
|
30
30
|
|
31
|
-
|
31
|
+
catChecks.change(
|
32
32
|
function() {
|
33
|
-
if ($(this).is(':checked'))
|
33
|
+
if ($(this).is(':checked'))
|
34
|
+
catChecks.not(this).prop('checked', false)
|
34
35
|
}
|
35
36
|
).filter(':checked').trigger('change')
|
36
37
|
}
|
@@ -1,9 +1,3 @@
|
|
1
|
-
/*
|
2
|
-
* decaffeinate suggestions:
|
3
|
-
* DS102: Remove unnecessary code created because of implicit returns
|
4
|
-
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
|
5
|
-
*/
|
6
|
-
|
7
1
|
/* eslint-env jquery */
|
8
2
|
$(function() {
|
9
3
|
const panel = $('#menu_content')
|
@@ -21,11 +15,11 @@ $(function() {
|
|
21
15
|
return
|
22
16
|
|
23
17
|
panel.find('#menu_reoreder_loading').show()
|
24
|
-
|
18
|
+
$.post(listPanel.attr('data-reorder_url'), data, function(res) {
|
25
19
|
lastData = data
|
26
20
|
panel.find('#menu_reoreder_loading').hide()
|
27
21
|
if (res)
|
28
|
-
|
22
|
+
alert(res)
|
29
23
|
})
|
30
24
|
})
|
31
25
|
|
@@ -33,13 +27,10 @@ $(function() {
|
|
33
27
|
const saveMenu = function(data) {
|
34
28
|
showLoading()
|
35
29
|
|
36
|
-
|
37
|
-
listPanel.
|
38
|
-
|
39
|
-
|
40
|
-
listPanel.children('.dd-list').append($(res).children())
|
41
|
-
return hideLoading()
|
42
|
-
})
|
30
|
+
$.post(listPanel.attr('data-url'), data, function(res) {
|
31
|
+
listPanel.children('.dd-list').append($(res).children())
|
32
|
+
hideLoading()
|
33
|
+
})
|
43
34
|
}
|
44
35
|
|
45
36
|
// add menu items (non-external)
|
@@ -48,7 +39,7 @@ $(function() {
|
|
48
39
|
let flag = false
|
49
40
|
$(this).closest('.panel').find('input:checkbox:checked').each(function() {
|
50
41
|
flag = true
|
51
|
-
|
42
|
+
data.items.push({ id: $(this).val(), kind: $(this).closest('.class_type').attr('data-type') })
|
52
43
|
}).prop('checked', false)
|
53
44
|
|
54
45
|
if (!flag)
|
@@ -64,7 +55,7 @@ $(function() {
|
|
64
55
|
let flag = false
|
65
56
|
$(this).closest('.panel').find('input:checkbox:checked').each(function() {
|
66
57
|
flag = true
|
67
|
-
|
58
|
+
data.custom_items.push({ url: $(this).val(), kind: $(this).attr('data-kind'), label: $(this).attr('data-label') })
|
68
59
|
}).prop('checked', false)
|
69
60
|
|
70
61
|
if (!flag)
|
@@ -93,10 +84,10 @@ $(function() {
|
|
93
84
|
title: link.attr('data-original-title') || link.attr('title'),
|
94
85
|
url: link.attr('href'),
|
95
86
|
mode: 'ajax',
|
96
|
-
callback(modal) {
|
87
|
+
callback: (modal) => {
|
97
88
|
const form = modal.find('form')
|
98
89
|
init_form_validations(form)
|
99
|
-
|
90
|
+
form.submit(function() {
|
100
91
|
if (!form.valid())
|
101
92
|
return false
|
102
93
|
|
@@ -104,7 +95,7 @@ $(function() {
|
|
104
95
|
$.post(form.attr('action'), form.serialize(), function(res) {
|
105
96
|
link.closest('li').replaceWith($(res).html())
|
106
97
|
modal.modal('hide')
|
107
|
-
|
98
|
+
hideLoading()
|
108
99
|
})
|
109
100
|
return false
|
110
101
|
})
|
@@ -122,39 +113,39 @@ $(function() {
|
|
122
113
|
showLoading()
|
123
114
|
$.get(link.attr('href'), function() {
|
124
115
|
link.closest('.dd-item').remove()
|
125
|
-
|
116
|
+
hideLoading()
|
126
117
|
})
|
127
118
|
return false
|
128
119
|
})
|
129
120
|
|
130
121
|
// new menu
|
131
122
|
panel.find('.new_menu_link, .edit_menu_link').ajax_modal({
|
132
|
-
callback(modal) {
|
123
|
+
callback: (modal) => {
|
133
124
|
const form = modal.find('form')
|
134
125
|
|
135
|
-
|
126
|
+
setTimeout(() => init_form_validations(form), 1000)
|
136
127
|
}
|
137
128
|
})
|
138
129
|
|
139
130
|
// menus list - change dropdown
|
140
|
-
panel.find('#menu_items #
|
131
|
+
panel.find('#menu_items #switch_nav_menu_form select').change(function() {
|
141
132
|
if (!$(this).val())
|
142
133
|
return
|
143
134
|
|
144
|
-
|
135
|
+
$(this).closest('form').submit()
|
145
136
|
})
|
146
137
|
|
147
138
|
// custom fields
|
148
|
-
|
139
|
+
listPanel.on('click', '.custom_settings_link', function() {
|
149
140
|
const link = $(this)
|
150
141
|
open_modal({
|
151
142
|
title: link.attr('data-original-title') || link.attr('title'),
|
152
143
|
url: link.attr('href'),
|
153
144
|
mode: 'ajax',
|
154
|
-
callback(modal) {
|
145
|
+
callback: (modal) => {
|
155
146
|
const form = modal.find('form')
|
156
147
|
init_form_validations(form)
|
157
|
-
|
148
|
+
form.submit(function() {
|
158
149
|
if (!form.valid())
|
159
150
|
return false
|
160
151
|
|
@@ -164,7 +155,7 @@ $(function() {
|
|
164
155
|
alert(res)
|
165
156
|
|
166
157
|
modal.modal('hide')
|
167
|
-
|
158
|
+
hideLoading()
|
168
159
|
})
|
169
160
|
return false
|
170
161
|
})
|
@@ -6,15 +6,6 @@ module CamaleonCms
|
|
6
6
|
skip_before_action :verify_authenticity_token, only: :upload, raise: false
|
7
7
|
before_action :init_media_vars, except: :download_private_file
|
8
8
|
|
9
|
-
LOCALHOST_DOMAIN_MATCHER = /
|
10
|
-
localhost|
|
11
|
-
127\.0\.0\.1|
|
12
|
-
0\.0\.0\.0|
|
13
|
-
0x7f\.0x0\.0x0\.0x1| # hex encoding
|
14
|
-
0177\.0\.0\.01| # octal encoding
|
15
|
-
2130706433 # dword encoding
|
16
|
-
/x.freeze
|
17
|
-
|
18
9
|
# render media section
|
19
10
|
def index
|
20
11
|
authorize! :manage, :media
|
@@ -71,13 +62,13 @@ module CamaleonCms
|
|
71
62
|
cama_uploader.delete_file(params[:folder].gsub('//', '/'))
|
72
63
|
render plain: ''
|
73
64
|
when 'crop_url'
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
r = if
|
78
|
-
{ error:
|
65
|
+
user_url = params[:url].to_s
|
66
|
+
user_url = "#{current_site.the_url(locale: nil)}#{user_url}" unless user_url.start_with?('data:', 'http')
|
67
|
+
url_validation_result = UserUrlValidator.validate(user_url)
|
68
|
+
r = if url_validation_result.is_a?(Array)
|
69
|
+
{ error: url_validation_result.join(', ') }
|
79
70
|
else
|
80
|
-
cama_tmp_upload(
|
71
|
+
cama_tmp_upload(user_url, formats: params[:formats], name: params[:name])
|
81
72
|
end
|
82
73
|
if r[:error].present?
|
83
74
|
render plain: helpers.sanitize(r[:error])
|
@@ -91,10 +82,6 @@ module CamaleonCms
|
|
91
82
|
end
|
92
83
|
end
|
93
84
|
|
94
|
-
def local_url?(url)
|
95
|
-
url.try :match?, LOCALHOST_DOMAIN_MATCHER
|
96
|
-
end
|
97
|
-
|
98
85
|
# upload files from media uploader
|
99
86
|
def upload(settings = {})
|
100
87
|
params[:dimension] = nil if params[:skip_auto_crop].present?
|
@@ -70,7 +70,8 @@ module CamaleonCms
|
|
70
70
|
|
71
71
|
# send email test
|
72
72
|
def test_email
|
73
|
-
|
73
|
+
data = { content: 'Test content', current_site: current_site, url_base: cama_root_url }
|
74
|
+
CamaleonCms::HtmlMailer.sender(params[:email], 'Test', data).deliver_now
|
74
75
|
head :ok
|
75
76
|
rescue StandardError => e
|
76
77
|
render inline: e.message, status: 502
|
@@ -29,7 +29,8 @@ module CamaleonCms
|
|
29
29
|
# return a child category from this category with id (integer) or by slug (string)
|
30
30
|
def the_category(slug_or_id)
|
31
31
|
return object.categories.where(id: slug_or_id).first if slug_or_id.is_a?(Integer)
|
32
|
-
|
32
|
+
|
33
|
+
object.categories.find_by_slug(slug_or_id) if slug_or_id.is_a?(String)
|
33
34
|
end
|
34
35
|
|
35
36
|
# ---------------------
|
@@ -70,7 +70,8 @@ module CamaleonCms
|
|
70
70
|
# return a category from this post_type with id (integer) or by slug (string)
|
71
71
|
def the_category(slug_or_id)
|
72
72
|
return the_categories.where(id: slug_or_id).first if slug_or_id.is_a?(Integer)
|
73
|
-
|
73
|
+
|
74
|
+
the_categories.find_by_slug(slug_or_id) if slug_or_id.is_a?(String)
|
74
75
|
end
|
75
76
|
|
76
77
|
# return all post_tags for the post_type (active_record) filtered by permissions + hidden posts + roles + etc...
|
@@ -80,7 +80,8 @@ module CamaleonCms
|
|
80
80
|
# slug_or_id: string => return all main categories of the post_type with slug = slug_or_id
|
81
81
|
def the_categories(slug_or_id = nil)
|
82
82
|
return the_post_type(slug_or_id).the_categories if slug_or_id.present?
|
83
|
-
|
83
|
+
|
84
|
+
object.categories unless slug_or_id.present?
|
84
85
|
end
|
85
86
|
|
86
87
|
# return the category object with id or slug = slug_or_id from this site
|
@@ -58,8 +58,11 @@ module CamaleonCms
|
|
58
58
|
prepend_view_path(Rails.root.join(views_dir).to_s)
|
59
59
|
|
60
60
|
theme = @current_site.get_theme
|
61
|
-
|
62
|
-
|
61
|
+
if theme.settings && theme.settings['gem_mode']
|
62
|
+
lookup_context.prefixes.prepend("themes/#{theme.slug}")
|
63
|
+
else
|
64
|
+
lookup_context.prefixes.prepend("themes/#{theme.slug}/views")
|
65
|
+
end
|
63
66
|
lookup_context.use_camaleon_partial_prefixes = true
|
64
67
|
((data[:files] || []) + (data[:attachments] || [])).each do |attach|
|
65
68
|
if File.exist?(attach) && !File.directory?(attach)
|
@@ -8,9 +8,10 @@ module CamaleonCms
|
|
8
8
|
return unless ptype.present? # only for posts that belongs to a post type model
|
9
9
|
|
10
10
|
posts = ptype.site.posts
|
11
|
-
.where(
|
12
|
-
|
13
|
-
|
11
|
+
.where(
|
12
|
+
"(#{slug_array.map { |s| "#{CamaleonCms::Post.table_name}.slug LIKE '%-->#{s}<!--%'" }
|
13
|
+
.join(' OR ')} ) OR #{CamaleonCms::Post.table_name}.slug = ?", record.slug
|
14
|
+
)
|
14
15
|
.where.not(id: record.id)
|
15
16
|
.where.not(status: %i[draft draft_child trash])
|
16
17
|
if posts.size.positive?
|
@@ -0,0 +1,207 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2011-present GitLab B.V.
|
4
|
+
#
|
5
|
+
# See https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/url_blocker.rb
|
6
|
+
#
|
7
|
+
# Portions of this software are licensed under the "MIT Expat" license as defined below.
|
8
|
+
#
|
9
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
10
|
+
# of this software and associated documentation files (the "Software"), to deal
|
11
|
+
# in the Software without restriction, including without limitation the rights
|
12
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
13
|
+
# copies of the Software, and to permit persons to whom the Software is
|
14
|
+
# furnished to do so, subject to the following conditions:
|
15
|
+
#
|
16
|
+
# The above copyright notice and this permission notice shall be included in all
|
17
|
+
# copies or substantial portions of the Software.
|
18
|
+
#
|
19
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
20
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
21
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
22
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
23
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
24
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
25
|
+
# SOFTWARE.
|
26
|
+
|
27
|
+
# require 'resolv'
|
28
|
+
require 'ipaddress'
|
29
|
+
require 'addressable/uri'
|
30
|
+
|
31
|
+
module CamaleonCms
|
32
|
+
class UserUrlValidator
|
33
|
+
LOCAL_IPS = %w[0.0.0.0 ::].freeze
|
34
|
+
|
35
|
+
def self.validate(...)
|
36
|
+
new.validate(...)
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize
|
40
|
+
@errors = []
|
41
|
+
end
|
42
|
+
|
43
|
+
# Validates the given url according to the constraints specified by the received arguments.
|
44
|
+
#
|
45
|
+
# allow_localhost - Registers error if URL resolves to a localhost IP address and argument is false.
|
46
|
+
# allow_local_network - Registers error if URL resolves to a link-local address and argument is false.
|
47
|
+
# enforce_user - Registers error if URL user doesn't start with alphanumeric characters and argument is true.
|
48
|
+
# enforce_sanitizing - Registers error if URL includes any HTML/CSS/JS tags and argument is true.
|
49
|
+
#
|
50
|
+
# Returns an array with [<uri>, <original-hostname>].
|
51
|
+
def validate(url, allow_localhost: false, allow_local_network: false, enforce_user: true, enforce_sanitizing: true)
|
52
|
+
return invalid_url unless url.present?
|
53
|
+
|
54
|
+
# Param url can be a string, URI or Addressable::URI
|
55
|
+
return invalid_url unless (uri = parse_url(url))
|
56
|
+
|
57
|
+
validate_uri(uri: uri, enforce_sanitizing: enforce_sanitizing, enforce_user: enforce_user)
|
58
|
+
return @errors if @errors.any?
|
59
|
+
|
60
|
+
address_info = get_address_info(uri)
|
61
|
+
return @errors if @errors.any?
|
62
|
+
|
63
|
+
validate_local_request(
|
64
|
+
address_info: address_info,
|
65
|
+
allow_localhost: allow_localhost,
|
66
|
+
allow_local_network: allow_local_network
|
67
|
+
)
|
68
|
+
|
69
|
+
@errors.empty? || @errors
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def validate_uri(uri:, enforce_sanitizing:, enforce_user:)
|
75
|
+
validate_html_tags(uri) if enforce_sanitizing
|
76
|
+
|
77
|
+
validate_user(uri.user) if enforce_user
|
78
|
+
validate_hostname(uri.hostname)
|
79
|
+
end
|
80
|
+
|
81
|
+
# @param uri [Addressable::URI]
|
82
|
+
# @return [Array<Addrinfo>] addrinfo object for the URI
|
83
|
+
def get_address_info(uri)
|
84
|
+
Addrinfo.getaddrinfo(uri.hostname, get_port(uri), nil, :STREAM).map do |addr|
|
85
|
+
addr.ipv6_v4mapped? ? addr.ipv6_to_ipv4 : addr
|
86
|
+
end
|
87
|
+
rescue ArgumentError => e
|
88
|
+
# Addrinfo.getaddrinfo errors if the domain exceeds 1024 characters.
|
89
|
+
@errors << I18n.t('camaleon_cms.admin.validate.hostname_long') if e.message.include?('hostname too long')
|
90
|
+
|
91
|
+
@errors << "#{e.message}: #{I18n.t('camaleon_cms.admin.validate.url')}" if @errors.blank?
|
92
|
+
rescue SocketError
|
93
|
+
@errors << I18n.t('camaleon_cms.admin.validate.host_invalid')
|
94
|
+
end
|
95
|
+
|
96
|
+
def validate_local_request(address_info:, allow_localhost:, allow_local_network:)
|
97
|
+
return if allow_local_network && allow_localhost
|
98
|
+
|
99
|
+
unless allow_localhost
|
100
|
+
validate_localhost(address_info)
|
101
|
+
validate_loopback(address_info)
|
102
|
+
end
|
103
|
+
|
104
|
+
return if allow_local_network
|
105
|
+
|
106
|
+
validate_local_network(address_info)
|
107
|
+
validate_link_local(address_info)
|
108
|
+
validate_shared_address(address_info)
|
109
|
+
validate_limited_broadcast_address(address_info)
|
110
|
+
end
|
111
|
+
|
112
|
+
def get_port(uri)
|
113
|
+
uri.port || uri.default_port
|
114
|
+
end
|
115
|
+
|
116
|
+
def validate_html_tags(uri)
|
117
|
+
uri_str = uri.to_s
|
118
|
+
sanitized_uri = ActionController::Base.helpers.sanitize(uri_str, tags: [])
|
119
|
+
@errors << I18n.t('camaleon_cms.admin.validate.html_tags') unless sanitized_uri == uri_str
|
120
|
+
end
|
121
|
+
|
122
|
+
# @param [String, Addressable::URI, #to_str] url The URL string to parse
|
123
|
+
# @return [Addressable::URI, nil] URI object based on the parsed string, or `nil` if the `url` is invalid
|
124
|
+
def parse_url(url)
|
125
|
+
invalid = nil
|
126
|
+
uri = Addressable::URI.parse(url).tap do |parsed_url|
|
127
|
+
invalid = true if multiline_blocked?(parsed_url)
|
128
|
+
end
|
129
|
+
return if invalid
|
130
|
+
|
131
|
+
uri
|
132
|
+
rescue Addressable::URI::InvalidURIError, URI::InvalidURIError
|
133
|
+
nil
|
134
|
+
end
|
135
|
+
|
136
|
+
def multiline_blocked?(parsed_url)
|
137
|
+
url = parsed_url.to_s
|
138
|
+
|
139
|
+
return true if url =~ /[\n\r]/
|
140
|
+
# Google Cloud Storage uses a multi-line, encoded Signature query string
|
141
|
+
return false if %w[http https].include?(parsed_url.scheme&.downcase)
|
142
|
+
|
143
|
+
CGI.unescape(url) =~ /[\n\r]/
|
144
|
+
end
|
145
|
+
|
146
|
+
def validate_user(value)
|
147
|
+
return if value.blank?
|
148
|
+
return if value =~ /\A\p{Alnum}/
|
149
|
+
|
150
|
+
@errors << I18n.t('camaleon_cms.admin.validate.username_alphanumeric')
|
151
|
+
end
|
152
|
+
|
153
|
+
def validate_hostname(value)
|
154
|
+
return if value.blank?
|
155
|
+
return if IPAddress.valid?(value)
|
156
|
+
return if value =~ /\A\p{Alnum}/
|
157
|
+
|
158
|
+
@errors << I18n.t('camaleon_cms.admin.validate.host_or_ip_invalid')
|
159
|
+
end
|
160
|
+
|
161
|
+
def validate_localhost(addrs_info)
|
162
|
+
return if (Socket.ip_address_list.map(&:ip_address).concat(LOCAL_IPS) & addrs_info.map(&:ip_address)).empty?
|
163
|
+
|
164
|
+
@errors << I18n.t('camaleon_cms.admin.validate.no_localhost_requests')
|
165
|
+
end
|
166
|
+
|
167
|
+
def validate_loopback(addrs_info)
|
168
|
+
return unless addrs_info.any? { |addr| addr.ipv4_loopback? || addr.ipv6_loopback? }
|
169
|
+
|
170
|
+
@errors << I18n.t('camaleon_cms.admin.validate.no_loopback_requests')
|
171
|
+
end
|
172
|
+
|
173
|
+
def validate_local_network(addrs_info)
|
174
|
+
return unless addrs_info.any? { |addr| addr.ipv4_private? || addr.ipv6_sitelocal? || addr.ipv6_unique_local? }
|
175
|
+
|
176
|
+
@errors << I18n.t('camaleon_cms.admin.validate.no_local_net_requests')
|
177
|
+
end
|
178
|
+
|
179
|
+
def validate_link_local(addrs_info)
|
180
|
+
netmask = IPAddr.new('169.254.0.0/16')
|
181
|
+
return unless addrs_info.any? { |addr| addr.ipv6_linklocal? || netmask.include?(addr.ip_address) }
|
182
|
+
|
183
|
+
@errors << I18n.t('camaleon_cms.admin.validate.no_link_local_net_requests')
|
184
|
+
end
|
185
|
+
|
186
|
+
def validate_shared_address(addrs_info)
|
187
|
+
netmask = IPAddr.new('100.64.0.0/10')
|
188
|
+
return unless addrs_info.any? { |addr| netmask.include?(addr.ip_address) }
|
189
|
+
|
190
|
+
@errors << I18n.t('camaleon_cms.admin.validate.no_shared_address_requests')
|
191
|
+
end
|
192
|
+
|
193
|
+
# Registers an error if any IP in `addrs_info` is the limited broadcast address.
|
194
|
+
# https://datatracker.ietf.org/doc/html/rfc919#section-7
|
195
|
+
def validate_limited_broadcast_address(addrs_info)
|
196
|
+
blocked_ips = ['255.255.255.255']
|
197
|
+
|
198
|
+
return if (blocked_ips & addrs_info.map(&:ip_address)).empty?
|
199
|
+
|
200
|
+
@errors << I18n.t('camaleon_cms.admin.validate.no_limited_broadcast_address_requests')
|
201
|
+
end
|
202
|
+
|
203
|
+
def invalid_url
|
204
|
+
@errors << I18n.t('camaleon_cms.admin.validate.url')
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
@@ -212,7 +212,6 @@ en:
|
|
212
212
|
reload: 'Reload'
|
213
213
|
clear_cache: 'Clear Cache'
|
214
214
|
name_required: 'File name is required'
|
215
|
-
local_upload_denied: 'Cannot upload from localhost'
|
216
215
|
menus:
|
217
216
|
menus: Menus
|
218
217
|
link_url: 'Link URL'
|
@@ -684,6 +683,16 @@ en:
|
|
684
683
|
required: 'This field is required.'
|
685
684
|
remote: 'Please fix this field.'
|
686
685
|
email: 'Please enter a valid email address.'
|
686
|
+
host_invalid: 'Host cannot be resolved or invalid'
|
687
|
+
host_or_ip_invalid: 'Hostname or IP address invalid'
|
688
|
+
hostname_long: 'Host is too long (maximum is 1024 characters)'
|
689
|
+
html_tags: 'HTML/CSS/JS tags are not allowed'
|
690
|
+
no_localhost_requests: 'Requests to localhost are not allowed'
|
691
|
+
no_loopback_requests: 'Requests to loopback addresses are not allowed'
|
692
|
+
no_local_net_requests: 'Requests to the local network are not allowed'
|
693
|
+
no_link_local_net_requests: 'Requests to the link local network are not allowed'
|
694
|
+
no_shared_address_requests: 'Requests to the shared address space are not allowed'
|
695
|
+
no_limited_broadcast_address_requests: 'Requests to the limited broadcast address are not allowed'
|
687
696
|
url: 'Please enter a valid URL.'
|
688
697
|
date: 'Please enter a valid date.'
|
689
698
|
dateiso: 'Please enter a valid date ( ISO ).'
|
@@ -697,6 +706,7 @@ en:
|
|
697
706
|
range: 'Please enter a value between {0} and {1}.'
|
698
707
|
max: 'Please enter a value less than or equal to {0}.'
|
699
708
|
min: 'Please enter a value greater than or equal to {0}.'
|
709
|
+
username_alphanumeric: 'Username needs to start with an alphanumeric character'
|
700
710
|
widgets:
|
701
711
|
create_widget: 'Create Widget'
|
702
712
|
create_sidebar: 'Create Sidebar'
|
data/lib/camaleon_cms/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: camaleon_cms
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.7.
|
4
|
+
version: 2.7.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Owen Peredo Diaz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-12-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: addressable
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bcrypt
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,6 +100,20 @@ dependencies:
|
|
86
100
|
- - ">="
|
87
101
|
- !ruby/object:Gem::Version
|
88
102
|
version: '0'
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: ipaddress
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :runtime
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
89
117
|
- !ruby/object:Gem::Dependency
|
90
118
|
name: jquery-rails
|
91
119
|
requirement: !ruby/object:Gem::Requirement
|
@@ -766,6 +794,7 @@ files:
|
|
766
794
|
- app/uploaders/camaleon_cms_uploader.rb
|
767
795
|
- app/validators/camaleon_cms/post_uniq_validator.rb
|
768
796
|
- app/validators/camaleon_cms/uniq_validator.rb
|
797
|
+
- app/validators/camaleon_cms/user_url_validator.rb
|
769
798
|
- app/views/camaleon_cms/404.html.erb
|
770
799
|
- app/views/camaleon_cms/500.html.erb
|
771
800
|
- app/views/camaleon_cms/_flash_messages.html.erb
|
@@ -1103,7 +1132,7 @@ requirements:
|
|
1103
1132
|
- rails >= 6.0
|
1104
1133
|
- ruby >= 2.7
|
1105
1134
|
- imagemagick
|
1106
|
-
rubygems_version: 3.
|
1135
|
+
rubygems_version: 3.5.1
|
1107
1136
|
signing_key:
|
1108
1137
|
specification_version: 4
|
1109
1138
|
summary: Camaleon is a CMS for Ruby on Rails as an alternative to Wordpress.
|