camaleon_cms 2.7.4 → 2.7.5
Sign up to get free protection for your applications and to get access to all the features.
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.
|