195 lines
5.3 KiB
Svelte
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>
|