236 lines
7.8 KiB
Svelte
236 lines
7.8 KiB
Svelte
<script lang="ts">
|
|
import type { Result } from "$src/lib/types";
|
|
import axios from "axios";
|
|
import { navigate, route } from "sv-router/generated";
|
|
import { serverPassword, serverUrl } from "$src/lib/stores/server";
|
|
import Searchbar from "$src/lib/components/index/search/searchbar.svelte";
|
|
import { toast } from "svelte-sonner";
|
|
import { onMount } from "svelte";
|
|
import Stats from "$src/lib/components/index/search/id/stats.svelte";
|
|
import Rows from "$src/lib/components/index/search/id/rows.svelte";
|
|
import {
|
|
ChevronDown,
|
|
CircleAlert,
|
|
CircleCheck,
|
|
CircleMinus,
|
|
CircleX,
|
|
Database,
|
|
Github,
|
|
} from "@lucide/svelte";
|
|
import { convertNanoSeconds } from "$src/lib/utils";
|
|
import GithubResult from "$src/lib/components/index/search/id/githubResult.svelte";
|
|
|
|
route.getParams("/search/:id");
|
|
|
|
let { id } = route.params;
|
|
|
|
let result = $state<Result | null>(null);
|
|
|
|
function loadData() {
|
|
if (id === undefined) {
|
|
return;
|
|
}
|
|
if (id === "") {
|
|
return;
|
|
}
|
|
axios
|
|
.get(`${$serverUrl}/search/${id}`, {
|
|
headers: {
|
|
"X-Password": $serverPassword,
|
|
},
|
|
})
|
|
.then((r) => {
|
|
result = r.data;
|
|
console.log(r.data);
|
|
if (result && result.Status !== "pending") {
|
|
clearInterval(intervalId);
|
|
}
|
|
})
|
|
.catch((e) => {
|
|
toast.error("Failed to fetch search result!");
|
|
clearInterval(intervalId);
|
|
navigate("/search");
|
|
});
|
|
}
|
|
|
|
let intervalId: ReturnType<typeof setInterval>;
|
|
let elapsedTime = 0;
|
|
let pollingInterval = 10000; // Start with a 10-second interval
|
|
|
|
onMount(() => {
|
|
if ($serverUrl === "") {
|
|
toast.error("Please, configure your server first!");
|
|
navigate("/");
|
|
return;
|
|
}
|
|
|
|
loadData();
|
|
|
|
intervalId = setInterval(() => {
|
|
elapsedTime += pollingInterval;
|
|
|
|
// Check for status change inside the interval
|
|
if (result && result.Status !== "pending") {
|
|
clearInterval(intervalId);
|
|
return;
|
|
}
|
|
|
|
// Change polling frequency based on elapsed time
|
|
if (elapsedTime >= 120000 && pollingInterval !== 10000) {
|
|
clearInterval(intervalId);
|
|
pollingInterval = 15000;
|
|
intervalId = setInterval(loadData, pollingInterval);
|
|
return;
|
|
} else if (elapsedTime >= 600000 && pollingInterval !== 30000) {
|
|
clearInterval(intervalId);
|
|
pollingInterval = 30000;
|
|
intervalId = setInterval(loadData, pollingInterval);
|
|
return;
|
|
}
|
|
|
|
loadData();
|
|
}, pollingInterval);
|
|
|
|
return () => {
|
|
clearInterval(intervalId);
|
|
};
|
|
});
|
|
</script>
|
|
|
|
<main>
|
|
{#if result}
|
|
<header class="flex gap-5 flex-col">
|
|
<a href="/search">
|
|
<h1 class="h1"><span class="text-2xl align-middle">🔍</span> Search</h1>
|
|
</a>
|
|
|
|
<Searchbar
|
|
initialQuery={result.Query.Text}
|
|
initialFilter={result.Query.Column}
|
|
initialExactMatch={result.Query.ExactMatch}
|
|
/>
|
|
</header>
|
|
|
|
<div class="my-10"></div>
|
|
|
|
<div class="grid grid-cols-1 gap-5 [&>div]:border-neutral">
|
|
<div class="card card-border shadow col-span-full">
|
|
<Stats {result} />
|
|
</div>
|
|
|
|
<div class="collapse collapse-arrow bg-base-100 border">
|
|
<input type="radio" name="my-accordion-2" checked={true} />
|
|
<div
|
|
class="collapse-title font-semibold text-xl flex justify-between items-center"
|
|
>
|
|
<div class="flex items-center gap-2">
|
|
<Database size={18} class="text-base-content/60" />
|
|
Data wells lookup
|
|
</div>
|
|
{#if result.LeakResult.Error !== ""}
|
|
<CircleX size={16} class="text-error" />
|
|
{:else if result.LeakResult.Duration === 0}
|
|
<span class="loading loading-dots loading-xs"></span>
|
|
{:else if result.LeakResult.Rows.length > 0}
|
|
<CircleCheck size={16} class="text-success" />
|
|
{:else}
|
|
<CircleMinus size={16} class="text-base-content/60" />
|
|
{/if}
|
|
</div>
|
|
<div class="collapse-content">
|
|
{#if result.LeakResult.Error !== ""}
|
|
<div role="alert" class="alert alert-soft alert-error">
|
|
<CircleAlert size={20} />
|
|
<span>Error! {result.LeakResult.Error}</span>
|
|
</div>
|
|
{:else if result.LeakResult.Duration === 0}
|
|
<ul class="list rounded-box">
|
|
{#each Array(5) as _}
|
|
<div class="list-row text-left">
|
|
<div>
|
|
<div
|
|
class="skeleton size-10 rounded-box items-center justify-center flex"
|
|
></div>
|
|
</div>
|
|
<div>
|
|
<div class="skeleton h-5 mb-1 w-52"></div>
|
|
<div
|
|
class="text-xs skeleton h-4 w-34 uppercase font-semibold opacity-60"
|
|
></div>
|
|
</div>
|
|
<div class="btn btn-square btn-ghost">
|
|
<ChevronDown size={12} />
|
|
</div>
|
|
</div>
|
|
{/each}
|
|
</ul>
|
|
{:else}
|
|
<p class="text-base-content/60">
|
|
{result.LeakResult.Rows.length} results in {convertNanoSeconds(
|
|
result.LeakResult.Duration,
|
|
)}
|
|
</p>
|
|
{#if result.LeakResult.LimitHit}
|
|
<div role="alert" class="alert alert-soft my-4">
|
|
<CircleAlert size={20} />
|
|
<div>
|
|
<span class="font-semibold">Limit hit!</span> Consider refining
|
|
your search query for more specific results.
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
<Rows {result} />
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
<div class="collapse collapse-arrow bg-base-100 border">
|
|
<input type="radio" name="my-accordion-2" />
|
|
<div
|
|
class="collapse-title font-semibold text-xl flex justify-between items-center"
|
|
>
|
|
<div class="flex items-center gap-2">
|
|
<Github size={18} class="text-base-content/60" />
|
|
Github Recon
|
|
</div>
|
|
{#if result.GithubResult.Error !== ""}
|
|
<CircleX size={16} class="text-error" />
|
|
{:else if result.GithubResult.Duration === 0}
|
|
<span class="loading loading-dots loading-xs"></span>
|
|
{:else if !result.GithubResult.EmailResult?.Commits && !result.GithubResult.EmailResult?.Spoofing && !result.GithubResult.UsernameResult?.User}
|
|
<CircleMinus size={16} class="text-base-content/60" />
|
|
{:else if result.GithubResult.UsernameResult || result.GithubResult.EmailResult}
|
|
<CircleCheck size={16} class="text-success" />
|
|
{/if}
|
|
</div>
|
|
<div class="collapse-content">
|
|
{#if result.GithubResult.Error !== ""}
|
|
<div role="alert" class="alert alert-soft alert-error">
|
|
<CircleAlert size={20} />
|
|
<span>Error! {result.GithubResult.Error}</span>
|
|
</div>
|
|
{:else if result.GithubResult.Duration === 0}
|
|
<div role="alert" class="alert alert-soft">
|
|
<span class="loading loading-dots loading-sm"></span>
|
|
<span>Loading...</span>
|
|
</div>
|
|
{:else if !result.GithubResult.EmailResult?.Commits && !result.GithubResult.EmailResult?.Spoofing && !result.GithubResult.UsernameResult?.User}
|
|
<div role="alert" class="alert alert-soft">
|
|
<CircleMinus size={20} />
|
|
<span>No result</span>
|
|
</div>
|
|
{:else}
|
|
<p class="text-base-content/60 mb-4">
|
|
Found a result in {convertNanoSeconds(
|
|
result.GithubResult.Duration,
|
|
)}
|
|
</p>
|
|
<GithubResult githubResult={result.GithubResult} />
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
|
|
<div class="mb-10"></div>
|
|
</main>
|