v0.5.4: 全面修复 — template literal URL, Cookie验证, 用户默认is_active, 默认账号路由, 空间信息, 密钥清理, promoForm修复
修复:
- quark-share.ts/storage.ts: 9处template literal ${}缺失导致fetch URL写死
- user/routes.ts: testCloudConnectionWithCookie缺await + 按cloudType分发驱动
- credential.service.ts: INSERT缺?参数 (9values/10cols)
- user/routes.ts: 用户新增网盘默认is_active=0
- admin.routes.ts: 新增PUT /admin/cloud-configs/:id/primary路由
- database.ts: is_primary列迁移
- UserDashboard.vue: 保存时传递storage_used/storage_total
- SystemConfig.vue: promoForm const重赋值bug
- config/index.ts: 移除泄露的默认密钥token
This commit is contained in:
@@ -131,6 +131,7 @@ export function saveCloudConfig(data: {
|
||||
cookie = COALESCE(?, cookie),
|
||||
nickname = COALESCE(?, nickname),
|
||||
cookie_uid = COALESCE(?, cookie_uid),
|
||||
cloud_type_uid = COALESCE(?, cloud_type_uid),
|
||||
promotion_account = COALESCE(?, promotion_account),
|
||||
is_active = COALESCE(?, is_active),
|
||||
storage_used = COALESCE(?, storage_used),
|
||||
@@ -138,7 +139,7 @@ export function saveCloudConfig(data: {
|
||||
consecutive_failures = 0,
|
||||
updated_at = ?
|
||||
WHERE id = ?`
|
||||
).run(data.cloud_type, encryptedCookie, data.nickname || null, cookieUidForUpdate || null, data.promotion_account || null, data.is_active ?? 1, data.storage_used || null, data.storage_total || null, localTimestamp(), data.id);
|
||||
).run(data.cloud_type, encryptedCookie, data.nickname || null, cookieUidForUpdate || null, cookieUidForUpdate || null, data.promotion_account || null, data.is_active ?? 1, data.storage_used || null, data.storage_total || null, localTimestamp(), data.id);
|
||||
} else {
|
||||
const existing = db.prepare(
|
||||
'SELECT id, nickname FROM cloud_configs WHERE cloud_type = ? AND is_active = 1 LIMIT 1'
|
||||
@@ -149,6 +150,7 @@ export function saveCloudConfig(data: {
|
||||
cookie = COALESCE(?, cookie),
|
||||
nickname = COALESCE(?, nickname),
|
||||
cookie_uid = COALESCE(?, cookie_uid),
|
||||
cloud_type_uid = COALESCE(?, cloud_type_uid),
|
||||
promotion_account = COALESCE(?, promotion_account),
|
||||
is_active = COALESCE(?, is_active),
|
||||
storage_used = COALESCE(?, storage_used),
|
||||
@@ -156,11 +158,11 @@ export function saveCloudConfig(data: {
|
||||
consecutive_failures = 0,
|
||||
updated_at = ?
|
||||
WHERE id = ?`
|
||||
).run(encryptedCookie, data.nickname || null, cookieUidForUpdate || null, data.promotion_account || null, data.is_active ?? 1, data.storage_used || null, data.storage_total || null, localTimestamp(), existing.id);
|
||||
).run(encryptedCookie, data.nickname || null, cookieUidForUpdate || null, cookieUidForUpdate || null, data.promotion_account || null, data.is_active ?? 1, data.storage_used || null, data.storage_total || null, localTimestamp(), existing.id);
|
||||
} else {
|
||||
db.prepare(
|
||||
'INSERT INTO cloud_configs (cloud_type, cookie, nickname, cookie_uid, promotion_account, is_active, storage_used, storage_total, consecutive_failures) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0)'
|
||||
).run(data.cloud_type, encryptedCookie, data.nickname || null, cookieUidForUpdate || null, data.promotion_account || null, data.is_active ?? 1, data.storage_used || null, data.storage_total || null);
|
||||
'INSERT INTO cloud_configs (cloud_type, cookie, nickname, cookie_uid, cloud_type_uid, promotion_account, is_active, storage_used, storage_total, consecutive_failures) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 0)'
|
||||
).run(data.cloud_type, encryptedCookie, data.nickname || null, cookieUidForUpdate || null, cookieUidForUpdate || null, data.promotion_account || null, data.is_active ?? 1, data.storage_used || null, data.storage_total || null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,8 +268,8 @@ export async function testCloudConnection(id: number): Promise<{
|
||||
|
||||
const cookieUid = extractCookieUid(cookie);
|
||||
db.prepare(
|
||||
`UPDATE cloud_configs SET nickname = ?, storage_total = ?, storage_used = ?, cookie_uid = ?, is_active = 1, verification_status = 'valid', updated_at = ? WHERE id = ?`
|
||||
).run(nickname, storageTotal, storageUsed, cookieUid, localTimestamp(), id);
|
||||
`UPDATE cloud_configs SET nickname = ?, storage_total = ?, storage_used = ?, cookie_uid = ?, cloud_type_uid = ?, is_active = 1, verification_status = 'valid', updated_at = ? WHERE id = ?`
|
||||
).run(nickname, storageTotal, storageUsed, cookieUid, cookieUid, localTimestamp(), id);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
@@ -295,21 +297,54 @@ export async function testCloudConnectionWithCookie(cloudType: string, cookie: s
|
||||
storage_total?: string;
|
||||
}> {
|
||||
try {
|
||||
const { QuarkDriver } = require('./drivers/quark.driver');
|
||||
const driver = new QuarkDriver({ cookie, nickname: '' });
|
||||
const valid = await driver.validate();
|
||||
if (!valid) {
|
||||
return { success: false, message: '连接失败:Cookie 无效或已过期' };
|
||||
if (cloudType === 'quark') {
|
||||
const { QuarkDriver } = require('./drivers/quark.driver');
|
||||
const driver = new QuarkDriver({ cookie, nickname: '' });
|
||||
const valid = await driver.validate();
|
||||
if (!valid) {
|
||||
return { success: false, message: '连接失败:Cookie 无效或已过期' };
|
||||
}
|
||||
const nickname = (await fetchQuarkNickname(cookie)) || '夸克网盘';
|
||||
const storage = await driver.getStorageInfo();
|
||||
return {
|
||||
success: true,
|
||||
message: '连接成功',
|
||||
nickname,
|
||||
storage_used: storage.used,
|
||||
storage_total: storage.total,
|
||||
};
|
||||
} else if (cloudType === 'baidu') {
|
||||
const { BaiduDriver } = require('./drivers/baidu.driver');
|
||||
const driver = new BaiduDriver({ cookie, nickname: '' });
|
||||
const valid = await driver.validate();
|
||||
if (!valid) {
|
||||
return { success: false, message: '连接失败:Cookie 无效或已过期(需包含 BDUSS)' };
|
||||
}
|
||||
const info = await driver.getUserInfo();
|
||||
const storage = await driver.getStorageInfo();
|
||||
return {
|
||||
success: true,
|
||||
message: '连接成功',
|
||||
nickname: info?.nickname || '百度网盘',
|
||||
storage_used: storage.used,
|
||||
storage_total: storage.total,
|
||||
};
|
||||
} else if (cloudType === 'aliyun') {
|
||||
const { AliyunDriver } = require('./drivers/aliyun.driver');
|
||||
const driver = new AliyunDriver({ cookie, nickname: '' });
|
||||
const nickname = await driver.getNickname();
|
||||
return {
|
||||
success: true,
|
||||
message: nickname ? '连接成功' : '连接成功(无法获取昵称)',
|
||||
nickname: nickname || '阿里云盘',
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
success: true,
|
||||
message: 'Cookie 已保存(该网盘类型暂不支持连接测试)',
|
||||
nickname: cloudType,
|
||||
};
|
||||
}
|
||||
const nickname = (await fetchQuarkNickname(cookie)) || cloudType;
|
||||
const storage = await driver.getStorageInfo();
|
||||
return {
|
||||
success: true,
|
||||
message: '连接成功',
|
||||
nickname,
|
||||
storage_used: storage.used,
|
||||
storage_total: storage.total,
|
||||
};
|
||||
} catch (err: any) {
|
||||
return { success: false, message: `连接失败:${err.message || '未知错误'}` };
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ export async function acquireStoken(cookie, pwdId) {
|
||||
for (let attempt = 0; attempt < 3; attempt++) {
|
||||
try {
|
||||
const params = new URLSearchParams(q.getCommonParams());
|
||||
const resp = await fetch(`q.QUARK_DRIVE_HOST + q.EP.SHARE_PAGE_TOKEN?${params.toString()}`, {
|
||||
const resp = await fetch(`${q.QUARK_DRIVE_HOST}${q.EP.SHARE_PAGE_TOKEN}?${params.toString()}`, {
|
||||
method: 'POST',
|
||||
headers: { ...q.getHeaders(cookie), 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ pwd_id: pwdId, passcode: '' }),
|
||||
@@ -57,7 +57,7 @@ export async function getDetailAt(cookie, pwdId, stoken, pdirFid) {
|
||||
ver: '2',
|
||||
fetch_share_full_path: '0',
|
||||
});
|
||||
const resp = await fetch(`q.QUARK_DRIVE_HOST + q.EP.SHARE_PAGE_DETAIL?${params.toString()}`, { headers: q.getHeaders(cookie), signal: AbortSignal.timeout(15000) });
|
||||
const resp = await fetch(`${q.QUARK_DRIVE_HOST}${q.EP.SHARE_PAGE_DETAIL}?${params.toString()}`, { headers: q.getHeaders(cookie), signal: AbortSignal.timeout(15000) });
|
||||
if (!resp.ok)
|
||||
return [];
|
||||
const data = await resp.json();
|
||||
@@ -107,7 +107,7 @@ export async function getShareFiles(cookie, pwdId, stoken) {
|
||||
*/
|
||||
export async function saveFiles(cookie, pwdId, stoken, fids, fidTokens, toPdirFid) {
|
||||
try {
|
||||
const resp = await fetch(`q.QUARK_DRIVE_HOST + q.EP.SHARE_PAGE_SAVE?${q.makeQuery()}`, {
|
||||
const resp = await fetch(`${q.QUARK_DRIVE_HOST}${q.EP.SHARE_PAGE_SAVE}?${q.makeQuery()}`, {
|
||||
method: 'POST',
|
||||
headers: { ...q.getHeaders(cookie), 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -154,7 +154,7 @@ export async function waitForTask(cookie, taskId, timeoutMs) {
|
||||
__dt: String(Math.floor(Math.random() * 240000 + 60000)),
|
||||
__t: String(Date.now() / 1000),
|
||||
});
|
||||
const resp = await fetch(`q.QUARK_DRIVE_HOST + q.EP.TASK?${params.toString()}`, { headers: q.getHeaders(cookie), signal: AbortSignal.timeout(10000) });
|
||||
const resp = await fetch(`${q.QUARK_DRIVE_HOST}${q.EP.TASK}?${params.toString()}`, { headers: q.getHeaders(cookie), signal: AbortSignal.timeout(10000) });
|
||||
const data = await resp.json();
|
||||
if (data.status === 200) {
|
||||
if (data.data?.status === 2) {
|
||||
@@ -179,7 +179,7 @@ export async function waitForTask(cookie, taskId, timeoutMs) {
|
||||
*/
|
||||
export async function renameFile(cookie, fid, newName) {
|
||||
try {
|
||||
const resp = await fetch(`q.QUARK_DRIVE_HOST + q.EP.FILE_RENAME?${q.makeQuery()}`, {
|
||||
const resp = await fetch(`${q.QUARK_DRIVE_HOST}${q.EP.FILE_RENAME}?${q.makeQuery()}`, {
|
||||
method: 'POST',
|
||||
headers: { ...q.getHeaders(cookie), 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ fid, file_name: newName }),
|
||||
@@ -206,7 +206,7 @@ export async function createShareLink(cookie, fileId) {
|
||||
for (const st of shareTypes) {
|
||||
await q.humanDelay();
|
||||
// Step 1: Create share task - get task_id
|
||||
const response = await fetch(`q.QUARK_DRIVE_HOST + q.EP.SHARE + "?"${q.makeQuery()}`, {
|
||||
const response = await fetch(`${q.QUARK_DRIVE_HOST}${q.EP.SHARE}?${q.makeQuery()}`, {
|
||||
method: 'POST',
|
||||
headers: { ...q.getHeaders(cookie), 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -255,7 +255,7 @@ export async function createShareLink(cookie, fileId) {
|
||||
*/
|
||||
async function submitShare(cookie, shareId, sharePwd) {
|
||||
try {
|
||||
const response = await fetch(`q.QUARK_DRIVE_HOST + q.EP.SHARE_PASSWORD?${q.makeQuery()}`, {
|
||||
const response = await fetch(`${q.QUARK_DRIVE_HOST}${q.EP.SHARE_PASSWORD}?${q.makeQuery()}`, {
|
||||
method: 'POST',
|
||||
headers: { ...q.getHeaders(cookie), 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ share_id: shareId, share_pwd: sharePwd || '' }),
|
||||
@@ -291,7 +291,7 @@ async function waitForShareTask(cookie, taskId, timeoutMs) {
|
||||
__dt: String(Math.floor(Math.random() * 240000 + 60000)),
|
||||
__t: String(Date.now() / 1000),
|
||||
});
|
||||
const resp = await fetch(`q.QUARK_DRIVE_HOST + q.EP.TASK?${params.toString()}`, { headers: q.getHeaders(cookie), signal: AbortSignal.timeout(10000) });
|
||||
const resp = await fetch(`${q.QUARK_DRIVE_HOST}${q.EP.TASK}?${params.toString()}`, { headers: q.getHeaders(cookie), signal: AbortSignal.timeout(10000) });
|
||||
const data = await resp.json();
|
||||
if (data.data?.status === 2) {
|
||||
// Task completed — try multiple extraction approaches
|
||||
|
||||
@@ -255,7 +255,7 @@ export async function saveFromShare(cookie, nickname, shareUrl, sourceTitle, ret
|
||||
*/
|
||||
export async function createDir(cookie, dirName, parentFid = '0') {
|
||||
try {
|
||||
const resp = await fetch(`q.QUARK_DRIVE_HOST + q.EP.FILE + '?'${q.makeQuery()}`, {
|
||||
const resp = await fetch(`${q.QUARK_DRIVE_HOST}${q.EP.FILE}?${q.makeQuery()}`, {
|
||||
method: 'POST',
|
||||
headers: { ...q.getHeaders(cookie), 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
|
||||
Reference in New Issue
Block a user