From 2f77010222da479b156578cfa929629d73f337e6 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 3 Jul 2025 02:08:53 +0000
Subject: [PATCH 1/5] Initial plan
From 0d299dedef104e6c22b73057614d8134ed31f50e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 3 Jul 2025 02:27:01 +0000
Subject: [PATCH 2/5] Implement comprehensive secure communication layer with
documentation and examples
Co-authored-by: kmock930 <78272416+kmock930@users.noreply.github.com>
---
.babelrc | 3 +
README.md | 32 +
__test__/security.test.js | 346 +++++++++++
docs/SECURITY.md | 728 +++++++++++++++++++++++
jest.config.js | 15 +
jest.setup.js | 1 +
next.config.js | 32 +-
src/app/content/navMenu.json | 7 +
src/app/examples/ErrorBoundary.js | 56 ++
src/app/examples/SecureAuthExample.js | 349 +++++++++++
src/app/examples/SecureContactForm.js | 255 ++++++++
src/app/examples/SecurityExamplesPage.js | 373 ++++++++++++
src/app/security/page.js | 13 +
src/lib/apiClient.js | 318 ++++++++++
src/lib/errorHandler.js | 270 +++++++++
src/lib/sanitize.js | 234 ++++++++
16 files changed, 3031 insertions(+), 1 deletion(-)
create mode 100644 .babelrc
create mode 100644 __test__/security.test.js
create mode 100644 docs/SECURITY.md
create mode 100644 jest.config.js
create mode 100644 jest.setup.js
create mode 100644 src/app/examples/ErrorBoundary.js
create mode 100644 src/app/examples/SecureAuthExample.js
create mode 100644 src/app/examples/SecureContactForm.js
create mode 100644 src/app/examples/SecurityExamplesPage.js
create mode 100644 src/app/security/page.js
create mode 100644 src/lib/apiClient.js
create mode 100644 src/lib/errorHandler.js
create mode 100644 src/lib/sanitize.js
diff --git a/.babelrc b/.babelrc
new file mode 100644
index 0000000..e49a7e6
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,3 @@
+{
+ "presets": ["next/babel"]
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 38d7c57..f1537d3 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,38 @@ My Personal Website: [kmock930-github-io.vercel.app](https://kmock930-github-io.
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
+## 🔐 Security Features
+
+This project includes a comprehensive secure communication layer with:
+
+- **HTTPS Implementation**: Force HTTPS in production with security headers
+- **Input Validation & Sanitization**: Comprehensive client and server-side validation
+- **API Security**: Secure API client with authentication and rate limiting
+- **Error Handling**: Secure error responses without information leakage
+- **XSS Prevention**: Input sanitization and output encoding
+- **CSRF Protection**: Request validation and token management
+- **Authentication**: JWT-based authentication with token refresh
+
+### Security Documentation
+
+- 📖 [Complete Security Guide](./docs/SECURITY.md) - Comprehensive security documentation
+- 🔧 [Security Utilities](./src/lib/) - Reusable security utilities
+- 📋 [Example Components](./src/app/examples/) - Secure component implementations
+- 🧪 [Security Tests](./tests/security.test.js) - Comprehensive security testing
+
+### Quick Security Setup
+
+```bash
+# Install dependencies
+npm install
+
+# Run security tests
+npm test -- security.test.js
+
+# Check for vulnerabilities
+npm audit
+```
+
## Getting Started
First, run the development server:
diff --git a/__test__/security.test.js b/__test__/security.test.js
new file mode 100644
index 0000000..8ac4904
--- /dev/null
+++ b/__test__/security.test.js
@@ -0,0 +1,346 @@
+/**
+ * Security Testing Examples
+ *
+ * This file contains comprehensive tests for security features
+ * including input sanitization, validation, and API security.
+ */
+
+const { sanitizeInput, validate, encodeOutput } = require('../src/lib/sanitize')
+const { handleClientError, ApiError, ErrorTypes } = require('../src/lib/errorHandler')
+
+describe('Security Features', () => {
+ describe('Input Sanitization', () => {
+ test('should sanitize text input', () => {
+ const maliciousInput = 'Hello World'
+ const sanitized = sanitizeInput.text(maliciousInput)
+
+ expect(sanitized).not.toContain('')
+ expect(sanitized).toContain('Hello World')
+ })
+
+ test('should sanitize HTML content', () => {
+ const htmlInput = '
Safe content
'
+ const sanitized = sanitizeInput.html(htmlInput)
+
+ expect(sanitized).not.toContain('')).toBeNull()
+ })
+
+ test('should sanitize URLs', () => {
+ expect(sanitizeInput.url('https://example.com')).toBe('https://example.com')
+ expect(sanitizeInput.url('http://example.com')).toBe('http://example.com')
+ expect(sanitizeInput.url('javascript:alert("XSS")')).toBeNull()
+ expect(sanitizeInput.url('data:text/html,')).toBeNull()
+ })
+
+ test('should sanitize phone numbers', () => {
+ expect(sanitizeInput.phone('(123) 456-7890')).toBe('(123) 456-7890')
+ expect(sanitizeInput.phone('123-456-7890')).toBe('123-456-7890')
+ expect(sanitizeInput.phone('+1 123 456 7890')).toBe('+1 123 456 7890')
+ expect(sanitizeInput.phone('invalid-phone')).toBeNull()
+ expect(sanitizeInput.phone('123')).toBeNull() // Too short
+ })
+
+ test('should limit text length', () => {
+ const longText = 'a'.repeat(2000)
+ const sanitized = sanitizeInput.text(longText, 100)
+
+ expect(sanitized.length).toBe(100)
+ })
+
+ test('should handle non-string inputs', () => {
+ expect(sanitizeInput.text(null)).toBe('')
+ expect(sanitizeInput.text(undefined)).toBe('')
+ expect(sanitizeInput.text(123)).toBe('')
+ expect(sanitizeInput.email(123)).toBeNull()
+ expect(sanitizeInput.url({})).toBeNull()
+ })
+ })
+
+ describe('Input Validation', () => {
+ test('should validate email format', () => {
+ expect(validate.email('test@example.com')).toBe(true)
+ expect(validate.email('invalid-email')).toBe(false)
+ expect(validate.email('')).toBe(false)
+ })
+
+ test('should validate text length', () => {
+ expect(validate.text('Hello', 3, 10)).toBe(true)
+ expect(validate.text('Hi', 3, 10)).toBe(false) // Too short
+ expect(validate.text('This is too long', 3, 10)).toBe(false) // Too long
+ })
+
+ test('should validate password strength', () => {
+ const weak = validate.password('123')
+ expect(weak.isValid).toBe(false)
+ expect(weak.errors).toContain('Password must be at least 8 characters long')
+
+ const strong = validate.password('MySecure123!')
+ expect(strong.isValid).toBe(true)
+ expect(strong.errors).toHaveLength(0)
+
+ const noNumber = validate.password('MySecurePass!')
+ expect(noNumber.isValid).toBe(false)
+ expect(noNumber.errors).toContain('Password must contain at least one number')
+ })
+
+ test('should validate URL format', () => {
+ expect(validate.url('https://example.com')).toBe(true)
+ expect(validate.url('invalid-url')).toBe(false)
+ expect(validate.url('javascript:alert("XSS")')).toBe(false)
+ })
+ })
+
+ describe('Output Encoding', () => {
+ test('should encode HTML entities', () => {
+ const input = ''
+ const encoded = encodeOutput.html(input)
+
+ expect(encoded).toBe('<script>alert("XSS")</script>')
+ })
+
+ test('should encode URLs', () => {
+ const input = 'hello world & special chars'
+ const encoded = encodeOutput.url(input)
+
+ expect(encoded).toBe('hello%20world%20%26%20special%20chars')
+ })
+
+ test('should encode JSON safely', () => {
+ const input = { message: '' }
+ const encoded = encodeOutput.json(input)
+
+ expect(encoded).toContain('\\u003c')
+ expect(encoded).toContain('\\u003e')
+ expect(encoded).not.toContain('<')
+ expect(encoded).not.toContain('>')
+ })
+
+ test('should handle non-string inputs', () => {
+ expect(encodeOutput.html(null)).toBe('')
+ expect(encodeOutput.html(undefined)).toBe('')
+ expect(encodeOutput.url(123)).toBe('')
+ })
+ })
+
+ describe('Error Handling', () => {
+ test('should handle client errors securely', () => {
+ const apiError = new ApiError('Database connection failed', ErrorTypes.SERVER, 500)
+ const handled = handleClientError(apiError)
+
+ expect(handled.message).toBe('An unexpected error occurred. Please try again.')
+ expect(handled.shouldRetry).toBe(false)
+ })
+
+ test('should handle network errors with retry suggestion', () => {
+ const networkError = new Error('fetch failed')
+ const handled = handleClientError(networkError)
+
+ expect(handled.message).toBe('Network error. Please check your connection.')
+ expect(handled.shouldRetry).toBe(true)
+ })
+
+ test('should handle validation errors', () => {
+ const validationError = new ApiError('Invalid input', ErrorTypes.VALIDATION, 400)
+ const handled = handleClientError(validationError)
+
+ expect(handled.message).toBe('Please check your input and try again.')
+ expect(handled.shouldRetry).toBe(false)
+ })
+
+ test('should handle authentication errors', () => {
+ const authError = new ApiError('Token expired', ErrorTypes.AUTHENTICATION, 401)
+ const handled = handleClientError(authError)
+
+ expect(handled.message).toBe('Please log in to continue.')
+ expect(handled.shouldRetry).toBe(false)
+ })
+
+ test('should handle rate limiting errors', () => {
+ const rateLimitError = new ApiError('Too many requests', ErrorTypes.RATE_LIMIT, 429)
+ const handled = handleClientError(rateLimitError)
+
+ expect(handled.message).toBe('Too many requests. Please wait a moment and try again.')
+ expect(handled.shouldRetry).toBe(true)
+ })
+ })
+
+ describe('XSS Prevention', () => {
+ test('should prevent script injection in text fields', () => {
+ const maliciousInputs = [
+ '',
+ 'javascript:alert("XSS")',
+ '
',
+ '