Files
eSIM-Tools/netlify/functions/notifications.js
Abner 7fd54dde39 ♻️ refactor: 修复安全漏洞并优化架构债务
安全修复:
- 修复 dom.js 和 simyo/app.js 中的 innerHTML XSS 注入风险
- 使用 HTMLSanitizer.escapeHtml/escapeAttr 替代直接模板拼接
- 将 onclick 内联事件替换为 data-* 属性 + addEventListener
- 移除 server.js 中硬编码的 Simyo X-Client-Token

架构优化:
- 新增 _shared/rate-limiter.js 分布式限流模块 (Netlify Blobs)
- verify-cookie.js 内存限流替换为 KV 跨实例共享方案
- giffgaff/utils.js debounce/throttle 改为委托共享实现
- simyo/app.js 会话存储迁移至 SecureStorage (自动 TTL 过期)
- 合并 notifications-internal.js 至 notifications.js 消除双维护路径
2026-04-25 16:30:19 +08:00

99 lines
2.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
/**
* 通知消息API
* 提供系统通知消息的查询接口
*/
const { withAuth } = require('./_shared/middleware');
// 通知消息数据可以从JSON文件或数据库读取
const NOTIFICATIONS = [
{
id: 'fix-giffgaff-oauth',
message: 'giffgaff的oauth登录方式已变更,请阅读新方法使用',
type: 'info',
timestamp: '2026-01-22T13:50:00Z',
active: true,
priority: 1
},
{
id: 'fix-simyo-api',
message: '已更新Simyo端点,完善更换流程',
type: 'success',
timestamp: '2026-01-13T00:30:00Z',
active: true,
priority: 2
},
{
id: 'fix-400-error',
message: '已修复Oauth交换时报错400问题,优化了MFA验证流程',
type: 'success',
timestamp: '2025-11-30T10:00:00Z',
active: false,
priority: 1
},
{
id: 'new-feature-oauth',
message: '新功能:支持OAuth 2.0 PKCE认证流程',
type: 'info',
timestamp: '2025-06-20T15:30:00Z',
active: false,
priority: 2
}
];
/**
* 获取活跃通知
*/
function getActiveNotifications() {
return NOTIFICATIONS
.filter(n => n.active)
.sort((a, b) => a.priority - b.priority);
}
/**
* 获取最新通知
*/
function getLatestNotification() {
const active = getActiveNotifications();
return active.length > 0 ? active[0] : null;
}
/**
* 主处理函数
*/
exports.handler = withAuth(async (event, context, { auth }) => {
const { httpMethod, queryStringParameters } = event;
// 仅支持GET请求
if (httpMethod !== 'GET') {
return {
statusCode: 405,
body: JSON.stringify({ error: 'Method not allowed' })
};
}
const mode = queryStringParameters?.mode || 'all';
let data;
switch (mode) {
case 'latest':
data = getLatestNotification();
break;
case 'all':
default:
data = getActiveNotifications();
break;
}
return {
statusCode: 200,
body: JSON.stringify({
success: true,
data,
timestamp: new Date().toISOString()
})
};
}, { requireAuth: false }); // 公开接口,不需要认证