feat(editor): audio block (#10947)

AudioMedia entity for loading & controlling a single audio media
AudioMediaManagerService: Global audio state synchronization across tabs
AudioAttachmentService + AudioAttachmentBlock for manipulating AttachmentBlock in affine - e.g., filling transcription (using mock endpoint for now)
Added AudioBlock + AudioPlayer for rendering audio block in affine (new transcription block whose renderer is provided in affine)

fix AF-2292
fix AF-2337
This commit is contained in:
pengx17
2025-03-20 12:46:14 +00:00
parent 8a5393ea50
commit fad49bb070
120 changed files with 5407 additions and 950 deletions
@@ -1,6 +1,6 @@
import { join } from 'node:path';
import { net, protocol, session } from 'electron';
import { app, net, protocol, session } from 'electron';
import cookieParser from 'set-cookie-parser';
import { resourcesPath } from '../shared/utils';
@@ -43,8 +43,10 @@ function isNetworkResource(pathname: string) {
async function handleFileRequest(request: Request) {
const urlObject = new URL(request.url);
const isAbsolutePath = urlObject.host !== '.';
// Redirect to webpack dev server if defined
if (process.env.DEV_SERVER_URL) {
if (process.env.DEV_SERVER_URL && !isAbsolutePath) {
const devServerUrl = new URL(
urlObject.pathname,
process.env.DEV_SERVER_URL
@@ -56,20 +58,30 @@ async function handleFileRequest(request: Request) {
});
// this will be file types (in the web-static folder)
let filepath = '';
// if is a file type, load the file in resources
if (urlObject.pathname.split('/').at(-1)?.includes('.')) {
// Sanitize pathname to prevent path traversal attacks
const decodedPath = decodeURIComponent(urlObject.pathname);
const normalizedPath = join(webStaticDir, decodedPath).normalize();
if (!normalizedPath.startsWith(webStaticDir)) {
// Attempted path traversal - reject by using empty path
filepath = join(webStaticDir, '');
// for relative path, load the file in resources
if (!isAbsolutePath) {
if (urlObject.pathname.split('/').at(-1)?.includes('.')) {
// Sanitize pathname to prevent path traversal attacks
const decodedPath = decodeURIComponent(urlObject.pathname);
const normalizedPath = join(webStaticDir, decodedPath).normalize();
if (!normalizedPath.startsWith(webStaticDir)) {
// Attempted path traversal - reject by using empty path
filepath = join(webStaticDir, '');
} else {
filepath = normalizedPath;
}
} else {
filepath = normalizedPath;
// else, fallback to load the index.html instead
filepath = join(webStaticDir, 'index.html');
}
} else {
// else, fallback to load the index.html instead
filepath = join(webStaticDir, 'index.html');
filepath = decodeURIComponent(urlObject.pathname);
// security check if the filepath is within app.getPath('sessionData')
const sessionDataPath = app.getPath('sessionData');
if (!filepath.startsWith(sessionDataPath)) {
throw new Error('Invalid filepath');
}
}
return net.fetch('file://' + filepath, clonedRequest);
}