import { api, API_CLIENT } from '../utils/api.ts'; import * as asserts from '@std/assert'; import { delete_user, EPHEMERAL_SERVER, get_ephemeral_listen_server, get_new_user, random_username, set_user_permissions } from './helpers.ts'; import { Cookie } from '@std/http/cookie'; import { generateTotp } from '../utils/totp.ts'; import * as fs from '@std/fs'; import * as path from '@std/path'; import { ensureFile } from '@std/fs'; Deno.test({ name: 'file uploading (home directory)', permissions: { env: true, read: true, write: true, net: true }, sanitizeResources: false, sanitizeOps: false, fn: async () => { let test_server_info: EPHEMERAL_SERVER | null = null; try { console.dir({ SERVERUS_PUT_PATHS_ALLOWED: Deno.env.get('SERVERUS_PUT_PATHS_ALLOWED') }); test_server_info = await get_ephemeral_listen_server(); const client: API_CLIENT = api({ prefix: '/api', hostname: test_server_info.hostname, port: test_server_info.port }); const owner_info = await get_new_user(client); asserts.assert(owner_info); const user = owner_info.user; asserts.assert(user); asserts.assert(user.id); const upload_body = new FormData(); upload_body.append( 'file', new File(['this is the test content'], 'test_uploading_to_home_dir.txt') ); const upload_response = await fetch( `http://${test_server_info.hostname}:${test_server_info.port}/files/users/${user.id}/test_uploading_to_home_dir.txt`, { method: 'PUT', headers: owner_info.headers, body: upload_body } ); asserts.assert(upload_response.ok); const upload_response_body = await upload_response.text(); asserts.assert(upload_response_body); const get_response = await fetch( `http://${test_server_info.hostname}:${test_server_info.port}/files/users/${user.id}/test_uploading_to_home_dir.txt` ); asserts.assert(get_response.ok); asserts.assert(get_response.body); const local_download_path = path.join(Deno.cwd(), 'files', 'users', user.id, 'test_uploading_to_home_dir.txt-downloaded'); await ensureFile(local_download_path); const file = await Deno.open(local_download_path, { truncate: true, write: true }); await get_response.body.pipeTo(file.writable); const download_content = await Deno.readTextFile(local_download_path); asserts.assert(download_content); asserts.assertEquals(download_content, 'this is the test content'); await Deno.remove(local_download_path); asserts.assert(!fs.existsSync(local_download_path)); const uploaded_to_homedir_path = path.join(Deno.cwd(), 'files', 'users', user.id, 'test_uploading_to_home_dir.txt'); await Deno.remove(uploaded_to_homedir_path); asserts.assert(!fs.existsSync(uploaded_to_homedir_path)); let dir = path.dirname(uploaded_to_homedir_path); do { if (dir.endsWith('files')) { break; } const files = Deno.readDirSync(dir); let has_files = false; for (const _ of files) { has_files = true; break; } if (has_files) { dir = ''; break; } await Deno.remove(dir); dir = path.dirname(dir); } while (dir.length); await delete_user(client, owner_info); } finally { if (test_server_info) { await test_server_info?.server?.stop(); } } } }); Deno.test({ name: 'file uploading (outside home directory)', permissions: { env: true, read: true, write: true, net: true }, sanitizeResources: false, sanitizeOps: false, fn: async () => { let test_server_info: EPHEMERAL_SERVER | null = null; try { test_server_info = await get_ephemeral_listen_server(); const client: API_CLIENT = api({ prefix: '/api', hostname: test_server_info.hostname, port: test_server_info.port }); const root_user_info = await get_new_user(client); asserts.assert(root_user_info); const regular_user_info = await get_new_user(client, {}, root_user_info); asserts.assert(regular_user_info); const upload_body = new FormData(); upload_body.append( 'file', new File(['this is the root dir test content'], 'test_uploading_to_root_dir.txt') ); const disallowed_upload_response = await fetch( `http://${test_server_info.hostname}:${test_server_info.port}/files/test_uploading_to_root_dir.txt`, { method: 'PUT', headers: { 'x-session_id': regular_user_info.session.id, 'x-totp': await generateTotp(regular_user_info.session.secret) }, body: upload_body } ); asserts.assert(!disallowed_upload_response.ok); await disallowed_upload_response.text(); await set_user_permissions(client, regular_user_info.user, regular_user_info.session, [...regular_user_info.user.permissions, 'files.write.all']); const allowed_upload_response = await fetch( `http://${test_server_info.hostname}:${test_server_info.port}/files/test_uploading_to_root_dir.txt`, { method: 'PUT', headers: { 'x-session_id': regular_user_info.session.id, 'x-totp': await generateTotp(regular_user_info.session.secret) }, body: upload_body } ); asserts.assert(allowed_upload_response.ok); await allowed_upload_response.text(); const get_response = await fetch( `http://${test_server_info.hostname}:${test_server_info.port}/files/test_uploading_to_root_dir.txt` ); asserts.assert(get_response.ok); asserts.assert(get_response.body); const local_download_path = path.join(Deno.cwd(), 'files', 'test_uploading_to_root_dir.txt-downloaded'); await ensureFile(local_download_path); const file = await Deno.open(local_download_path, { truncate: true, write: true }); await get_response.body.pipeTo(file.writable); const download_content = await Deno.readTextFile(local_download_path); asserts.assert(download_content); asserts.assertEquals(download_content, 'this is the root dir test content'); await Deno.remove(local_download_path); asserts.assert(!fs.existsSync(local_download_path)); const uploaded_to_root_dir_path = path.join(Deno.cwd(), 'files', 'test_uploading_to_root_dir.txt'); await Deno.remove(uploaded_to_root_dir_path); asserts.assert(!fs.existsSync(uploaded_to_root_dir_path)); let dir = path.dirname(uploaded_to_root_dir_path); do { if (dir.endsWith('files')) { break; } const files = Deno.readDirSync(dir); let has_files = false; for (const _ of files) { has_files = true; break; } if (has_files) { dir = ''; break; } await Deno.remove(dir); dir = path.dirname(dir); } while (dir.length); } finally { if (test_server_info) { await test_server_info?.server?.stop(); } } } });