Modernize UI/UX with Bootstrap 5.3 and contemporary design

Complete UI overhaul bringing RailsGoat into 2024 with a professional,
modern interface while maintaining all security vulnerabilities for
educational purposes.

## Design System
- Modern color palette with CSS variables
- Primary: #e63946 (red), Secondary: #457b9d (blue)
- Professional sans-serif typography
- Consistent spacing and shadows
- Bootstrap Icons for modern iconography
- Responsive design with mobile-first approach

## Layout Changes
- Fixed header with clean navigation (60px height)
- Dark sidebar with modern icons and section headers (250px width)
- Proper spacing and padding throughout
- Responsive breakpoints for mobile/tablet/desktop
- Modern card-based content areas

## Header Modernization
- Clean white header with subtle shadow
- RailsGoat branding with shield icon
- Modern dropdown user menu with avatar
- Improved font size controls
- Better button styling and spacing
- Modal-based credentials display (Bootstrap 5)

## Sidebar Improvements
- Dark navy background (#1d3557)
- Bootstrap Icons instead of custom fonts
- Section headers (Admin, Employee)
- Active state highlighting
- Smooth hover transitions
- Version info in footer

## Login Page Redesign
- Beautiful gradient background
- Centered card with shadow
- Modern form inputs with icons
- Clear call-to-action buttons
- Security training notice banner
- Responsive design

## Components Updated
- Modern alerts with icons and proper dismiss buttons
- Footer with OWASP links and copyright
- Scroll-to-top button (vanilla JS, no jQuery)
- Form controls with proper Bootstrap 5 classes

## Technical Improvements
- Bootstrap 5.3 properly implemented (not just CDN reference)
- Bootstrap Icons 1.11.1 for modern iconography
- Removed jQuery dependencies where possible
- Modern JavaScript (vanilla, no jQuery for new features)
- Proper Bootstrap 5 data attributes (data-bs-*)
- Semantic HTML5 structure

## Security Vulnerabilities Preserved
- XSS via html_safe in user welcome (header)
- XSS via cookie font-size (application layout)
- XSS via URL hash parameter (login page)
- Missing SRI on CDN assets (A03:2025)
- All educational vulnerabilities intact

## Files Modified
- app/views/layouts/application.html.erb - Complete redesign with CSS variables
- app/views/layouts/shared/_header.html.erb - Modern navigation
- app/views/layouts/shared/_sidebar.html.erb - Dark sidebar with icons
- app/views/layouts/shared/_footer.html.erb - Modern footer with links
- app/views/layouts/shared/_messages.html.erb - Bootstrap 5 alerts
- app/views/sessions/new.html.erb - Beautiful login page

This modernization makes RailsGoat visually appealing and professional
while maintaining its core educational purpose. The application now
looks like a modern web app security professionals want to use.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ken Johnson
2025-12-07 00:36:21 -05:00
parent 9f157012b0
commit 876955fff1
6 changed files with 599 additions and 325 deletions
+83 -135
View File
@@ -1,142 +1,90 @@
<% if current_user %>
<div id="mainnav" class="hidden-phone hidden-tablet">
<ul style="display: block;">
<li id="home">
<%= link_to home_dashboard_index_path do %>
<div class="icon">
<span class="fs1" aria-hidden="true" data-icon="&#xe0a0;"></span>
</div>
Dashboard
<% end %>
</li>
<% if is_admin? %>
<li class="submenu" id='admin'>
<a href="#">
<div class="icon">
<span class="fs1" aria-hidden="true" data-icon="&#xe1c8;"></span>
</div>
Admin
</a>
<ul>
<li>
<%= link_to admin_dashboard_path(:admin_id => "1") do %>
Manage Users
<% end %>
</li>
<li>
<%= link_to admin_analytics_path(:admin_id => "1") do %>
View Analytics
<% end %>
</li>
</ul>
</li>
<% end %>
<li id="benefit_forms">
<%= link_to user_benefit_forms_path(user_id: current_user.id) do %>
<div class="icon">
<span class="fs1" aria-hidden="true" data-icon="&#xe05c;"></span>
</div>
Benefit Forms
<% end %>
</li>
<li id="retirement">
<%= link_to user_retirement_index_path(user_id: current_user.id) do %>
<div class="icon">
<span class="fs1" aria-hidden="true" data-icon="&#xe096;"></span>
</div>
401k Info
<% end %>
</li>
<li id="pto">
<%= link_to user_paid_time_off_index_path(user_id: current_user.id) do %>
<div class="icon">
<span class="fs1" aria-hidden="true" data-icon="&#xe0d2;"></span>
</div>
PTO
<% end %>
</li>
<li id="employee_info">
<%= link_to user_work_info_index_path(user_id: current_user.id) do %>
<div class="icon">
<span class="fs1" aria-hidden="true" data-icon="&#xe0a9;"></span>
</div>
Work Info
<% end %>
</li>
<li id="performance">
<%= link_to user_performance_index_path(user_id: current_user.id) do %>
<div class="icon">
<span class="fs1" aria-hidden="true" data-icon="&#xe14a;"></span>
</div>
Performance
<% end %>
</li>
<li id="messages">
<%= link_to user_messages_path(user_id: current_user.id) do %>
<div class="icon">
<span class="fs1" aria-hidden="true" data-icon="&#xe040;"></span>
</div>
Messages
<% end %>
</li>
<li id="pay">
<%= link_to user_pay_index_path(user_id: current_user.id) do %>
<div class="icon">
<span class="fs1" aria-hidden="true" data-icon="&#xe038;"></span>
</div>
Pay
<% end %>
</li>
</ul>
</div>
<nav class="rg-sidebar">
<ul class="rg-sidebar-nav">
<li>
<%= link_to home_dashboard_index_path, class: "#{controller_name == 'dashboard' ? 'active' : ''}" do %>
<i class="bi bi-speedometer2"></i>
<span>Dashboard</span>
<% end %>
</li>
<script type="text/javascript">
//Main menu navigation
<% if is_admin? %>
<li class="mt-3">
<div class="px-4 py-2 text-white-50 text-uppercase small fw-bold">Admin</div>
</li>
<li>
<%= link_to admin_dashboard_path(admin_id: "1"), class: "#{controller_name == 'admin' && action_name == 'dashboard' ? 'active' : ''}" do %>
<i class="bi bi-people"></i>
<span>Manage Users</span>
<% end %>
</li>
<li>
<%= link_to admin_analytics_path(admin_id: "1"), class: "#{controller_name == 'admin' && action_name == 'analytics' ? 'active' : ''}" do %>
<i class="bi bi-graph-up"></i>
<span>View Analytics</span>
<% end %>
</li>
<% end %>
$('.submenu > a').click(function(e){
e.preventDefault();
var submenu = $(this).siblings('ul');
var li = $(this).parents('li');
var submenus = $('#mainnav li.submenu ul');
var submenus_parents = $('#mainnav li.submenu');
if(li.hasClass('open'))
{
if(($(window).width() > 768) || ($(window).width() < 479)) {
submenu.slideUp();
} else {
submenu.fadeOut(250);
}
li.removeClass('open');
} else
{
if(($(window).width() > 768) || ($(window).width() < 479)) {
submenus.slideUp();
submenu.slideDown();
} else {
submenus.fadeOut(250);
submenu.fadeIn(250);
}
submenus_parents.removeClass('open');
li.addClass('open');
}
});
<li class="mt-3">
<div class="px-4 py-2 text-white-50 text-uppercase small fw-bold">Employee</div>
</li>
var ul = $('#mainnav > ul');
<li>
<%= link_to user_benefit_forms_path(user_id: current_user.id), class: "#{controller_name == 'benefit_forms' ? 'active' : ''}" do %>
<i class="bi bi-file-earmark-text"></i>
<span>Benefit Forms</span>
<% end %>
</li>
$('#mainnav > a').click(function(e)
{
e.preventDefault();
var mainnav = $('#mainnav');
if(mainnav.hasClass('open'))
{
mainnav.removeClass('open');
ul.slideUp(250);
} else
{
mainnav.addClass('open');
ul.slideDown(250);
}
});
<li>
<%= link_to user_retirement_index_path(user_id: current_user.id), class: "#{controller_name == 'retirement' ? 'active' : ''}" do %>
<i class="bi bi-piggy-bank"></i>
<span>401k Info</span>
<% end %>
</li>
</script>
<li>
<%= link_to user_paid_time_off_index_path(user_id: current_user.id), class: "#{controller_name == 'paid_time_off' ? 'active' : ''}" do %>
<i class="bi bi-calendar-check"></i>
<span>PTO</span>
<% end %>
</li>
<li>
<%= link_to user_work_info_index_path(user_id: current_user.id), class: "#{controller_name == 'work_info' ? 'active' : ''}" do %>
<i class="bi bi-briefcase"></i>
<span>Work Info</span>
<% end %>
</li>
<li>
<%= link_to user_performance_index_path(user_id: current_user.id), class: "#{controller_name == 'performance' ? 'active' : ''}" do %>
<i class="bi bi-bar-chart"></i>
<span>Performance</span>
<% end %>
</li>
<li>
<%= link_to user_messages_path(user_id: current_user.id), class: "#{controller_name == 'messages' ? 'active' : ''}" do %>
<i class="bi bi-envelope"></i>
<span>Messages</span>
<% end %>
</li>
<li>
<%= link_to user_pay_index_path(user_id: current_user.id), class: "#{controller_name == 'pay' ? 'active' : ''}" do %>
<i class="bi bi-credit-card"></i>
<span>Pay</span>
<% end %>
</li>
<li class="mt-4 pt-4 border-top border-secondary">
<div class="px-4 py-2 text-white-50 small">
<i class="bi bi-shield-exclamation"></i>
OWASP RailsGoat <%= Rails::VERSION::STRING %>
</div>
</li>
</ul>
</nav>
<% end %>