fix(core): Handle missing binary metadata in download urls (#5242)

This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™ 2023-01-25 10:19:19 +01:00 committed by GitHub
parent ac460aa841
commit 21579a8a2a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 44 additions and 15 deletions

View file

@ -95,6 +95,7 @@ import {
import { credentialsController } from '@/credentials/credentials.controller'; import { credentialsController } from '@/credentials/credentials.controller';
import { oauth2CredentialController } from '@/credentials/oauth2Credential.api'; import { oauth2CredentialController } from '@/credentials/oauth2Credential.api';
import type { import type {
BinaryDataRequest,
CurlHelper, CurlHelper,
ExecutionRequest, ExecutionRequest,
NodeListSearchRequest, NodeListSearchRequest,
@ -1305,19 +1306,24 @@ class Server extends AbstractServer {
// Download binary // Download binary
this.app.get( this.app.get(
`/${this.restEndpoint}/data/:path`, `/${this.restEndpoint}/data/:path`,
async (req: express.Request, res: express.Response): Promise<void> => { async (req: BinaryDataRequest, res: express.Response): Promise<void> => {
// TODO UM: check if this needs permission check for UM // TODO UM: check if this needs permission check for UM
const identifier = req.params.path; const identifier = req.params.path;
const binaryDataManager = BinaryDataManager.getInstance(); const binaryDataManager = BinaryDataManager.getInstance();
const binaryPath = binaryDataManager.getBinaryPath(identifier); const binaryPath = binaryDataManager.getBinaryPath(identifier);
const { mimeType, fileName, fileSize } = await binaryDataManager.getBinaryMetadata( let { mode, fileName, mimeType } = req.query;
identifier, if (!fileName || !mimeType) {
); try {
const metadata = await binaryDataManager.getBinaryMetadata(identifier);
fileName = metadata.fileName;
mimeType = metadata.mimeType;
res.setHeader('Content-Length', metadata.fileSize);
} catch {}
}
if (mimeType) res.setHeader('Content-Type', mimeType); if (mimeType) res.setHeader('Content-Type', mimeType);
if (req.query.mode === 'download' && fileName) { if (mode === 'download') {
res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`); res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`);
} }
res.setHeader('Content-Length', fileSize);
res.sendFile(binaryPath); res.sendFile(binaryPath);
}, },
); );

View file

@ -350,3 +350,14 @@ export declare namespace CurlHelper {
export declare namespace LicenseRequest { export declare namespace LicenseRequest {
type Activate = AuthenticatedRequest<{}, {}, { activationKey: string }, {}>; type Activate = AuthenticatedRequest<{}, {}, { activationKey: string }, {}>;
} }
export type BinaryDataRequest = AuthenticatedRequest<
{ path: string },
{},
{},
{
mode: 'view' | 'download';
fileName?: string;
mimeType?: string;
}
>;

View file

@ -237,7 +237,12 @@ export interface IRestApi {
deleteExecutions(sendData: IExecutionDeleteFilter): Promise<void>; deleteExecutions(sendData: IExecutionDeleteFilter): Promise<void>;
retryExecution(id: string, loadWorkflow?: boolean): Promise<boolean>; retryExecution(id: string, loadWorkflow?: boolean): Promise<boolean>;
getTimezones(): Promise<IDataObject>; getTimezones(): Promise<IDataObject>;
getBinaryUrl(dataPath: string, mode: 'view' | 'download'): string; getBinaryUrl(
dataPath: string,
mode: 'view' | 'download',
fileName?: string,
mimeType?: string,
): string;
getExecutionEvents(id: string): Promise<IAbstractEventMessage[]>; getExecutionEvents(id: string): Promise<IAbstractEventMessage[]>;
} }

View file

@ -45,18 +45,18 @@ export default mixins(restApi).extend({
}; };
}, },
async mounted() { async mounted() {
const id = this.binaryData?.id; const { id, data, fileName, fileType, mimeType } = (this.binaryData || {}) as IBinaryData;
const isJSONData = this.binaryData.fileType === 'json'; const isJSONData = fileType === 'json';
if (!id) { if (!id) {
if (isJSONData) { if (isJSONData) {
this.jsonData = jsonParse(atob(this.binaryData.data)); this.jsonData = jsonParse(atob(data));
} else { } else {
this.embedSource = 'data:' + this.binaryData.mimeType + ';base64,' + this.binaryData.data; this.embedSource = 'data:' + mimeType + ';base64,' + data;
} }
} else { } else {
try { try {
const binaryUrl = this.restApi().getBinaryUrl(id, 'view'); const binaryUrl = this.restApi().getBinaryUrl(id, 'view', fileName, mimeType);
if (isJSONData) { if (isJSONData) {
this.jsonData = await (await fetch(binaryUrl)).json(); this.jsonData = await (await fetch(binaryUrl)).json();
} else { } else {

View file

@ -1206,7 +1206,7 @@ export default mixins(externalHooks, genericHelpers, nodeHelpers, pinData).exten
const { id, data, fileName, fileExtension, mimeType } = this.binaryData[index][key]; const { id, data, fileName, fileExtension, mimeType } = this.binaryData[index][key];
if (id) { if (id) {
const url = this.restApi().getBinaryUrl(id, 'download'); const url = this.restApi().getBinaryUrl(id, 'download', fileName, mimeType);
saveAs(url, [fileName, fileExtension].join('.')); saveAs(url, [fileName, fileExtension].join('.'));
return; return;
} else { } else {

View file

@ -202,8 +202,15 @@ export const restApi = Vue.extend({
}, },
// Binary data // Binary data
getBinaryUrl: (dataPath, mode): string => getBinaryUrl: (dataPath, mode, fileName, mimeType): string => {
self.rootStore.getRestApiContext.baseUrl + `/data/${dataPath}?mode=${mode}`, let restUrl = self.rootStore.getRestUrl;
if (restUrl.startsWith('/')) restUrl = window.location.origin + restUrl;
const url = new URL(`${restUrl}/data/${dataPath}`);
url.searchParams.append('mode', mode);
if (fileName) url.searchParams.append('fileName', fileName);
if (mimeType) url.searchParams.append('mimeType', mimeType);
return url.toString();
},
// Returns all the available timezones // Returns all the available timezones
getExecutionEvents: (id: string): Promise<IAbstractEventMessage[]> => { getExecutionEvents: (id: string): Promise<IAbstractEventMessage[]> => {