Files
cnpmcore/app/common/UserUtil.ts
fengmk2 4427a4fca5 feat: use egg v4 (#747)
BREAKING CHANGE: only support egg >= 4.0.0

the first app on egg v4

https://github.com/eggjs/egg/issues/3644
2025-02-09 15:43:24 +08:00

57 lines
1.6 KiB
TypeScript

import crypto from 'node:crypto';
import base from 'base-x';
import { crc32 } from '@node-rs/crc32';
import * as ssri from 'ssri';
import UAParser from 'ua-parser-js';
const base62 = base('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');
const crc32Buffer = Buffer.alloc(4);
export function randomToken(prefix: string): string {
const bytes = crypto.randomBytes(24);
const crc = crc32(bytes);
crc32Buffer.writeUInt32BE(crc);
return `${prefix}_${base62.encode(bytes)}_${base62.encode(crc32Buffer)}`;
}
export function checkToken(token: string, prefix: string): boolean {
const splits = token.split('_');
if (splits.length !== 3) return false;
if (splits[0] !== prefix) return false;
try {
const bytes = base62.decode(splits[1]);
const crcBytes = base62.decode(splits[2]);
return crcBytes.readUInt32BE(0) === crc32(bytes);
} catch {
return false;
}
}
export function integrity(plain: string): string {
return ssri.create().update(plain).digest()
.toString();
}
export function checkIntegrity(plain: string, expectedIntegrity: string): boolean {
return !!ssri.checkData(plain, expectedIntegrity);
}
export function sha512(plain: string): string {
return crypto.createHash('sha512').update(plain).digest('hex');
}
export function getUAInfo(userAgent?: string) {
if (!userAgent) return null;
return new UAParser(userAgent);
}
export function getBrowserTypeForWebauthn(userAgent?: string) {
const ua = getUAInfo(userAgent);
if (!ua) return null;
const os = ua.getOS();
if (os.name === 'iOS' || os.name === 'Android') return 'mobile';
if (os.name === 'Mac OS') return ua.getBrowser().name;
return null;
}