alchemy_cms 8.3.7 → 8.3.8

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.
@@ -1,4 +1,7 @@
1
- import { RemoteSelect } from "alchemy_admin/components/remote_select"
1
+ import {
2
+ RemoteSelect,
3
+ escapeHtml
4
+ } from "alchemy_admin/components/remote_select"
2
5
 
3
6
  export class AttachmentSelect extends RemoteSelect {
4
7
  _renderResult(item) {
@@ -15,7 +18,7 @@ export class AttachmentSelect extends RemoteSelect {
15
18
  _renderListEntry(attachment, term) {
16
19
  return `
17
20
  <div class="attachment-select--attachment">
18
- <alchemy-icon name="${attachment.icon_css_class}"></alchemy-icon>
21
+ <alchemy-icon name="${escapeHtml(attachment.icon_css_class)}"></alchemy-icon>
19
22
  <span class="attachment-select--attachment-name">${this._hightlightTerm(attachment.name, term)}</span>
20
23
  </div>
21
24
  `
@@ -1,4 +1,7 @@
1
- import { RemoteSelect } from "alchemy_admin/components/remote_select"
1
+ import {
2
+ RemoteSelect,
3
+ escapeHtml
4
+ } from "alchemy_admin/components/remote_select"
2
5
 
3
6
  class NodeSelect extends RemoteSelect {
4
7
  _searchQuery(term, page) {
@@ -23,7 +26,7 @@ class NodeSelect extends RemoteSelect {
23
26
  * @private
24
27
  */
25
28
  _renderListEntry(node, term) {
26
- const ancestors = node.ancestors.map((a) => a.name)
29
+ const ancestors = node.ancestors.map((a) => escapeHtml(a.name))
27
30
  const seperator = `<alchemy-icon name="arrow-right-s"></alchemy-icon>`
28
31
 
29
32
  return `
@@ -38,7 +41,7 @@ class NodeSelect extends RemoteSelect {
38
41
  </span>
39
42
  </div>
40
43
  <div class="node-select--node-url">
41
- ${node.url || ""}
44
+ ${escapeHtml(node.url || "")}
42
45
  </div>
43
46
  </div>
44
47
  `
@@ -1,4 +1,7 @@
1
- import { RemoteSelect } from "alchemy_admin/components/remote_select"
1
+ import {
2
+ RemoteSelect,
3
+ escapeHtml
4
+ } from "alchemy_admin/components/remote_select"
2
5
 
3
6
  export class PageSelect extends RemoteSelect {
4
7
  get pageId() {
@@ -30,7 +33,7 @@ export class PageSelect extends RemoteSelect {
30
33
  * @private
31
34
  */
32
35
  _renderResult(page) {
33
- return page.text || page.name
36
+ return escapeHtml(page.text || page.name)
34
37
  }
35
38
 
36
39
  /**
@@ -46,11 +49,11 @@ export class PageSelect extends RemoteSelect {
46
49
  <div class="page-select--top">
47
50
  <alchemy-icon name="file-3"></alchemy-icon>
48
51
  <span class="page-select--page-name">${this._hightlightTerm(page.name, term)}</span>
49
- <span class="page-select--site-name">${page.site.name}</span>
52
+ <span class="page-select--site-name">${escapeHtml(page.site.name)}</span>
50
53
  </div>
51
54
  <div class="page-select--bottom">
52
- <span class="page-select--page-urlname">${page.url_path}</span>
53
- <span class="page-select--language-code">${page.language_code}</span>
55
+ <span class="page-select--page-urlname">${escapeHtml(page.url_path)}</span>
56
+ <span class="page-select--language-code">${escapeHtml(page.language_code)}</span>
54
57
  </div>
55
58
  </div>
56
59
  `
@@ -1,7 +1,41 @@
1
1
  import { setupSelectLocale } from "alchemy_admin/i18n"
2
2
 
3
+ /**
4
+ * Escapes a string for use within HTML. Select2 hands the return value of
5
+ * `formatResult`/`formatSelection` straight to jQuery, so everything woven into
6
+ * those templates has to be escaped here.
7
+ * @param {string} value
8
+ * @returns {string}
9
+ */
10
+ export function escapeHtml(value) {
11
+ return `${value}`
12
+ .replace(/&/g, "&amp;")
13
+ .replace(/</g, "&lt;")
14
+ .replace(/>/g, "&gt;")
15
+ .replace(/"/g, "&quot;")
16
+ }
17
+
18
+ /**
19
+ * Escapes a string for literal use inside a `RegExp`, so a term with
20
+ * metacharacters (e.g. `(`) matches itself instead of being compiled as a
21
+ * pattern, which could match the wrong text or throw a SyntaxError.
22
+ * @param {string} value
23
+ * @returns {string}
24
+ */
25
+ export function escapeRegExp(value) {
26
+ return String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
27
+ }
28
+
3
29
  export function hightlightTerm(name, term) {
4
- return name.replace(new RegExp(term, "gi"), (match) => `<em>${match}</em>`)
30
+ // The result is rendered raw as the entry's name, so the name must be escaped
31
+ // before the term markup is woven in — otherwise a crafted name (e.g. a menu
32
+ // node title) is a stored XSS sink.
33
+ const escapedName = escapeHtml(name)
34
+ if (!term) return escapedName
35
+ return escapedName.replace(
36
+ new RegExp(escapeRegExp(term), "gi"),
37
+ (match) => `<em>${match}</em>`
38
+ )
5
39
  }
6
40
 
7
41
  export class RemoteSelect extends HTMLElement {
@@ -229,6 +229,7 @@
229
229
  .option {
230
230
  padding: var(--spacing-2);
231
231
  cursor: pointer;
232
+ min-height: 2.75em;
232
233
 
233
234
  .highlight {
234
235
  text-decoration: underline;
@@ -128,7 +128,8 @@ form {
128
128
  }
129
129
 
130
130
  .field_with_errors {
131
- input[type="text"],
131
+ &:not(:has(.ts-control)) input[type="text"],
132
+ .ts-control,
132
133
  input[type="email"],
133
134
  input[type="password"],
134
135
  textarea,
@@ -7,11 +7,13 @@
7
7
  <th class="tools"></th>
8
8
  </tr>
9
9
  <% nodes = @page.nodes.select(&:persisted?) %>
10
- <% seperator = '<alchemy-icon name="arrow-right-s" style="vertical-align: text-bottom"></alchemy-icon>' %>
10
+ <% seperator = '<alchemy-icon name="arrow-right-s" style="vertical-align: text-bottom"></alchemy-icon>'.html_safe %>
11
11
  <% if nodes.length > 0 %>
12
12
  <% nodes.each do |node| %>
13
13
  <tr class="even">
14
- <td><%== node.ancestors.map(&:name).join(seperator) %><%== seperator %><strong><%== node.name %></strong></td>
14
+ <td>
15
+ <%= safe_join(node.ancestors.map(&:name), seperator) %><%= seperator %><strong><%= node.name %></strong>
16
+ </td>
15
17
  <td class="tools">
16
18
  <sl-tooltip content="<%= Alchemy.t("delete_node") %>">
17
19
  <%= link_to render_icon(:minus),
@@ -3,7 +3,7 @@
3
3
  module Alchemy
4
4
  extend self
5
5
 
6
- VERSION = "8.3.7"
6
+ VERSION = "8.3.8"
7
7
 
8
8
  def version
9
9
  VERSION
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alchemy_cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.3.7
4
+ version: 8.3.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas von Deyen