105 lines
2.9 KiB
TypeScript
105 lines
2.9 KiB
TypeScript
import type { Upload } from './Upload';
|
||
|
||
// 定义ASCII码中的空格和逗号字符的码点
|
||
const ASCII_SPACE = ' '.codePointAt(0);
|
||
const ASCII_COMMA = ','.codePointAt(0);
|
||
// 定义用于验证Base64字符串的正则表达式
|
||
const BASE64_REGEX = /^[\d+/A-Za-z]*={0,2}$/;
|
||
|
||
/**
|
||
* 验证元数据键的有效性
|
||
* @param key 需要验证的键
|
||
* @returns 如果键有效则返回true,否则返回false
|
||
*/
|
||
export function validateKey(key: string) {
|
||
// 如果键的长度为0,则无效
|
||
if (key.length === 0) {
|
||
return false;
|
||
}
|
||
|
||
// 遍历键的每个字符,检查其码点是否在有效范围内
|
||
for (let i = 0; i < key.length; ++i) {
|
||
const charCodePoint = key.codePointAt(i) as number;
|
||
if (
|
||
charCodePoint > 127 || // 非ASCII字符
|
||
charCodePoint === ASCII_SPACE || // 空格字符
|
||
charCodePoint === ASCII_COMMA // 逗号字符
|
||
) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 验证元数据值的有效性
|
||
* @param value 需要验证的值
|
||
* @returns 如果值是有效的Base64字符串则返回true,否则返回false
|
||
*/
|
||
export function validateValue(value: string) {
|
||
// Base64字符串的长度必须是4的倍数
|
||
if (value.length % 4 !== 0) {
|
||
return false;
|
||
}
|
||
|
||
// 使用正则表达式验证Base64字符串的格式
|
||
return BASE64_REGEX.test(value);
|
||
}
|
||
|
||
/**
|
||
* 解析元数据字符串
|
||
* @param str 需要解析的元数据字符串
|
||
* @returns 返回解析后的元数据对象
|
||
* @throws 如果元数据字符串无效则抛出错误
|
||
*/
|
||
export function parse(str?: string) {
|
||
const meta: Record<string, string | null> = {};
|
||
|
||
// 如果字符串为空或仅包含空白字符,则无效
|
||
if (!str || str.trim().length === 0) {
|
||
throw new Error('Metadata string is not valid');
|
||
}
|
||
|
||
// 遍历字符串中的每个键值对
|
||
for (const pair of str.split(',')) {
|
||
const tokens = pair.split(' ');
|
||
const [key, value] = tokens;
|
||
// 验证键和值的有效性,并确保键在元数据对象中不存在
|
||
if (
|
||
key &&
|
||
((tokens.length === 1 && validateKey(key)) ||
|
||
(tokens.length === 2 && validateKey(key) && value && validateValue(value))) &&
|
||
!(key in meta)
|
||
) {
|
||
// 如果值存在,则将其从Base64解码为UTF-8字符串
|
||
const decodedValue = value ? Buffer.from(value, 'base64').toString('utf8') : null;
|
||
meta[key] = decodedValue;
|
||
} else {
|
||
throw new Error('Metadata string is not valid');
|
||
}
|
||
}
|
||
|
||
return meta;
|
||
}
|
||
|
||
/**
|
||
* 将元数据对象序列化为字符串
|
||
* @param metadata 需要序列化的元数据对象
|
||
* @returns 返回序列化后的元数据字符串
|
||
*/
|
||
export function stringify(metadata: NonNullable<Upload['metadata']>): string {
|
||
return Object.entries(metadata)
|
||
.map(([key, value]) => {
|
||
// 如果值为null,则仅返回键
|
||
if (value === null) {
|
||
return key;
|
||
}
|
||
|
||
// 将值编码为Base64字符串,并与键组合
|
||
const encodedValue = Buffer.from(value, 'utf8').toString('base64');
|
||
return `${key} ${encodedValue}`;
|
||
})
|
||
.join(',');
|
||
}
|