Harden remote API security boundaries

This commit is contained in:
Bohdan Triapitsyn
2026-06-12 18:24:07 +03:00
parent c281937406
commit 106b31a407
52 changed files with 1582 additions and 579 deletions
+53 -3
View File
@@ -192,6 +192,7 @@ export type DesktopSettings = {
type DesktopBridgeGlobal = {
invoke?: (cmd: string, args?: Record<string, unknown>) => Promise<unknown>;
openDialog?: (options: Record<string, unknown>) => Promise<unknown>;
grantFileAccess?: (path: string) => Promise<unknown>;
openExternal?: (url: string) => Promise<unknown>;
listen?: (
event: string,
@@ -433,22 +434,43 @@ export const requestDirectoryAccess = async (
return { success: true, path: directoryPath };
};
const isDesktopFileGrantResult = (
value: unknown
): value is { path?: unknown; outsideFileGrant?: unknown } => (
value !== null && typeof value === 'object' && !Array.isArray(value)
);
export const requestFileAccess = async (
options?: { filters?: Array<{ name: string; extensions: string[] }>; defaultPath?: string }
): Promise<{ success: boolean; path?: string; error?: string }> => {
): Promise<{ success: boolean; path?: string; outsideFileGrant?: string; error?: string }> => {
if (hasDesktopInvoke() && isDesktopLocalOriginActive()) {
try {
const selected = await getDesktopBridge()?.openDialog?.({
directory: false,
multiple: false,
title: 'Select File',
returnGrant: true,
...(options?.filters ? { filters: options.filters } : {}),
...(options?.defaultPath ? { defaultPath: options.defaultPath } : {}),
});
if (!selected || typeof selected !== 'string') {
if (!selected) {
return { success: false, error: 'File selection cancelled' };
}
return { success: true, path: selected };
if (typeof selected === 'string') {
return { success: true, path: selected };
}
if (!isDesktopFileGrantResult(selected)) {
return { success: false, error: 'File selection cancelled' };
}
const path = typeof selected.path === 'string' ? selected.path : '';
if (!path) {
return { success: false, error: 'File selection cancelled' };
}
return {
success: true,
path,
outsideFileGrant: typeof selected.outsideFileGrant === 'string' ? selected.outsideFileGrant : undefined,
};
} catch (error) {
console.warn('Failed to request file access', error);
return { success: false, error: error instanceof Error ? error.message : String(error) };
@@ -458,6 +480,34 @@ export const requestFileAccess = async (
return { success: false, error: 'Native file picker not available' };
};
export const requestExistingFileAccess = async (
path: string
): Promise<{ success: boolean; path?: string; outsideFileGrant?: string; error?: string }> => {
const targetPath = typeof path === 'string' ? path.trim() : '';
if (!targetPath) {
return { success: false, error: 'Path is required' };
}
if (!hasDesktopInvoke() || !isDesktopLocalOriginActive()) {
return { success: false, error: 'Native file access not available' };
}
try {
const selected = await getDesktopBridge()?.grantFileAccess?.(targetPath);
if (!isDesktopFileGrantResult(selected)) {
return { success: false, error: 'File access was not granted' };
}
const grantedPath = typeof selected.path === 'string' ? selected.path : '';
const outsideFileGrant = typeof selected.outsideFileGrant === 'string' ? selected.outsideFileGrant : '';
if (!grantedPath || !outsideFileGrant) {
return { success: false, error: 'File access was not granted' };
}
return { success: true, path: grantedPath, outsideFileGrant };
} catch (error) {
console.warn('Failed to request existing file access', error);
return { success: false, error: error instanceof Error ? error.message : String(error) };
}
};
export const startAccessingDirectory = async (
directoryPath: string
): Promise<{ success: boolean; error?: string }> => {