new redis migration

Signed-off-by: ale <ale@manalejandro.com>
Este commit está contenido en:
ale
2025-12-15 16:35:35 +01:00
padre ad7a1cf0a7
commit 3ce64eeb8e
Se han modificado 20 ficheros con 1021 adiciones y 712 borrados

Ver fichero

@@ -1,34 +1,29 @@
import { NextResponse } from 'next/server';
import { esClient, INDEX_NAME } from '@/lib/elasticsearch';
import { getRedisInfo, getStats, INDEX_NAME } from '@/lib/redis';
export async function GET() {
try {
// Check Elasticsearch connection
const health = await esClient.cluster.health({});
// Check Redis connection and get info
const redisInfo = await getRedisInfo();
// Check if index exists
const indexExists = await esClient.indices.exists({ index: INDEX_NAME });
// Get index stats if exists
let stats = null;
if (indexExists) {
const statsResponse = await esClient.indices.stats({ index: INDEX_NAME });
stats = {
documentCount: statsResponse._all?.primaries?.docs?.count || 0,
indexSize: statsResponse._all?.primaries?.store?.size_in_bytes || 0
};
}
// Get index stats
const stats = await getStats();
return NextResponse.json({
status: 'ok',
elasticsearch: {
cluster: health.cluster_name,
status: health.status,
redis: {
connected: redisInfo.connected,
version: redisInfo.version,
usedMemory: redisInfo.usedMemory,
dbSize: redisInfo.dbSize
},
index: {
exists: indexExists,
exists: true,
name: INDEX_NAME,
stats
stats: {
documentCount: stats.count,
indexSize: stats.size
}
}
});
} catch (error) {

Ver fichero

@@ -1,17 +1,7 @@
import { NextRequest, NextResponse } from 'next/server';
import { esClient, INDEX_NAME, initializeIndex } from '@/lib/elasticsearch';
import { storeHashDocument, findByPlaintext, findByHash, initializeRedis } from '@/lib/redis';
import { generateHashes, detectHashType } from '@/lib/hash';
interface HashDocument {
plaintext: string;
md5: string;
sha1: string;
sha256: string;
sha512: string;
bcrypt: string;
created_at?: string;
}
export async function POST(request: NextRequest) {
try {
const { query } = await request.json();
@@ -23,8 +13,8 @@ export async function POST(request: NextRequest) {
);
}
// Ensure index exists
await initializeIndex();
// Ensure Redis is connected
await initializeRedis();
const cleanQuery = query.trim().split(/\s+/)[0];
@@ -39,37 +29,24 @@ export async function POST(request: NextRequest) {
const hashType = detectHashType(cleanQueryLower);
if (hashType) {
// Query is a hash - search for it in Elasticsearch
const searchResponse = await esClient.search<HashDocument>({
index: INDEX_NAME,
query: {
term: {
[hashType]: hashType === 'bcrypt' ? cleanQuery : cleanQueryLower
}
}
});
// Query is a hash - search for it in Redis
const doc = await findByHash(hashType, cleanQueryLower);
const hits = searchResponse.hits.hits;
if (hits.length > 0) {
if (doc) {
// Found matching plaintext
return NextResponse.json({
found: true,
hashType,
hash: cleanQuery,
results: hits.map((hit) => {
const source = hit._source!;
return {
plaintext: source.plaintext,
hashes: {
md5: source.md5,
sha1: source.sha1,
sha256: source.sha256,
sha512: source.sha512,
bcrypt: source.bcrypt,
}
};
})
results: [{
plaintext: doc.plaintext,
hashes: {
md5: doc.md5,
sha1: doc.sha1,
sha256: doc.sha256,
sha512: doc.sha512,
}
}]
});
} else {
// Hash not found in database
@@ -82,72 +59,41 @@ export async function POST(request: NextRequest) {
}
} else {
// Query is plaintext - check if it already exists first
const existsResponse = await esClient.search<HashDocument>({
index: INDEX_NAME,
query: {
term: {
'plaintext.keyword': cleanQuery
}
}
});
const existingDoc = await findByPlaintext(cleanQuery);
let hashes;
let wasGenerated = false;
if (existsResponse.hits.hits.length > 0) {
if (existingDoc) {
// Plaintext found, retrieve existing hashes
const existingDoc = existsResponse.hits.hits[0]._source!;
hashes = {
md5: existingDoc.md5,
sha1: existingDoc.sha1,
sha256: existingDoc.sha256,
sha512: existingDoc.sha512,
bcrypt: existingDoc.bcrypt,
};
} else {
// Plaintext not found, generate hashes and check if any hash already exists
// Plaintext not found, generate and store hashes
hashes = await generateHashes(cleanQuery);
const hashExistsResponse = await esClient.search<HashDocument>({
index: INDEX_NAME,
query: {
bool: {
should: [
{ term: { md5: hashes.md5 } },
{ term: { sha1: hashes.sha1 } },
{ term: { sha256: hashes.sha256 } },
{ term: { sha512: hashes.sha512 } },
],
minimum_should_match: 1
}
}
await storeHashDocument({
...hashes,
created_at: new Date().toISOString()
});
if (hashExistsResponse.hits.hits.length === 0) {
// No duplicates found, insert new document
await esClient.index({
index: INDEX_NAME,
document: {
...hashes,
created_at: new Date().toISOString()
}
});
// Refresh index to make the document searchable immediately
await esClient.indices.refresh({ index: INDEX_NAME });
}
wasGenerated = true;
}
return NextResponse.json({
found: true,
isPlaintext: true,
plaintext: cleanQuery,
wasGenerated: existsResponse.hits.hits.length === 0,
wasGenerated,
hashes: {
md5: hashes.md5,
sha1: hashes.sha1,
sha256: hashes.sha256,
sha512: hashes.sha512,
bcrypt: hashes.bcrypt,
}
});
}

Ver fichero

@@ -14,8 +14,8 @@ const geistMono = Geist_Mono({
export const metadata: Metadata = {
title: "Hasher - Hash Search & Generator",
description: "Search for hashes or generate them from plaintext. Supports MD5, SHA1, SHA256, SHA512, and Bcrypt. Powered by Elasticsearch.",
keywords: ["hash", "md5", "sha1", "sha256", "sha512", "bcrypt", "hash generator", "hash search", "elasticsearch"],
description: "Search for hashes or generate them from plaintext. Supports MD5, SHA1, SHA256, and SHA512. Powered by Redis.",
keywords: ["hash", "md5", "sha1", "sha256", "sha512", "hash generator", "hash search", "redis"],
authors: [{ name: "Hasher" }],
creator: "Hasher",
publisher: "Hasher",
@@ -28,7 +28,7 @@ export const metadata: Metadata = {
openGraph: {
type: "website",
title: "Hasher - Hash Search & Generator",
description: "Search for hashes or generate them from plaintext. Supports MD5, SHA1, SHA256, SHA512, and Bcrypt.",
description: "Search for hashes or generate them from plaintext. Supports MD5, SHA1, SHA256, and SHA512.",
siteName: "Hasher",
images: [
{
@@ -42,7 +42,7 @@ export const metadata: Metadata = {
twitter: {
card: "summary",
title: "Hasher - Hash Search & Generator",
description: "Search for hashes or generate them from plaintext. Supports MD5, SHA1, SHA256, SHA512, and Bcrypt.",
description: "Search for hashes or generate them from plaintext. Supports MD5, SHA1, SHA256, and SHA512.",
images: ["/logo.png"],
},
viewport: {

Ver fichero

@@ -15,7 +15,6 @@ interface SearchResult {
sha1: string;
sha256: string;
sha512: string;
bcrypt: string;
};
results?: Array<{
plaintext: string;
@@ -24,7 +23,6 @@ interface SearchResult {
sha1: string;
sha256: string;
sha512: string;
bcrypt: string;
};
}>;
message?: string;
@@ -144,7 +142,7 @@ export default function Home() {
Search for hashes or generate them from plaintext
</p>
<p className="text-sm text-gray-500 mt-2">
Supports MD5, SHA1, SHA256, SHA512, and Bcrypt
Supports MD5, SHA1, SHA256, and SHA512
</p>
{stats && (
<div className="flex items-center justify-center gap-4 mt-4 text-sm text-gray-500">
@@ -214,7 +212,6 @@ export default function Home() {
<HashDisplay label="SHA1" value={result.hashes!.sha1} field="sha1-gen" />
<HashDisplay label="SHA256" value={result.hashes!.sha256} field="sha256-gen" />
<HashDisplay label="SHA512" value={result.hashes!.sha512} field="sha512-gen" />
<HashDisplay label="Bcrypt" value={result.hashes!.bcrypt} field="bcrypt-gen" />
</div>
{result.wasGenerated && (
<div className="mt-6 bg-blue-50 border border-blue-200 rounded-xl p-4">
@@ -260,7 +257,6 @@ export default function Home() {
<HashDisplay label="SHA1" value={item.hashes.sha1} field={`sha1-${idx}`} />
<HashDisplay label="SHA256" value={item.hashes.sha256} field={`sha256-${idx}`} />
<HashDisplay label="SHA512" value={item.hashes.sha512} field={`sha512-${idx}`} />
<HashDisplay label="Bcrypt" value={item.hashes.bcrypt} field={`bcrypt-${idx}`} />
</div>
</div>
))}
@@ -304,7 +300,7 @@ export default function Home() {
</div>
<h3 className="text-xl font-bold text-gray-900 mb-2">Generate Hashes</h3>
<p className="text-gray-600">
Enter any plaintext to instantly generate MD5, SHA1, SHA256, SHA512, and Bcrypt hashes. Results are saved automatically.
Enter any plaintext to instantly generate MD5, SHA1, SHA256, and SHA512 hashes. Results are saved automatically.
</p>
</div>
</div>
@@ -312,7 +308,7 @@ export default function Home() {
{/* Footer */}
<footer className="mt-16 text-center text-gray-500 text-sm">
<p>Powered by Elasticsearch Built with Next.js</p>
<p>Powered by Redis Built with Next.js</p>
</footer>
</div>
</div>