/** * 条码/二维码内容编码工具(Base64Url) * * 设计: * - 生成端用 Base64Url 对原文编码,并加 `~` 前缀标识; * - 扫码端识别前缀后 Base64Url 解码还原原文; * - 无前缀的历史/明文码直接透传,保证向后兼容; * - 仅防止肉眼直接读取,不是真正的加密。 */ const ENCODE_PREFIX = '~'; function toBase64Url(str) { const b64 = btoa(unescape(encodeURIComponent(str))); return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); } function fromBase64Url(str) { let b64 = str.replace(/-/g, '+').replace(/_/g, '/'); while (b64.length % 4) b64 += '='; return decodeURIComponent(escape(atob(b64))); } /** * 编码原文:输出 `~` + Base64Url(原文)。 * @param {string} plain * @returns {string} */ export function encryptCode(plain) { if (plain == null || plain === '') return ''; try { return ENCODE_PREFIX + toBase64Url(String(plain)); } catch (e) { console.error('encryptCode failed:', e); return String(plain); } } /** * 解码扫码内容: * - 以 `~` 开头:Base64Url 解码还原原文;失败时回退原值; * - 不以 `~` 开头:视为明文,直接返回(兼容历史码)。 * @param {string} code * @returns {string} */ export function decryptCode(code) { if (code == null || code === '') return ''; const str = String(code).trim(); if (!str.startsWith(ENCODE_PREFIX)) return str; try { return fromBase64Url(str.slice(ENCODE_PREFIX.length)); } catch (e) { console.error('decryptCode failed:', e, code); return str; } } export default { encryptCode, decryptCode };