This commit is contained in:
“xHuPo” 2025-06-17 14:44:48 +08:00
parent 17a02ea47e
commit 70e7a113e6
22 changed files with 967 additions and 285 deletions

View file

@ -222,14 +222,17 @@ Page({
// 为每个token计算正确的时间戳
const updatePromises = tokensToUpdate.map(token => {
// 优先使用令牌中的时间戳(如果有的话)
const tokenTimestamp = token.timestamp || currentTimestamp;
if (token.type === 'totp') {
// 计算时间窗口的开始时间
const period = token.period || 30;
const windowStart = Math.floor(currentTimestamp / period) * period;
const windowStart = Math.floor(tokenTimestamp / period) * period;
return this.updateTokenCode(token, windowStart);
} else {
// 对于HOTP类型直接使用当前时间戳
return this.updateTokenCode(token, currentTimestamp);
// 对于HOTP类型直接使用时间戳
return this.updateTokenCode(token, tokenTimestamp);
}
});
@ -263,14 +266,17 @@ Page({
// 并行更新所有令牌的验证码,为每个令牌计算其时间窗口的开始时间
const updatePromises = tokens.map(token => {
// 优先使用令牌中的时间戳(如果有的话)
const tokenTimestamp = token.timestamp || currentTimestamp;
if (token.type === 'totp') {
// 计算时间窗口的开始时间
const period = token.period || 30;
const windowStart = Math.floor(currentTimestamp / period) * period;
const windowStart = Math.floor(tokenTimestamp / period) * period;
return this.updateTokenCode(token, windowStart);
} else {
// 对于HOTP类型直接使用当前时间戳
return this.updateTokenCode(token, currentTimestamp);
// 对于HOTP类型直接使用时间戳
return this.updateTokenCode(token, tokenTimestamp);
}
});
@ -426,73 +432,33 @@ Page({
try {
// 解析二维码内容
const qrContent = res.result;
// 如果是otpauth://格式的URL
if (qrContent.startsWith('otpauth://')) {
// 小程序兼容的URL解析
const [protocolAndPath, search] = qrContent.split('?');
const [protocol, path] = protocolAndPath.split('://');
const type = protocol.replace('otpauth:', '');
// 解析路径部分
const decodedPath = decodeURIComponent(path.substring(1)); // 移除开头的/
let [issuer, remark] = decodedPath.split(':');
if (!remark) {
remark = issuer;
issuer = '';
}
// 解析查询参数
const params = {};
if (search) {
search.split('&').forEach(pair => {
const [key, value] = pair.split('=');
if (key && value) {
params[key] = decodeURIComponent(value);
}
});
}
// 从参数中获取issuer如果存在
if (params.issuer) {
issuer = params.issuer;
}
// 验证secret参数
if (!params.secret) {
wx.showToast({
title: '无效的二维码缺少secret参数',
icon: 'none',
duration: 2000
});
return;
}
// 将otpauth类型转换为实际类型
let validType = type.toLowerCase();
if (validType === 'otpauth') {
// 从URI路径中提取实际类型
validType = path.split('/')[0].toLowerCase();
}
// 构建表单数据,确保数字类型参数正确转换
// 导入util.js中的parseURL函数
const { parseURL } = require('../../utils/util');
// 使用parseURL函数解析二维码内容
const parsedToken = parseURL(qrContent);
if (parsedToken) {
// 构建表单数据
const formData = {
type: validType,
issuer,
remark,
secret: params.secret,
algorithm: params.algorithm || 'SHA1',
digits: params.digits ? parseInt(params.digits, 10) : 6,
period: validType === 'totp' ? (params.period ? parseInt(params.period, 10) : 30) : undefined,
counter: validType === 'hotp' ? (params.counter ? parseInt(params.counter, 10) : 0) : undefined
type: parsedToken.type,
issuer: parsedToken.issuer || '',
account: parsedToken.account || '',
secret: parsedToken.secret || '',
algorithm: parsedToken.algorithm || 'SHA1',
digits: parsedToken.digits || 6,
period: parsedToken.type === 'totp' ? (parsedToken.period || 30) : undefined,
counter: parsedToken.type === 'hotp' ? (parsedToken.counter || 0) : undefined
};
// 验证必要参数
if (formData.digits < 6 || formData.digits > 8) {
formData.digits = 6;
console.warn('验证码位数无效已设置为默认值6');
}
if (validType === 'totp' && (formData.period < 15 || formData.period > 60)) {
if (formData.type === 'totp' && (formData.period < 15 || formData.period > 60)) {
formData.period = 30;
console.warn('TOTP周期无效已设置为默认值30秒');
}
@ -640,14 +606,22 @@ Page({
// 获取当前令牌列表
const tokens = await wx.getStorageSync('tokens') || [];
// 生成唯一ID和时间戳
// 生成唯一ID和时间戳
const newToken = {
...tokenData,
id: Date.now().toString(),
createdAt: new Date().toISOString(),
lastUpdate: new Date().toISOString()
createTime: formatTime(new Date()),
lastUpdate: formatTime(new Date()),
code: '' // 初始化为空字符串
};
// 对于HOTP类型添加counter字段
if (tokenData.type && tokenData.type.toUpperCase() === 'HOTP') {
newToken.counter = 0; // HOTP类型需要counter >= 0
}
// 对于TOTP类型不设置counter字段让它在JSON序列化时被忽略
// 如果是TOTP类型先初始化剩余时间
if ((newToken.type || 'totp').toLowerCase() === 'totp') {
const period = parseInt(newToken.period || '30', 10);