Skip to content

Commit

Permalink
Added user prompt to access encrypted files from dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
FlorianLeChat committed Jan 26, 2024
1 parent cdd8d2f commit 9c6723b
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 12 deletions.
1 change: 1 addition & 0 deletions app/[locale]/dashboard/components/file-upload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ export default function FileUpload( {
type: json.type,
path: new URL( json.path, window.location.href ).href,
status: json.status,
encrypted: json.encrypted,
versions: json.versions.map( ( version ) => ( {
...version,
date: new Date( version.date )
Expand Down
120 changes: 109 additions & 11 deletions app/[locale]/dashboard/components/row-actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { Ban,
History,
RefreshCw,
FolderLock,
ShieldCheck,
ArrowUpRight,
ClipboardCopy,
MoreHorizontal,
Expand Down Expand Up @@ -69,8 +70,10 @@ export default function RowActions( {

// Déclaration des variables d'état.
const rename = useRef<HTMLButtonElement>( null );
const access = useRef<HTMLButtonElement>( null );
const loading = states.loading.includes( row.id );
const [ open, setOpen ] = useState( false );
const [ password, setPassword ] = useState( "" );

// Filtrage des données d'une ou plusieurs lignes.
const rowData = states.files.filter( ( file ) => file.uuid === row.id );
Expand Down Expand Up @@ -533,7 +536,7 @@ export default function RowActions( {
);
}
}}
disabled={loading}
disabled={loading || !selectedData[ 0 ].name}
className="max-sm:w-full"
>
{loading ? (
Expand All @@ -552,16 +555,111 @@ export default function RowActions( {
</DialogContent>
</Dialog>

<a
rel="noopener noreferrer"
href={rowData[ 0 ].path}
target="_blank"
>
<DropdownMenuItem>
<ArrowUpRight className="mr-2 h-4 w-4" />
Accéder à la ressource
</DropdownMenuItem>
</a>
{rowData[ 0 ].encrypted ? (
<Dialog>
<DialogTrigger asChild>
<DropdownMenuItem
// https://github.com/radix-ui/primitives/issues/1836#issuecomment-1674338372
onSelect={( event ) => event.preventDefault()}
>
<ArrowUpRight className="mr-2 h-4 w-4" />
Accéder à la ressource
</DropdownMenuItem>
</DialogTrigger>

<DialogContent>
<DialogHeader>
<DialogTitle>
<ShieldCheck className="mr-2 inline h-5 w-5" />

<span className="align-middle">
Veuillez saisir la clé de déchiffrement.
</span>
</DialogTitle>

<DialogDescription>
Ce fichier est chiffré par une clé que le
serveur ne possède pas. Pour accéder à la
ressource, veuillez saisir la clé de
déchiffrement qui vous a été fournie lors du
téléversement du fichier.{" "}
<strong>
En cas de perte, vous ne pourrez plus
accéder à la ressource. Si c&lsquo;est
le cas, supprimez le fichier et
téléversez-le à nouveau.
L&lsquo;assistance technique ne pourra
pas vous aider car elle ne possède pas
la clé de déchiffrement.
</strong>
</DialogDescription>
</DialogHeader>

<Input
type="text"
onInput={( event ) =>
{
// Mise à jour de l'entrée utilisateur.
setPassword( event.currentTarget.value );
}}
onKeyDown={( event ) =>
{
// Soumission du formulaire par clavier.
const { key } = event;

if (
key === "Enter"
|| key === "NumpadEnter"
)
{
access.current?.click();
}
}}
spellCheck="false"
placeholder="your_key"
autoComplete="off"
autoCapitalize="off"
/>

<DialogFooter>
<Button
ref={access}
onClick={() =>
{
// Ouverture de la ressource dans un nouvel onglet.
window.open(
new URL(
`${ rowData[ 0 ].path }?key=${ password }`,
window.location.href
).href,
"_blank",
"noopener,noreferrer"
);

// Fermeture du menu des actions.
setOpen( false );
}}
disabled={loading || !password}
className="max-sm:w-full"
>
<ArrowUpRight className="mr-2 h-4 w-4" />
Accéder
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
) : (
<a
rel="noopener noreferrer"
href={rowData[ 0 ].path}
target="_blank"
>
<DropdownMenuItem>
<ArrowUpRight className="mr-2 h-4 w-4" />
Accéder à la ressource
</DropdownMenuItem>
</a>
)}

<DropdownMenuSeparator />

Expand Down
1 change: 1 addition & 0 deletions app/[locale]/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ async function getFiles(): Promise<FileAttributes[]>
type: mime.getType( file.name ) ?? "application/octet-stream",
path,
status: file.status ?? "public",
encrypted: file.encrypted,
versions: file.versions.map( ( version ) => ( {
uuid: version.id,
size: Number( version.size ),
Expand Down
3 changes: 3 additions & 0 deletions interfaces/File.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ export interface FileAttributes {
// Statut de partage du fichier.
status: "public" | "private" | "shared";

// État de chiffrement du fichier.
encrypted: boolean;

// Liste des versions du fichier.
versions: {
// Identifiant unique de la version.
Expand Down
6 changes: 5 additions & 1 deletion middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,14 @@ export default async function middleware( request: NextRequest )
{
// On récupère le tampon de données du fichier ainsi que
// la clé de chiffrement.
const key = request.nextUrl.searchParams.get( "key" );
const buffer = new Uint8Array( await content.arrayBuffer() );
const cipher = await crypto.subtle.importKey(
"raw",
Buffer.from( process.env.AUTH_SECRET ?? "", "base64" ),
Buffer.from(
key ?? process.env.AUTH_SECRET ?? "",
"base64"
),
{
name: "AES-GCM",
length: 256
Expand Down
1 change: 1 addition & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ model File {
userId String
name String
status String
encrypted Boolean @default(false)
expiration DateTime?
versions Version[]
}
Expand Down

0 comments on commit 9c6723b

Please sign in to comment.