feat: improve application access and money precision
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
import { isIP } from 'node:net';
|
||||
|
||||
export function isIpAllowed(remoteIp: string, allowlist: string[]) {
|
||||
const normalizedRemoteIp = normalizeIp(remoteIp);
|
||||
if (allowlist.length === 0) return true;
|
||||
return allowlist.some((rule) => ipMatchesRule(normalizedRemoteIp, rule));
|
||||
}
|
||||
|
||||
function ipMatchesRule(remoteIp: string, rule: string) {
|
||||
const normalizedRule = normalizeIp(rule.trim());
|
||||
if (!normalizedRule) return false;
|
||||
if (!normalizedRule.includes('/')) return remoteIp === normalizedRule;
|
||||
const [network, prefixText] = normalizedRule.split('/');
|
||||
const prefix = Number(prefixText);
|
||||
if (!Number.isInteger(prefix) || prefix < 0 || prefix > 32 || isIP(remoteIp) !== 4 || isIP(network) !== 4) return false;
|
||||
const mask = prefix === 0 ? 0 : (0xffffffff << (32 - prefix)) >>> 0;
|
||||
return (ipv4ToInt(remoteIp) & mask) === (ipv4ToInt(network) & mask);
|
||||
}
|
||||
|
||||
function normalizeIp(value: string) {
|
||||
return value.replace(/^::ffff:/, '').trim();
|
||||
}
|
||||
|
||||
function ipv4ToInt(value: string) {
|
||||
return value.split('.').reduce((result, part) => ((result << 8) + Number(part)) >>> 0, 0);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
|
||||
export const MONEY_UNITS_PER_YUAN = 10_000;
|
||||
|
||||
export function moneyToNumber(value: number | bigint | null | undefined) {
|
||||
if (value === null || value === undefined) return 0;
|
||||
const result = typeof value === 'bigint' ? Number(value) : value;
|
||||
if (!Number.isSafeInteger(result)) {
|
||||
throw new RangeError('金额超过 JavaScript 安全整数范围');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function moneyUnitsToYuan(value: number | bigint | null | undefined) {
|
||||
return moneyToNumber(value) / MONEY_UNITS_PER_YUAN;
|
||||
}
|
||||
|
||||
export function moneyUnitsToFixedYuan(value: number | bigint | null | undefined) {
|
||||
return moneyUnitsToYuan(value).toFixed(4);
|
||||
}
|
||||
|
||||
export function assertMoneyUnits(
|
||||
value: number,
|
||||
label: string,
|
||||
options: { allowNegative?: boolean; allowZero?: boolean } = {},
|
||||
) {
|
||||
if (!Number.isSafeInteger(value)) {
|
||||
throw new BadRequestException(`${label}最多支持人民币小数点后 4 位,且不能超过安全金额范围`);
|
||||
}
|
||||
if (!options.allowNegative && value < 0) {
|
||||
throw new BadRequestException(`${label}不能为负数`);
|
||||
}
|
||||
if (options.allowZero === false && value === 0) {
|
||||
throw new BadRequestException(`${label}不能为 0`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user