fix: cross-audit fixes — file validation, type safety, dedup
- Avatar upload: whitelist image MIME types and extensions (jpg/png/gif/webp) - Normalize device_id to String for strict comparison in treatment sync - Add ORDER BY expire_time DESC to purchase/adminCreate subscription queries - Deduplicate readBearer: middleware imports from lib/auth.js - Parameterize createTrial INTERVAL instead of string concatenation - Add rate limiting (20/15min) to avatar upload and phone auth endpoints
这个提交包含在:
@@ -56,10 +56,10 @@ async function findAnyActive(userId) {
|
||||
* @returns {Promise<Array>} query result
|
||||
*/
|
||||
async function createTrial(userId, orderId, days) {
|
||||
const trialDays = days || 7
|
||||
const trialDays = Number(days) || 7
|
||||
return query(
|
||||
"INSERT INTO subscriptions (user_id, plan, status, amount, order_id, start_time, expire_time) VALUES (:user_id, 'trial', 1, 0, :order_id, NOW(), DATE_ADD(NOW(), INTERVAL " + Number(trialDays) + " DAY))",
|
||||
{ user_id: userId, order_id: orderId || 'TRIAL' + Date.now() }
|
||||
"INSERT INTO subscriptions (user_id, plan, status, amount, order_id, start_time, expire_time) VALUES (:user_id, 'trial', 1, 0, :order_id, NOW(), DATE_ADD(NOW(), INTERVAL :trial_days DAY))",
|
||||
{ user_id: userId, order_id: orderId || 'TRIAL' + Date.now(), trial_days: trialDays }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ async function createTrial(userId, orderId, days) {
|
||||
async function purchase(userId, plan, amount, orderId, days) {
|
||||
return transaction(async conn => {
|
||||
const [rows] = await conn.execute(
|
||||
'SELECT subscription_id FROM subscriptions WHERE user_id = ? AND status = 1 AND expire_time > NOW() LIMIT 1',
|
||||
'SELECT subscription_id FROM subscriptions WHERE user_id = ? AND status = 1 AND expire_time > NOW() ORDER BY expire_time DESC LIMIT 1',
|
||||
[userId]
|
||||
)
|
||||
if (rows.length > 0) {
|
||||
@@ -114,7 +114,7 @@ async function purchase(userId, plan, amount, orderId, days) {
|
||||
async function adminCreate(userId, plan, amount, orderId, days) {
|
||||
return transaction(async conn => {
|
||||
const [rows] = await conn.execute(
|
||||
'SELECT subscription_id FROM subscriptions WHERE user_id = ? AND status = 1 AND expire_time > NOW() LIMIT 1',
|
||||
'SELECT subscription_id FROM subscriptions WHERE user_id = ? AND status = 1 AND expire_time > NOW() ORDER BY expire_time DESC LIMIT 1',
|
||||
[userId]
|
||||
)
|
||||
if (rows.length > 0) {
|
||||
|
||||
在新工单中引用
屏蔽一个用户