fix: encode url (#6497)

This commit is contained in:
chenos 2025-03-18 21:18:43 +08:00 committed by GitHub
parent 8f8ee69aec
commit 00cd51c14e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 50 additions and 6 deletions

View File

@ -12,7 +12,7 @@ import { isURL, Registry } from '@nocobase/utils';
import { basename } from 'path'; import { basename } from 'path';
import { Model, Transactionable } from '@nocobase/database'; import { Collection, Model, Transactionable } from '@nocobase/database';
import fs from 'fs'; import fs from 'fs';
import { STORAGE_TYPE_ALI_OSS, STORAGE_TYPE_LOCAL, STORAGE_TYPE_S3, STORAGE_TYPE_TX_COS } from '../constants'; import { STORAGE_TYPE_ALI_OSS, STORAGE_TYPE_LOCAL, STORAGE_TYPE_S3, STORAGE_TYPE_TX_COS } from '../constants';
import initActions from './actions'; import initActions from './actions';
@ -23,6 +23,7 @@ import StorageTypeAliOss from './storages/ali-oss';
import StorageTypeLocal from './storages/local'; import StorageTypeLocal from './storages/local';
import StorageTypeS3 from './storages/s3'; import StorageTypeS3 from './storages/s3';
import StorageTypeTxCos from './storages/tx-cos'; import StorageTypeTxCos from './storages/tx-cos';
import { encodeURL } from './utils';
export type * from './storages'; export type * from './storages';
@ -205,6 +206,20 @@ export class PluginFileManagerServer extends Plugin {
options.model = 'FileModel'; options.model = 'FileModel';
} }
}); });
this.db.on('afterDefineCollection', (collection: Collection) => {
if (collection.options.template !== 'file') {
return;
}
collection.model.beforeUpdate((model) => {
if (!model.changed('url') || !model.changed('preview')) {
return;
}
model.set('url', model.previous('url'));
model.set('preview', model.previous('preview'));
model.changed('url', false);
model.changed('preview', false);
});
});
this.app.on('afterStart', async () => { this.app.on('afterStart', async () => {
await this.loadStorages(); await this.loadStorages();
}); });
@ -301,11 +316,11 @@ export class PluginFileManagerServer extends Plugin {
async getFileURL(file: AttachmentModel, preview = false) { async getFileURL(file: AttachmentModel, preview = false) {
if (!file.storageId) { if (!file.storageId) {
return file.url; return encodeURL(file.url);
} }
const storage = this.storagesCache.get(file.storageId); const storage = this.storagesCache.get(file.storageId);
if (!storage) { if (!storage) {
return file.url; return encodeURL(file.url);
} }
const storageType = this.storageTypes.get(storage.type); const storageType = this.storageTypes.get(storage.type);
return new storageType(storage).getFileURL(file, preview ? storage.options.thumbnailRule : ''); return new storageType(storage).getFileURL(file, preview ? storage.options.thumbnailRule : '');

View File

@ -10,6 +10,7 @@
import { isURL } from '@nocobase/utils'; import { isURL } from '@nocobase/utils';
import { StorageEngine } from 'multer'; import { StorageEngine } from 'multer';
import urlJoin from 'url-join'; import urlJoin from 'url-join';
import { encodeURL } from '../utils';
export interface StorageModel { export interface StorageModel {
id?: number; id?: number;
@ -46,9 +47,9 @@ export abstract class StorageType {
// 兼容历史数据 // 兼容历史数据
if (file.url && isURL(file.url)) { if (file.url && isURL(file.url)) {
if (preview) { if (preview) {
return file.url + (this.storage.options.thumbnailRule || ''); return encodeURL(file.url) + (this.storage.options.thumbnailRule || '');
} }
return file.url; return encodeURL(file.url);
} }
const keys = [ const keys = [
this.storage.baseUrl, this.storage.baseUrl,

View File

@ -7,8 +7,8 @@
* For more information, please refer to: https://www.nocobase.com/agreement. * For more information, please refer to: https://www.nocobase.com/agreement.
*/ */
import path from 'path';
import { uid } from '@nocobase/utils'; import { uid } from '@nocobase/utils';
import path from 'path';
export function getFilename(req, file, cb) { export function getFilename(req, file, cb) {
const originalname = Buffer.from(file.originalname, 'binary').toString('utf8'); const originalname = Buffer.from(file.originalname, 'binary').toString('utf8');
@ -29,3 +29,31 @@ export const cloudFilenameGetter = (storage) => (req, file, cb) => {
export function getFileKey(record) { export function getFileKey(record) {
return [record.path.replace(/^\/|\/$/g, ''), record.filename].filter(Boolean).join('/'); return [record.path.replace(/^\/|\/$/g, ''), record.filename].filter(Boolean).join('/');
} }
function ensureUrlEncoded(value) {
try {
// 如果解码后与原字符串不同,说明已经被转义过
if (decodeURIComponent(value) !== value) {
return value; // 已经是转义的,直接返回
}
} catch (e) {
// 如果解码出错,说明是非法的编码,直接转义
return encodeURIComponent(value);
}
// 如果没问题但字符串未转义过,则进行转义
return encodeURIComponent(value);
}
function encodePathKeepSlash(path) {
return path
.split('/')
.map((segment) => ensureUrlEncoded(segment))
.join('/');
}
export function encodeURL(url) {
const parsedUrl = new URL(url);
parsedUrl.pathname = encodePathKeepSlash(parsedUrl.pathname);
return parsedUrl.toString();
}