Replace modal with dedicated credentials page

Removed complex modal implementation and replaced with simple
link to dedicated credentials page to eliminate all modal issues.

Changes:
- Add credentials action to TutorialsController
- Remove layout false restriction for credentials
- Replace button with simple link_to for Demo Credentials
- Remove entire modal HTML structure
- Remove all JavaScript for modal initialization
- Remove fetch/AJAX complexity

The credentials view already existed but was modal-only. Now it's
a proper page that users can navigate to directly. Much simpler!

🤖 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 01:50:54 -05:00
parent 0c4533a88a
commit feba9b7889
2 changed files with 5 additions and 72 deletions
+3 -1
View File
@@ -3,7 +3,9 @@ class TutorialsController < ApplicationController
skip_before_action :has_info
skip_before_action :authenticated
layout false, only: [:credentials]
def credentials
# Render credentials page with layout
end
# VULNERABILITY: Regular Expression Denial of Service (ReDoS)
# This endpoint demonstrates how malicious input can cause catastrophic backtracking
+2 -71
View File
@@ -81,9 +81,9 @@
<div class="col-auto">
<div class="d-flex align-items-center gap-2">
<button type="button" id="show_creds_btn" class="btn btn-sm btn-warning">
<%= link_to credentials_tutorials_path, class: "btn btn-sm btn-warning" do %>
<i class="bi bi-key"></i> Demo Credentials
</button>
<% end %>
<%= button_to "https://github.com/OWASP/railsgoat/wiki", {
method: "get",
@@ -112,73 +112,4 @@
</div>
</header>
<!-- Credentials Modal -->
<div class="modal fade" id="credentialsModal" tabindex="-1" aria-labelledby="credentialsModalLabel">
<div class="modal-dialog" role="document">
<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>
function initCredentialsModal() {
const showCredsBtn = document.getElementById('show_creds_btn');
const modalElement = document.getElementById('credentialsModal');
if (showCredsBtn && modalElement) {
// Remove any existing listeners by cloning
const newBtn = showCredsBtn.cloneNode(true);
showCredsBtn.parentNode.replaceChild(newBtn, showCredsBtn);
newBtn.addEventListener('click', function(event) {
event.preventDefault();
fetch('<%= credentials_tutorials_path %>')
.then(response => response.text())
.then(html => {
document.getElementById('modal_content').innerHTML = html;
// Dispose of any existing modal instance first
const existingModal = bootstrap.Modal.getInstance(modalElement);
if (existingModal) {
existingModal.dispose();
}
// Create fresh modal instance and show
const modal = new bootstrap.Modal(modalElement, {
backdrop: true,
keyboard: true,
focus: true
});
// Force show after a small delay to ensure DOM is ready
setTimeout(() => {
modal.show();
}, 10);
})
.catch(error => {
console.error('Error loading credentials:', error);
document.getElementById('modal_content').innerHTML = '<p class="text-danger">Error loading credentials. Please try again.</p>';
const modal = new bootstrap.Modal(modalElement);
modal.show();
});
});
}
}
// Handle both initial load and Turbolinks navigation
document.addEventListener('DOMContentLoaded', initCredentialsModal);
document.addEventListener('turbolinks:load', initCredentialsModal);
</script>
<% end %>