FIX: Validate email_accent_bg_color color (#13778)

FIX: Validate email_accent_bg_color color (#13778)

Using an invalid value was allowed. This commit tries to automatically fix the color by adding missing # symbol or will show an error to the user if it is not possible and it is not a CSS color either.

diff --git a/app/assets/javascripts/admin/addon/components/color-input.js b/app/assets/javascripts/admin/addon/components/color-input.js
index c563fed..91aeaec 100644
--- a/app/assets/javascripts/admin/addon/components/color-input.js
+++ b/app/assets/javascripts/admin/addon/components/color-input.js
@@ -22,9 +22,21 @@ export default Component.extend({
     return this.onlyHex ? 6 : null;
   }),
 
+  normalize(color) {
+    if (/^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(color)) {
+      if (!color.startsWith("#")) {
+        color = "#" + color;
+      }
+    }
+
+    return color;
+  },
+
   @action
   onHexInput(color) {
-    this.attrs.onChangeColor && this.attrs.onChangeColor(color || "");
+    if (this.attrs.onChangeColor) {
+      this.attrs.onChangeColor(this.normalize(color || ""));
+    }
   },
 
   @observes("hexValue", "brightnessValue", "valid")
@@ -32,7 +44,9 @@ export default Component.extend({
     const hex = this.hexValue;
     let text = this.element.querySelector("input.hex-input");
 
-    this.attrs.onChangeColor && this.attrs.onChangeColor(hex);
+    if (this.attrs.onChangeColor) {
+      this.attrs.onChangeColor(this.normalize(hex));
+    }
 
     if (this.valid) {
       this.styleSelection &&
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 6e787d7..ce7d3b1 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -2324,6 +2324,7 @@ en:
     allow_changing_staged_user_tracking: "Allow a staged user's category and tag notification preferences to be changed by an admin user."
 
     errors:
+      invalid_css_color: "Invalid color. Enter a color name or hex value."
       invalid_email: "Invalid email address."
       invalid_username: "There's no user with that username."
       invalid_group: "There's no group with that name."
diff --git a/config/site_settings.yml b/config/site_settings.yml
index b01c9fc..363aacc 100644
--- a/config/site_settings.yml
+++ b/config/site_settings.yml
@@ -1064,8 +1064,15 @@ email:
   email_accent_bg_color:
     type: color
     default: "#2F70AC"
-  email_accent_fg_color: "#FFFFFF"
-  email_link_color: "#006699"
+    validator: "CssColorValidator"
+  email_accent_fg_color:
+    type: color
+    default: "#FFFFFF"
+    validator: "CssColorValidator"
+  email_link_color:
+    type: color
+    default: "#006699"
+    validator: "CssColorValidator"
   show_topic_featured_link_in_digest: false
   email_custom_headers: "Auto-Submitted: auto-generated"
   email_subject: "[%{site_name}] %{optional_pm}%{optional_cat}%{topic_title}"
diff --git a/lib/validators/css_color_validator.rb b/lib/validators/css_color_validator.rb
new file mode 100644
index 0000000..630e9ca
--- /dev/null
+++ b/lib/validators/css_color_validator.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+class CssColorValidator
+  COLORS = %w{
+    aliceblue antiquewhite aqua aquamarine azure beige bisque black
+    blanchedalmond blue blueviolet brown burlywood cadetblue chartreuse
+    chocolate coral cornflowerblue cornsilk crimson cyan darkblue darkcyan
+    darkgoldenrod darkgray darkgreen darkgrey darkkhaki darkmagenta
+    darkolivegreen darkorange darkorchid darkred darksalmon darkseagreen
+    darkslateblue darkslategray darkslategrey darkturquoise darkviolet
+    deeppink deepskyblue dimgray dimgrey dodgerblue firebrick floralwhite
+    forestgreen fuchsia gainsboro ghostwhite gold goldenrod gray green
+    greenyellow grey honeydew hotpink indianred indigo ivory khaki lavender
+    lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan
+    lightgoldenrodyellow lightgray lightgreen lightgrey lightpink lightsalmon
+    lightseagreen lightskyblue lightslategray lightslategrey lightsteelblue
+    lightyellow lime limegreen linen magenta maroon mediumaquamarine
+    mediumblue mediumorchid mediumpurple mediumseagreen mediumslateblue
+    mediumspringgreen mediumturquoise mediumvioletred midnightblue mintcream
+    mistyrose moccasin navajowhite navy oldlace olive olivedrab orange
+    orangered orchid palegoldenrod palegreen paleturquoise palevioletred
+    papayawhip peachpuff peru pink plum powderblue purple red rosybrown
+    royalblue saddlebrown salmon sandybrown seagreen seashell sienna silver
+    skyblue slateblue slategray slategrey snow springgreen steelblue tan teal
+    thistle tomato turquoise violet wheat white whitesmoke yellow yellowgreen
+  }
+
+  def initialize(opts = {})
+    @opts = opts
+  end
+
+  def valid_value?(val)
+    !!(val =~ /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/ || COLORS.include?(val&.downcase))
+  end
+
+  def error_message
+    I18n.t("site_settings.errors.invalid_css_color")
+  end
+end
diff --git a/spec/components/validators/css_color_validator_spec.rb b/spec/components/validators/css_color_validator_spec.rb
new file mode 100644
index 0000000..db75480
--- /dev/null
+++ b/spec/components/validators/css_color_validator_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe CssColorValidator do
+  subject { described_class.new }
+
+  it "validates hex colors" do
+    expect(subject.valid_value?('#0')).to eq(false)
+    expect(subject.valid_value?('#00')).to eq(false)
+    expect(subject.valid_value?('#000')).to eq(true)
+    expect(subject.valid_value?('#0000')).to eq(false)
+    expect(subject.valid_value?('#00000')).to eq(false)
+    expect(subject.valid_value?('#000000')).to eq(true)
+  end
+
+  it "validates css colors" do
+    expect(subject.valid_value?('red')).to eq(true)
+    expect(subject.valid_value?('green')).to eq(true)
+    expect(subject.valid_value?('blue')).to eq(true)
+    expect(subject.valid_value?('hello')).to eq(false)
+  end
+end

GitHub sha: 18c32a809b36fc171916ae751d91ecd49cf45910

This commit appears in #13778 which was approved by ZogStriP. It was merged by nbianca.