diff --git a/app/javascript/maps/places.js b/app/javascript/maps/places.js
index eaf0498c..31b67438 100644
--- a/app/javascript/maps/places.js
+++ b/app/javascript/maps/places.js
@@ -177,8 +177,10 @@ export class PlacesManager {
}
createPlaceIcon(place) {
- const emoji = place.icon || place.tags[0]?.icon || '📍';
- const color = place.color || place.tags[0]?.color || '#4CAF50';
+ const rawEmoji = place.icon || place.tags[0]?.icon || '📍';
+ const emoji = this.escapeHtml(rawEmoji);
+ const rawColor = place.color || place.tags[0]?.color || '#4CAF50';
+ const color = this.sanitizeColor(rawColor);
const iconHtml = `
- ${tag.icon} #${tag.name}
- `
- ).join(' ');
+ const tags = place.tags.map(tag => {
+ const safeIcon = this.escapeHtml(tag.icon || '');
+ const safeName = this.escapeHtml(tag.name || '');
+ const safeColor = this.sanitizeColor(tag.color);
+ return `
+ ${safeIcon} #${safeName}
+ `;
+ }).join(' ');
+
+ const safeName = this.escapeHtml(place.name || '');
+ const safeVisitsCount = place.visits_count ? parseInt(place.visits_count, 10) : 0;
return `
` : '
No tags created yet
'}
@@ -209,6 +213,20 @@ export function createPlacesControl(placesManager, tags, userTheme = 'dark') {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
+ },
+
+ sanitizeColor: function(color) {
+ // Validate hex color format (#RGB or #RRGGBB)
+ if (!color || typeof color !== 'string') {
+ return '#4CAF50'; // Default green
+ }
+
+ const hexColorRegex = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
+ if (hexColorRegex.test(color)) {
+ return color;
+ }
+
+ return '#4CAF50'; // Default green for invalid colors
}
});
}
diff --git a/config/initializers/01_constants.rb b/config/initializers/01_constants.rb
index a360d0d5..53644b1e 100644
--- a/config/initializers/01_constants.rb
+++ b/config/initializers/01_constants.rb
@@ -50,6 +50,8 @@ OMNIAUTH_PROVIDERS =
providers << :github if ENV['GITHUB_OAUTH_CLIENT_ID'].present? && ENV['GITHUB_OAUTH_CLIENT_SECRET'].present?
providers << :google_oauth2 if ENV['GOOGLE_OAUTH_CLIENT_ID'].present? && ENV['GOOGLE_OAUTH_CLIENT_SECRET'].present?
+
+ providers
end
# Custom OIDC provider display name