Files
vue-driven-cloud-storage/backend/utils/share.js

55 lines
1.6 KiB
JavaScript

const { normalizeVirtualPath } = require('./path-safety');
const SHARE_CODE_PATTERN = /^[A-Za-z0-9]{6,32}$/;
function isValidShareCode(code) {
return typeof code === 'string' && SHARE_CODE_PATTERN.test(code);
}
function isPathWithinShare(requestPath, share) {
if (!requestPath || !share) return false;
const normalizedRequest = normalizeVirtualPath(requestPath);
const normalizedShare = normalizeVirtualPath(share.share_path);
if (!normalizedRequest || !normalizedShare) return false;
if (share.share_type === 'file') return normalizedRequest === normalizedShare;
const sharePrefix = normalizedShare.endsWith('/') ? normalizedShare : `${normalizedShare}/`;
return normalizedRequest === normalizedShare || normalizedRequest.startsWith(sharePrefix);
}
function parseShareIpWhitelist(rawValue) {
if (typeof rawValue !== 'string') return [];
return rawValue
.split(/[\s,;]+/)
.map((item) => item.trim())
.filter(Boolean)
.slice(0, 100);
}
function isShareIpAllowed(clientIp, whitelist = []) {
if (!Array.isArray(whitelist) || whitelist.length === 0) return true;
if (!clientIp) return false;
for (const rule of whitelist) {
const normalizedRule = String(rule || '').trim();
if (!normalizedRule) continue;
if (normalizedRule === clientIp) return true;
if (normalizedRule.endsWith('*')) {
const prefix = normalizedRule.slice(0, -1);
if (prefix && clientIp.startsWith(prefix)) return true;
}
}
return false;
}
module.exports = {
isPathWithinShare,
isShareIpAllowed,
isValidShareCode,
parseShareIpWhitelist
};