143 lines
6.2 KiB
TypeScript
143 lines
6.2 KiB
TypeScript
import type { LoaderFunctionArgs } from "@remix-run/node";
|
|
import { json } from "@remix-run/node";
|
|
import { useLoaderData } from "@remix-run/react";
|
|
import { requireAuthLevel } from "~/utils/auth.server";
|
|
import DashboardLayout from "~/components/DashboardLayout";
|
|
import { testEncryption, encrypt, decrypt } from "~/utils/encryption.server";
|
|
|
|
export async function loader({ request }: LoaderFunctionArgs) {
|
|
// Require auth level 3 to access encryption test
|
|
const user = await requireAuthLevel(request, 3);
|
|
|
|
// Test encryption with sample data
|
|
const testResults = testEncryption("sample-smtp-password-123");
|
|
|
|
// Test with different types of data
|
|
const tests = [
|
|
{ name: "Simple Password", data: "mypassword123" },
|
|
{ name: "Complex Password", data: "P@ssw0rd!@#$%^&*()" },
|
|
{ name: "Email Password", data: "smtp.gmail.app.password" },
|
|
{ name: "Special Characters", data: "test!@#$%^&*()_+-=[]{}|;:,.<>?" }
|
|
];
|
|
|
|
const testResults2 = tests.map(test => {
|
|
try {
|
|
const encrypted = encrypt(test.data);
|
|
const decrypted = decrypt(encrypted);
|
|
return {
|
|
...test,
|
|
encrypted,
|
|
decrypted,
|
|
success: decrypted === test.data,
|
|
encryptedLength: encrypted.length
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
...test,
|
|
error: error instanceof Error ? error.message : 'Unknown error',
|
|
success: false
|
|
};
|
|
}
|
|
});
|
|
|
|
return json({
|
|
user,
|
|
basicTest: testResults,
|
|
detailedTests: testResults2
|
|
});
|
|
}
|
|
|
|
export default function TestEncryption() {
|
|
const { user, basicTest, detailedTests } = useLoaderData<typeof loader>();
|
|
|
|
return (
|
|
<DashboardLayout user={user}>
|
|
<div className="max-w-4xl mx-auto p-6">
|
|
<h1 className="text-2xl font-bold mb-6">Encryption Test Results</h1>
|
|
|
|
{/* Basic Test */}
|
|
<div className="bg-white shadow rounded-lg p-6 mb-6">
|
|
<h2 className="text-lg font-semibold mb-4">Basic Encryption Test</h2>
|
|
<div className="space-y-2">
|
|
<div className="flex items-center">
|
|
<span className="font-medium w-20">Status:</span>
|
|
<span className={`px-2 py-1 rounded text-sm ${
|
|
basicTest.success ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'
|
|
}`}>
|
|
{basicTest.success ? 'PASSED' : 'FAILED'}
|
|
</span>
|
|
</div>
|
|
{basicTest.success ? (
|
|
<>
|
|
<div><span className="font-medium">Original:</span> {basicTest.original}</div>
|
|
<div><span className="font-medium">Encrypted:</span> <code className="bg-gray-100 px-2 py-1 rounded text-sm">{basicTest.encrypted}</code></div>
|
|
<div><span className="font-medium">Decrypted:</span> {basicTest.decrypted}</div>
|
|
<div><span className="font-medium">Valid:</span> {basicTest.isValid ? '✅' : '❌'}</div>
|
|
</>
|
|
) : (
|
|
<div className="text-red-600">Error: {basicTest.error}</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Detailed Tests */}
|
|
<div className="bg-white shadow rounded-lg p-6">
|
|
<h2 className="text-lg font-semibold mb-4">Detailed Encryption Tests</h2>
|
|
<div className="overflow-x-auto">
|
|
<table className="min-w-full divide-y divide-gray-200">
|
|
<thead className="bg-gray-50">
|
|
<tr>
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Test Name</th>
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Original</th>
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Encrypted Length</th>
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Match</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody className="bg-white divide-y divide-gray-200">
|
|
{detailedTests.map((test, index) => (
|
|
<tr key={index}>
|
|
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
|
|
{test.name}
|
|
</td>
|
|
<td className="px-6 py-4 whitespace-nowrap">
|
|
<span className={`px-2 py-1 rounded text-xs ${
|
|
test.success ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'
|
|
}`}>
|
|
{test.success ? 'PASS' : 'FAIL'}
|
|
</span>
|
|
</td>
|
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
|
<code className="bg-gray-100 px-2 py-1 rounded text-xs">
|
|
{test.data.length > 20 ? test.data.substring(0, 20) + '...' : test.data}
|
|
</code>
|
|
</td>
|
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
|
{test.encryptedLength || 'N/A'}
|
|
</td>
|
|
<td className="px-6 py-4 whitespace-nowrap text-sm">
|
|
{test.success ? '✅' : '❌'}
|
|
{test.error && <div className="text-red-500 text-xs mt-1">{test.error}</div>}
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Security Notes */}
|
|
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4 mt-6">
|
|
<h3 className="text-lg font-semibold text-yellow-800 mb-2">Security Notes</h3>
|
|
<ul className="text-sm text-yellow-700 space-y-1">
|
|
<li>• Passwords are encrypted using AES-256-CBC algorithm</li>
|
|
<li>• Each encryption uses a random IV (Initialization Vector)</li>
|
|
<li>• Encrypted data format: IV:EncryptedData</li>
|
|
<li>• Encryption key should be set via ENCRYPTION_KEY environment variable</li>
|
|
<li>• This test page should only be accessible to Super Admins</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</DashboardLayout>
|
|
);
|
|
} |