fix share password issues
This commit is contained in:
@@ -120,19 +120,24 @@ export async function listShareFiles(
|
||||
| { success: true; files: DirectoryEntry[]; parent: DirectoryEntry | null }
|
||||
| { success: false }
|
||||
> {
|
||||
const { data } = await useFetch<
|
||||
const { data, error } = await useFetch<
|
||||
ApiResponse<{ files: DirectoryEntry[]; parent: DirectoryEntry | null }>
|
||||
>(getApiUrl('warrens/files/ls_share'), {
|
||||
method: 'POST',
|
||||
headers: getApiHeaders(),
|
||||
// This is only required for development
|
||||
headers:
|
||||
password != null
|
||||
? { ...getApiHeaders(), 'X-Share-Password': password }
|
||||
: getApiHeaders(),
|
||||
body: JSON.stringify({
|
||||
shareId: shareId,
|
||||
path: path,
|
||||
password: password,
|
||||
}),
|
||||
});
|
||||
|
||||
if (data.value == null) {
|
||||
const errorMessage = await error.value?.data;
|
||||
console.log(errorMessage);
|
||||
return {
|
||||
success: false,
|
||||
};
|
||||
@@ -174,3 +179,32 @@ export async function fetchShareFile(
|
||||
data: data.value,
|
||||
};
|
||||
}
|
||||
|
||||
export async function verifySharePassword(
|
||||
shareId: string,
|
||||
password: string
|
||||
): Promise<{ success: boolean }> {
|
||||
const { data } = await useFetch<ApiResponse<null>>(
|
||||
getApiUrl(`warrens/files/verify_share_password`),
|
||||
{
|
||||
method: 'POST',
|
||||
headers: getApiHeaders(),
|
||||
body: JSON.stringify({
|
||||
shareId: shareId,
|
||||
password: password,
|
||||
}),
|
||||
responseType: 'json',
|
||||
cache: 'default',
|
||||
}
|
||||
);
|
||||
|
||||
if (data.value == null || data.value.status !== 200) {
|
||||
return {
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
<script lang="ts" setup>
|
||||
import { fetchShareFile, getShare, listShareFiles } from '~/lib/api/shares';
|
||||
import byteSize from 'byte-size';
|
||||
import { toast } from 'vue-sonner';
|
||||
import {
|
||||
fetchShareFile,
|
||||
getShare,
|
||||
listShareFiles,
|
||||
verifySharePassword,
|
||||
} from '~/lib/api/shares';
|
||||
import type { DirectoryEntry } from '~/shared/types';
|
||||
import type { Share } from '~/shared/types/shares';
|
||||
import { useImageViewer, useTextEditor } from '~/stores/viewers';
|
||||
@@ -60,7 +67,39 @@ async function getShareFromQuery(): Promise<{
|
||||
}
|
||||
|
||||
async function submitPassword() {
|
||||
loadFiles();
|
||||
if (share == null || loading.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!passwordValid.value) {
|
||||
loading.value = true;
|
||||
const result = await verifySharePassword(share.data.id, password.value);
|
||||
loading.value = false;
|
||||
|
||||
if (result.success) {
|
||||
passwordValid.value = true;
|
||||
let cookie = `X-Share-Password=${password.value}; Path=/; SameSite=Lax; Secure;`;
|
||||
|
||||
if (share.data.expiresAt != null) {
|
||||
const dayjs = useDayjs();
|
||||
|
||||
const diff = dayjs(share.data.expiresAt).diff(dayjs()) / 1000;
|
||||
cookie += `Max-Age=${diff};`;
|
||||
}
|
||||
|
||||
document.cookie = cookie;
|
||||
} else {
|
||||
toast.error('Share', {
|
||||
id: 'SHARE_PASSWORD_TOAST',
|
||||
description: 'Invalid password',
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (share.file.fileType === 'directory') {
|
||||
loadFiles();
|
||||
}
|
||||
}
|
||||
|
||||
async function loadFiles() {
|
||||
@@ -68,10 +107,6 @@ async function loadFiles() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (share.file.fileType !== 'directory') {
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
|
||||
const result = await listShareFiles(
|
||||
@@ -81,18 +116,6 @@ async function loadFiles() {
|
||||
);
|
||||
|
||||
if (result.success) {
|
||||
passwordValid.value = true;
|
||||
let cookie = `X-Share-Password=${password.value}; Path=/; SameSite=Lax; Secure;`;
|
||||
|
||||
if (share.data.expiresAt != null) {
|
||||
const dayjs = useDayjs();
|
||||
|
||||
const diff = dayjs(share.data.expiresAt).diff(dayjs()) / 1000;
|
||||
cookie += `Max-Age=${diff};`;
|
||||
}
|
||||
|
||||
document.cookie = cookie;
|
||||
|
||||
warrenStore.setCurrentWarrenEntries(result.files, result.parent);
|
||||
}
|
||||
|
||||
@@ -102,7 +125,11 @@ async function loadFiles() {
|
||||
async function onEntryClicked(entry: DirectoryEntry, event: MouseEvent) {
|
||||
event.stopPropagation();
|
||||
|
||||
if (warrenStore.current == null) {
|
||||
if (
|
||||
warrenStore.current == null ||
|
||||
share == null ||
|
||||
(share.data.password && !passwordValid.value)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -110,7 +137,10 @@ async function onEntryClicked(entry: DirectoryEntry, event: MouseEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entryPath = joinPaths(warrenStore.current.path, entry.name);
|
||||
const entryPath =
|
||||
entry !== share.file
|
||||
? joinPaths(warrenStore.current.path, entry.name)
|
||||
: warrenStore.current.path;
|
||||
|
||||
if (entry.fileType === 'directory') {
|
||||
warrenStore.setCurrentWarrenPath(entryPath);
|
||||
@@ -217,17 +247,35 @@ function onEntryDownload(entry: DirectoryEntry) {
|
||||
>
|
||||
<div
|
||||
:class="[
|
||||
'h-[min(98vh,600px)] w-full max-w-screen-xl rounded-lg border transition-all',
|
||||
passwordValid ? 'max-w-screen-xl' : 'max-w-lg',
|
||||
'w-full rounded-lg border transition-all',
|
||||
passwordValid && share.file.fileType === 'directory'
|
||||
? 'h-[min(98vh,600px)] max-w-screen-xl'
|
||||
: 'max-w-2xl',
|
||||
]"
|
||||
>
|
||||
<div
|
||||
class="flex flex-row items-center justify-between gap-4 px-6 pt-6"
|
||||
>
|
||||
<div class="flex w-full flex-row">
|
||||
<div class="flex grow flex-col gap-1.5">
|
||||
<h3 class="leading-none font-semibold">Share</h3>
|
||||
<p class="text-muted-foreground text-sm">
|
||||
<div class="flex flex-row items-center justify-between gap-4 p-6">
|
||||
<button
|
||||
:disabled="share.data.password && !passwordValid"
|
||||
:class="[
|
||||
'flex min-w-0 grow flex-row items-center gap-2 text-left',
|
||||
(!share.data.password || passwordValid) &&
|
||||
'cursor-pointer',
|
||||
]"
|
||||
@click="(e) => onEntryClicked(share!.file, e)"
|
||||
>
|
||||
<DirectoryEntryIcon :entry="share.file" />
|
||||
|
||||
<div class="flex flex-col overflow-hidden">
|
||||
<h3
|
||||
:title="share.file.name"
|
||||
class="truncate leading-none font-semibold"
|
||||
>
|
||||
{{ share.file.name }}
|
||||
</h3>
|
||||
<p class="text-muted-foreground text-sm text-nowrap">
|
||||
{{ byteSize(share.file.size) }}
|
||||
</p>
|
||||
<p class="text-muted-foreground text-sm text-nowrap">
|
||||
Created
|
||||
{{
|
||||
$dayjs(share.data.createdAt).format(
|
||||
@@ -236,19 +284,12 @@ function onEntryDownload(entry: DirectoryEntry) {
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-row items-center justify-end gap-4">
|
||||
<p>{{ share.file.name }}</p>
|
||||
<DirectoryEntryIcon
|
||||
:entry="{ ...share.file, name: '/' }"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<div class="flex flex-row items-end">
|
||||
<Button
|
||||
:class="
|
||||
share.file.fileType !== 'file' &&
|
||||
entries == null &&
|
||||
'hidden'
|
||||
share.data.password && !passwordValid && 'hidden'
|
||||
"
|
||||
size="icon"
|
||||
variant="outline"
|
||||
@@ -258,7 +299,13 @@ function onEntryDownload(entry: DirectoryEntry) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex w-full flex-col p-6">
|
||||
<div
|
||||
v-if="
|
||||
share.file.fileType === 'directory' ||
|
||||
(share.data.password && !passwordValid)
|
||||
"
|
||||
class="flex w-full flex-col px-6 pb-6"
|
||||
>
|
||||
<DirectoryList
|
||||
v-if="entries != null"
|
||||
:entries
|
||||
|
||||
Reference in New Issue
Block a user