Files
eleakxir/front/src/lib/components/index/search/searchbar.svelte
2026-01-06 16:06:27 +01:00

195 lines
5.3 KiB
Svelte

<script lang="ts">
import { serverPassword, serverUrl } from "$src/lib/stores/server";
import { cn } from "$src/lib/utils";
import { Equal, EqualNot, Search, Settings } from "@lucide/svelte";
import axios from "axios";
import { toast } from "svelte-sonner";
const {
initialQuery = "",
initialFilter = "all",
initialExactMatch = false,
initialDatawells = true,
initialGithubRecon = true,
initialGravatarRecon = true,
folders = [],
initialIncludeFolders = [],
}: {
initialQuery?: string;
initialFilter?: string;
initialExactMatch?: boolean;
initialDatawells?: boolean;
initialGithubRecon?: boolean;
initialGravatarRecon?: boolean;
folders?: string[];
initialIncludeFolders?: boolean[];
} = $props();
let filters = [
"all",
"username",
"email",
"name",
"phone",
"url",
"password",
"password hash",
"full_text",
];
let activeFilter = $state<string>(initialFilter);
let query = $state<string>(initialQuery);
let exactMatch = $state<boolean>(initialExactMatch);
let datawells = $state<boolean>(initialDatawells);
let githubRecon = $state<boolean>(initialGithubRecon);
let gravatarRecon = $state<boolean>(initialGravatarRecon);
let includeFolders = $state<boolean[]>([]);
$effect(() => {
if (folders.length > 0 && includeFolders.length !== folders.length) {
includeFolders =
initialIncludeFolders.length === folders.length
? [...initialIncludeFolders]
: new Array(folders.length).fill(true);
}
});
function NewSearch() {
axios
.post(
`${$serverUrl}/search`,
{
Text: query,
Column: activeFilter,
ExactMatch: exactMatch,
Datawells: datawells,
GithubRecon: githubRecon,
GravatarRecon: gravatarRecon,
IncludeFolders: includeFolders,
},
{
headers: {
"Content-Type": "application/json",
"X-Password": $serverPassword,
},
},
)
.then((r) => {
const id = r.data.Id;
window.location.href = `/search/${id}`;
})
.catch((e) => {
if (e.response.data.Error !== undefined) {
toast.error(e.response.data.Error);
} else {
toast.error("An error occurred");
}
});
}
</script>
<div class="flex gap-5 flex-col">
<div class="w-full flex justify-between gap-5">
<div
class="flex gap-3 justify-start items-center w-full overflow-y-hidden overflow-x-auto"
>
{#each filters as filter}
<button
class={cn(
"btn btn-md capitalize",
activeFilter === filter
? "btn-primary"
: "btn-ghost btn-neutral text-base-content/80 hover:text-neutral-content",
)}
onclick={() => (activeFilter = filter)}
>{filter.replace("_", " ")}</button
>
{/each}
</div>
<div class="dropdown dropdown-end">
<div tabindex="0" role="button" class="btn m-1 btn-square btn-soft">
<Settings size={16} />
</div>
<ul
tabindex="-1"
class="dropdown-content menu bg-base-100 rounded-box z-1 w-52 p-2 shadow-sm"
>
<li>
<label class="label">
<input type="checkbox" bind:checked={datawells} class="checkbox" />
Datawells lookup
</label>
{#each folders as folder, i}
<label class="label">
{#if includeFolders[i] !== undefined}
<input
type="checkbox"
bind:checked={includeFolders[i]}
class="checkbox checkbox-xs ml-5"
disabled={!datawells}
/>
{/if}
{
folder.split("/")
.filter((part) => part.length > 0)
.pop()
}
</label>
{/each}
</li>
<li>
<label class="label">
<input
type="checkbox"
bind:checked={githubRecon}
class="checkbox"
/>
Github Recon
</label>
</li>
<li>
<label class="label">
<input
type="checkbox"
bind:checked={gravatarRecon}
class="checkbox"
/>
Gravatar Recon
</label>
</li>
</ul>
</div>
</div>
<form
class="join w-full"
onsubmit={(e) => {
e.preventDefault();
NewSearch();
}}
>
<label class="grow input input-xl input-primary join-item w-full">
<Search size={16} />
<input
class="grow input-xl"
type="text"
bind:value={query}
placeholder={(activeFilter === "all"
? "Search..."
: `Search in ${activeFilter.replace("_", " ")}...`) +
((activeFilter === "phone" && " (e.g. 612233445)") || "")}
required
/>
<div class="tooltip" data-tip="Exact Match">
<label class="toggle text-base-content toggle-xs">
<input type="checkbox" bind:checked={exactMatch} />
<EqualNot aria-label="disable" size={12} />
<Equal aria-label="enabled" size={12} />
</label>
</div>
</label>
<button class="btn btn-primary btn-xl join-item">Search</button>
</form>
</div>