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
+184 -25
View File
@@ -1,9 +1,12 @@
<!DOCTYPE html>
<html>
<html lang="en" data-bs-theme="light">
<head>
<title>RailsGoat</title>
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>RailsGoat - OWASP Security Training</title>
<%= stylesheet_link_tag "application", media: "all", "data-turbo-track": "reload" %>
<%= javascript_include_tag "application", "data-turbo-track": "reload", type: "module" %>
<%#= csrf_meta_tags %> <!-- <~ What is this for? I hear it helps w/ JS and Sea-surfing.....whatevz -->
<!-- VULNERABILITY A03:2025 - Software Supply Chain Failures
@@ -14,41 +17,197 @@
See: /tutorials/supply_chain for exploitation details
-->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<!-- bootstrap css -->
<!-- Modern Design System -->
<style>
:root {
--rg-primary: #e63946;
--rg-primary-dark: #d62828;
--rg-secondary: #457b9d;
--rg-secondary-dark: #1d3557;
--rg-success: #06d6a0;
--rg-warning: #ffb703;
--rg-danger: #e63946;
--rg-light: #f8f9fa;
--rg-dark: #1d3557;
--rg-sidebar-width: 250px;
--rg-header-height: 60px;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: var(--rg-light);
min-height: 100vh;
}
/* Modern Header */
.rg-header {
background: white;
border-bottom: 1px solid #dee2e6;
height: var(--rg-header-height);
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1030;
box-shadow: 0 2px 4px rgba(0,0,0,0.08);
}
.rg-brand {
font-size: 1.5rem;
font-weight: 700;
color: var(--rg-primary);
text-decoration: none;
}
.rg-brand:hover {
color: var(--rg-primary-dark);
}
/* Modern Sidebar */
.rg-sidebar {
position: fixed;
top: var(--rg-header-height);
left: 0;
bottom: 0;
width: var(--rg-sidebar-width);
background: var(--rg-dark);
color: white;
overflow-y: auto;
transition: transform 0.3s ease;
}
.rg-sidebar-nav {
list-style: none;
padding: 1rem 0;
margin: 0;
}
.rg-sidebar-nav li a {
display: flex;
align-items: center;
padding: 0.75rem 1.5rem;
color: rgba(255,255,255,0.8);
text-decoration: none;
transition: all 0.2s;
}
.rg-sidebar-nav li a:hover,
.rg-sidebar-nav li a.active {
background: rgba(255,255,255,0.1);
color: white;
}
.rg-sidebar-nav li a i {
font-size: 1.25rem;
margin-right: 0.75rem;
width: 24px;
text-align: center;
}
/* Main Content */
.rg-main {
margin-top: var(--rg-header-height);
margin-left: var(--rg-sidebar-width);
padding: 2rem;
min-height: calc(100vh - var(--rg-header-height));
}
.rg-main.no-sidebar {
margin-left: 0;
}
/* Cards */
.rg-card {
background: white;
border-radius: 0.5rem;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
margin-bottom: 1.5rem;
}
/* Buttons */
.btn-primary {
background: var(--rg-primary);
border-color: var(--rg-primary);
}
.btn-primary:hover {
background: var(--rg-primary-dark);
border-color: var(--rg-primary-dark);
}
/* Alerts */
.alert {
border-radius: 0.5rem;
border: none;
}
/* Login Page */
.rg-login-wrapper {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, var(--rg-secondary-dark) 0%, var(--rg-secondary) 100%);
}
.rg-login-card {
background: white;
border-radius: 1rem;
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
padding: 3rem;
width: 100%;
max-width: 450px;
}
.rg-login-header {
text-align: center;
margin-bottom: 2rem;
}
.rg-login-logo {
font-size: 3rem;
color: var(--rg-primary);
margin-bottom: 1rem;
}
/* Responsive */
@media (max-width: 768px) {
.rg-sidebar {
transform: translateX(-100%);
}
.rg-sidebar.show {
transform: translateX(0);
}
.rg-main {
margin-left: 0;
}
}
/* VULNERABILITY: XSS via cookie font-size -->
<%
if cookies[:font]
%>
<style>body { font-size:<%= raw cookies[:font] %> !important;}</style>
body { font-size:<%= raw cookies[:font] %> !important;}
<%
end
%>
</style>
</head>
<body>
<%= render "layouts/shared/header" %>
<%= render "layouts/shared/sidebar" %>
<div class="container-fluid">
<% if current_user %>
<div class="dashboard-wrapper">
<main class="rg-main <%= 'no-sidebar' unless current_user %>">
<%= render "layouts/shared/messages" %>
<%= yield %>
</div>
<% else %>
<div class="login-wrapper">
<%= render "layouts/shared/messages" %>
<%= yield %>
</div>
<% end %>
</div>
</main>
<%= render "layouts/shared/footer" %>
<script type="text/javascript">
//Dropdown
$('.dropdown-toggle').dropdown();
</script>
</body>
</html>
+50 -16
View File
@@ -1,22 +1,56 @@
<footer>
<p align="center">
&copy; The Open Worldwide Application Security Project - OWASP, 2015
<% if current_user %>
<footer class="border-top mt-5 py-4 text-center text-muted bg-white">
<div class="container">
<div class="row">
<div class="col-md-12">
<p class="mb-1">
<i class="bi bi-shield-check"></i>
&copy; <%= Date.current.year %> The Open Worldwide Application Security Project - OWASP
</p>
</footer>
<p class="small mb-0">
<a href="https://owasp.org" target="_blank" class="text-decoration-none me-3">
<i class="bi bi-globe"></i> OWASP.org
</a>
<a href="https://github.com/OWASP/railsgoat" target="_blank" class="text-decoration-none me-3">
<i class="bi bi-github"></i> GitHub
</a>
<a href="https://github.com/OWASP/railsgoat/wiki" target="_blank" class="text-decoration-none">
<i class="bi bi-book"></i> Documentation
</a>
</p>
</div>
</div>
</div>
</footer>
<% end %>
<script type="text/javascript">
<!-- Scroll to Top Button -->
<button id="scrollTopBtn" class="btn btn-primary rounded-circle position-fixed bottom-0 end-0 m-4" style="width: 48px; height: 48px; display: none; z-index: 1000;" title="Scroll to top">
<i class="bi bi-arrow-up"></i>
</button>
//ScrollUp
$(function () {
$.scrollUp({
scrollName: 'scrollUp', // Element ID
topDistance: '300', // Distance from top before showing element (px)
topSpeed: 300, // Speed back to top (ms)
animation: 'fade', // Fade, slide, none
animationInSpeed: 400, // Animation in speed (ms)
animationOutSpeed: 400, // Animation out speed (ms)
scrollText: 'Scroll to top', // Text for element
activeOverlay: false, // Set CSS color to display scrollUp active point, e.g '#00FFFF'
<script>
// Modern scroll-to-top without jQuery
(function() {
const scrollBtn = document.getElementById('scrollTopBtn');
if (scrollBtn) {
// Show/hide button based on scroll position
window.addEventListener('scroll', function() {
if (window.pageYOffset > 300) {
scrollBtn.style.display = 'block';
} else {
scrollBtn.style.display = 'none';
}
});
// Scroll to top on click
scrollBtn.addEventListener('click', function() {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
});
}
})();
</script>
+135 -68
View File
@@ -1,88 +1,155 @@
<% if current_user %>
<header>
<span style="color:#eee;margin-left:10px;">
Font Size:
<a data-no-turbolink='true' href="/dashboard/home?font=8pt" style="font-size:10pt;color:#eee" aria-label="small font">A</a>
<a data-no-turbolink='true' href="/dashboard/home?font=200%25" style="font-size:18pt;color:#eee;" aria-label="large font">A</a>
</span>
<div class="user-profile">
<button data-toggle="dropdown" class="dropdown-toggle">
<img src=" <%= image_path('profile_color.jpg')%>" alt="profile">
</button>
<span class="caret"></span>
<ul class="dropdown-menu pull-right">
<li>
<%= link_to "Account settings", user_account_settings_path(user_id: current_user.id) %>
</li>
<li>
<%= link_to "Logout", logout_path %>
</li>
</ul>
<!-- Authenticated Header -->
<header class="rg-header">
<div class="container-fluid h-100">
<div class="row h-100 align-items-center">
<div class="col-auto">
<a href="<%= home_dashboard_index_path %>" class="rg-brand">
<i class="bi bi-shield-fill-exclamation"></i> RailsGoat
</a>
</div>
<div class="col"></div>
<div class="col-auto">
<div class="d-flex align-items-center gap-3">
<!-- Font Size Controls -->
<div class="btn-group btn-group-sm" role="group" aria-label="Font size controls">
<a href="/dashboard/home?font=8pt" class="btn btn-outline-secondary" style="font-size: 10pt;" title="Small font" aria-label="Small font">
<i class="bi bi-type"></i>
</a>
<a href="/dashboard/home?font=200%25" class="btn btn-outline-secondary" style="font-size: 14pt;" title="Large font" aria-label="Large font">
<i class="bi bi-type"></i>
</a>
</div>
<!-- Tutorial Link -->
<%= button_to "https://github.com/OWASP/railsgoat/wiki", {
method: "get",
class: "btn btn-sm btn-outline-primary",
onclick: "window.open('https://github.com/OWASP/railsgoat/wiki', '_blank'); return false;"
} do %>
<i class="bi bi-book"></i> Tutorials
<% end %>
<!-- User Dropdown -->
<div class="dropdown">
<button class="btn btn-link text-decoration-none dropdown-toggle d-flex align-items-center gap-2" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<div class="bg-primary rounded-circle d-flex align-items-center justify-content-center" style="width: 32px; height: 32px;">
<i class="bi bi-person-fill text-white"></i>
</div>
<ul class="mini-nav">
<li style="color: #FFFFFF">
<!--
VULNERABILITY: XSS via html_safe
I'm going to use HTML safe because we had some weird stuff
going on with funny chars and jquery, plus it says safe so I'm guessing
nothing bad will happen
-->
Welcome, <%= current_user.first_name.html_safe %>
</li>
</ul>
<ul class="mini-nav">
<span class="text-dark"><%= current_user.first_name.html_safe %></span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<%= button_to "Visit Tutorial", nil,
{
:class => "btn",
:method => "get",
:onclick => "window.open('https://github.com/OWASP/railsgoat/wiki', '_blank')"
} %>
<%= link_to user_account_settings_path(user_id: current_user.id), class: "dropdown-item" do %>
<i class="bi bi-gear"></i> Account Settings
<% end %>
</li>
</ul>
</header>
<% else %>
<!-- Want to use this template whether auth'd or not so I've got some code to determine how to render below -->
<header>
<ul class="mini-nav">
<li><hr class="dropdown-divider"></li>
<li>
<%= button_to "Signup", signup_path, {:class => "btn btn-primary", :method => "get"} %>
</li>
</ul>
<ul class="mini-nav">
<li>
<%= button_to "login", login_path, {:class => "btn", :method => "get"} %>
</li>
</ul>
<ul class="mini-nav">
<li>
<%= button_to "Tutorial Credentials", "#myModalLabel1", {:id => "show_creds_btn", :class => "btn btn-danger", :method => "get"} %>
</li>
</ul>
<ul class="mini-nav">
<li>
<%= button_to "Visit Tutorial", nil,
{
:class => "btn",
:method => "get",
:onclick => "window.open('https://github.com/OWASP/railsgoat/wiki', '_blank')"
} %>
<%= link_to logout_path, class: "dropdown-item text-danger" do %>
<i class="bi bi-box-arrow-right"></i> Logout
<% end %>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</header>
<div id="modal_div" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myAlert" aria-hidden="true">
<% else %>
<!-- Unauthenticated Header -->
<header class="rg-header">
<div class="container-fluid h-100">
<div class="row h-100 align-items-center">
<div class="col-auto">
<span class="rg-brand">
<i class="bi bi-shield-fill-exclamation"></i> RailsGoat
</span>
</div>
<script type="text/javascript">
<div class="col"></div>
$('#show_creds_btn').click(function(event) {
<div class="col-auto">
<div class="d-flex align-items-center gap-2">
<%= button_to "Tutorial Credentials", "#", {
id: "show_creds_btn",
class: "btn btn-sm btn-warning",
method: "get",
data: { bs_toggle: "modal", bs_target: "#credentialsModal" }
} do %>
<i class="bi bi-key"></i> Demo Credentials
<% end %>
<%= button_to "https://github.com/OWASP/railsgoat/wiki", {
method: "get",
class: "btn btn-sm btn-outline-primary",
onclick: "window.open('https://github.com/OWASP/railsgoat/wiki', '_blank'); return false;"
} do %>
<i class="bi bi-book"></i> Tutorials
<% end %>
<%= button_to "Sign Up", signup_path, {
class: "btn btn-sm btn-primary",
method: "get"
} do %>
<i class="bi bi-person-plus"></i> Sign Up
<% end %>
<%= button_to "Login", login_path, {
class: "btn btn-sm btn-outline-primary",
method: "get"
} do %>
<i class="bi bi-box-arrow-in-right"></i> Login
<% end %>
</div>
</div>
</div>
</div>
</header>
<!-- Credentials Modal -->
<div class="modal fade" id="credentialsModal" tabindex="-1" aria-labelledby="credentialsModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="credentialsModalLabel">
<i class="bi bi-key"></i> Demo Credentials
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div id="modal_content" class="modal-body">
<!-- Content loaded via AJAX -->
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const showCredsBtn = document.getElementById('show_creds_btn');
if (showCredsBtn) {
showCredsBtn.addEventListener('click', function(event) {
event.preventDefault();
$("#modal_div").load(<%= credentials_tutorials_path.inspect.html_safe %>);
$("#modal_div").modal("show");
});
</script>
fetch('<%= credentials_tutorials_path %>')
.then(response => response.text())
.then(html => {
document.getElementById('modal_content').innerHTML = html;
const modal = new bootstrap.Modal(document.getElementById('credentialsModal'));
modal.show();
});
});
}
});
</script>
<% end %>
+33 -14
View File
@@ -1,19 +1,38 @@
<% flash.each do |name, msg| %>
<% name = name.to_sym %>
<% if name == :error %>
<div class="alert alert-error">
<a class="close" aria-label="dismiss" data-dismiss="alert" href="#">×</a>
<%= content_tag :div, msg, :id => "flash_notice" %>
<%
alert_class = case name
when :error, :alert
'alert-danger'
when :success, :notice
'alert-success'
when :info
'alert-info'
when :warning
'alert-warning'
else
'alert-secondary'
end
icon_class = case name
when :error, :alert
'bi-exclamation-circle-fill'
when :success, :notice
'bi-check-circle-fill'
when :info
'bi-info-circle-fill'
when :warning
'bi-exclamation-triangle-fill'
else
'bi-bell-fill'
end
%>
<div class="alert <%= alert_class %> alert-dismissible fade show d-flex align-items-center" role="alert">
<i class="bi <%= icon_class %> me-2"></i>
<div class="flex-grow-1">
<%= msg %>
</div>
<% elsif name == :success %>
<div class="alert alert-success">
<a class="close" aria-label="dismiss" data-dismiss="alert" href="#">×</a>
<%= content_tag :div, msg, :id => "flash_notice" %>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<% elsif name == :info %>
<div class="alert alert-info">
<a class="close" aria-label="dismiss" data-dismiss="alert" href="#">×</a>
<%= content_tag :div, msg, :id => "flash_notice" %>
</div>
<% end %>
<% end %>
+78 -130
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
<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>
<% 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 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") do %>
Manage Users
<%= 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") do %>
View Analytics
<%= 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 %>
<li class="mt-3">
<div class="px-4 py-2 text-white-50 text-uppercase small fw-bold">Employee</div>
</li>
<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>
<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>
<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>
</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>
<script type="text/javascript">
//Main menu navigation
$('.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');
}
});
var ul = $('#mainnav > ul');
$('#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);
}
});
</script>
</nav>
<% end %>
+96 -49
View File
@@ -1,55 +1,102 @@
<div align="right">
<!-- support for multiple languages coming soon! -->
<script>
//document.write("<select style=\"width: 100px;\">");
//document.write("<OPTION value=1>English</OPTION>");
//document.write("<OPTION value=2>Spanish</OPTION>");
<div class="rg-login-wrapper">
<div class="rg-login-card">
<div class="rg-login-header">
<div class="rg-login-logo">
<i class="bi bi-shield-fill-exclamation"></i>
</div>
<h2 class="mb-1">MetaCorp</h2>
<p class="text-muted mb-0">A GoatGroup Company</p>
</div>
<%= form_tag "sessions", class: "needs-validation", novalidate: true do %>
<div class="mb-3">
<label for="email" class="form-label">Email Address</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-envelope"></i></span>
<%= text_field_tag :email, params[:email], {
class: "form-control",
id: "email",
placeholder: "you@example.com",
required: true,
autofocus: true
} %>
</div>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-lock"></i></span>
<%= password_field_tag :password, nil, {
class: "form-control",
id: "password",
placeholder: "Enter your password",
required: true
} %>
</div>
</div>
<%= hidden_field_tag :url, @url %>
<div class="mb-3 form-check">
<%= check_box_tag :remember_me, 1, params[:remember_me], {
id: "remember_me",
class: "form-check-input"
} %>
<label class="form-check-label" for="remember_me">
Remember me
</label>
</div>
<div class="d-grid gap-2">
<%= submit_tag "Login", class: "btn btn-primary btn-lg" %>
</div>
<div class="text-center mt-3">
<%= link_to "Forgot Password?", forgot_password_path, class: "text-decoration-none" %>
</div>
<hr class="my-4">
<div class="text-center">
<p class="text-muted mb-2">Don't have an account?</p>
<%= link_to "Sign up now", signup_path, class: "btn btn-outline-primary" %>
</div>
<% end %>
<div class="mt-4 p-3 bg-warning bg-opacity-10 border border-warning rounded">
<div class="d-flex align-items-start">
<i class="bi bi-exclamation-triangle-fill text-warning me-2 mt-1"></i>
<div class="small">
<strong>Security Training Environment</strong><br>
This is an intentionally vulnerable application for educational purposes.
<a href="https://github.com/OWASP/railsgoat/wiki" target="_blank" class="text-decoration-none">Learn more</a>
</div>
</div>
</div>
</div>
</div>
<!-- VULNERABILITY: XSS via URL hash parameter -->
<script>
// support for multiple languages coming soon!
try {
var hashParam = location.hash.split("#")[1];
if (hashParam) {
var paramName = hashParam.split('=')[0];
var paramValue = decodeURIComponent(hashParam.split('=')[1]);
document.write("<OPTION value=3>" + paramValue + "</OPTION>");
} catch(err) {
// VULNERABLE: Directly writing user input to DOM
document.write("<div class='alert alert-info mt-3'>" + paramValue + "</div>");
}
//document.write("</select>");
</script>
</div>
<div class="row-fluid">
<div class="span12">
<div class="row-fluid">
<div class="span4 offset4">
<h2 align="center">MetaCorp</h2>
<h3 align="center">A GoatGroup Company</h3>
} catch(err) {
// Silently fail
}
</script>
<div class="signup">
<%= form_tag "sessions", :class=> "signup-wrapper" do %>
<div class="header">
<h2>Login</h2>
<p>Fill out the form below to login to your control panel.</p>
</div>
<div class="content">
<%= hidden_field_tag :url, @url %>
<%= text_field_tag :email, params[:email], {:class => "input input-block-level", :placeholder=>"Email"} %>
<%= password_field_tag :password, nil, {:class => "input input-block-level", :placeholder=>"Password"}%>
</div>
<div class="actions">
<%= link_to "Forgot Password", forgot_password_path, {:class=>"pull-left"}%><br/>
<%= submit_tag "Login", {:class => "btn btn-info btn-large pull-right"} %>
<span class="checkbox-wrapper">
<%= check_box_tag :remember_me, 1, params[:remember_me], {:id => "form-terms", :class => "checkbox", :type => "checkbox"} %>
<label class="checkbox-label" for="form-terms"></label> <span class="label-text">Remember</span>
</span>
<div class="clearfix"></div>
<% end %>
</div>
</div>
</div>
</div>
</div>
<style>
/* Override main content styling for login page */
.rg-main.no-sidebar {
margin: 0;
padding: 0;
}
</style>