feat: implement prompt injection protection and OpenRouter paid API key support

- Add comprehensive prompt injection security module with 160+ attack pattern detection
- Implement security checks in message handling with proper blocking and user feedback
- Add OpenRouter paid API key support (OPENROUTER_PAID_API_KEY) for premium models
- Update model discovery and chat functions to use paid API key for premium models
- Add comprehensive test suite with 434 test cases (98.39% accuracy)
- Tests cover legitimate WordPress development queries, injection attacks, obfuscated attempts
- Improve builder loading indicators with text-based progress (building/planning)
- Replace spinning animations with 'Starting build/planning process' messages
This commit is contained in:
southseact-3d
2026-02-08 13:23:59 +00:00
parent 6e0d039d7c
commit 0f631dc99a
6 changed files with 1440 additions and 39 deletions

View File

@@ -1634,23 +1634,74 @@ function renderSessionMeta(session) {
}
// Helper functions for loading indicator
function showLoadingIndicator(text) {
function showLoadingIndicator(type) {
// Remove any existing loading indicator first
hideLoadingIndicator();
const loadingDiv = document.createElement('div');
loadingDiv.className = 'loading-indicator animate-in';
loadingDiv.id = 'loading-indicator';
loadingDiv.style.cssText = 'display: flex; flex-direction: column; align-items: flex-start; padding: 16px; background: var(--shopify-bg); border-radius: 8px; margin: 8px 0;';
const spinner = document.createElement('div');
spinner.className = 'loading-spinner';
// Create status container
const statusContainer = document.createElement('div');
statusContainer.style.cssText = 'display: flex; align-items: center; gap: 12px; margin-bottom: 8px;';
const textSpan = document.createElement('span');
textSpan.className = 'loading-text';
textSpan.textContent = text;
// Create animated dots
const dotsContainer = document.createElement('div');
dotsContainer.style.cssText = 'display: flex; gap: 4px;';
for (let i = 0; i < 3; i++) {
const dot = document.createElement('span');
dot.style.cssText = `width: 8px; height: 8px; background: var(--shopify-green); border-radius: 50%; animation: loadingDot 1.4s ease-in-out ${i * 0.2}s infinite;`;
dotsContainer.appendChild(dot);
}
loadingDiv.appendChild(spinner);
loadingDiv.appendChild(textSpan);
// Create status text
const statusText = document.createElement('span');
statusText.className = 'loading-status-text';
statusText.style.cssText = 'font-weight: 600; color: var(--shopify-text); font-size: 14px;';
// Set appropriate text based on type
if (type === 'planning') {
statusText.textContent = 'Starting planning process';
} else {
statusText.textContent = 'Starting build process';
}
statusContainer.appendChild(dotsContainer);
statusContainer.appendChild(statusText);
// Create detailed info text
const detailText = document.createElement('span');
detailText.className = 'loading-detail-text';
detailText.style.cssText = 'font-size: 12px; color: var(--shopify-text-secondary); margin-left: 32px;';
if (type === 'planning') {
detailText.textContent = 'Analyzing your request and creating a development plan...';
} else {
detailText.textContent = 'Building your plugin with AI-generated code...';
}
// Add animation keyframes if not already added
if (!document.getElementById('loading-animations')) {
const style = document.createElement('style');
style.id = 'loading-animations';
style.textContent = `
@keyframes loadingDot {
0%, 80%, 100% { transform: scale(0.6); opacity: 0.5; }
40% { transform: scale(1); opacity: 1; }
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
`;
document.head.appendChild(style);
}
loadingDiv.appendChild(statusContainer);
loadingDiv.appendChild(detailText);
el.chatArea.appendChild(loadingDiv);