Skip to content

Commit 235733a

Browse files
authored
Merge pull request #44 from dmego/copilot/fix-22118976-106078837-a5b90b60-4665-4d0c-b63e-7de1ae7473dc
Optimize JavaScript performance and eliminate security vulnerabilities
2 parents 0a1a410 + 1b4405c commit 235733a

File tree

2 files changed

+91
-56
lines changed

2 files changed

+91
-56
lines changed

assets/js/bing.js

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,15 @@ const options = {
99
}
1010

1111
const req = https.request(options, bing_res => {
12-
let bing_body = [], bing_data = {};
12+
const chunks = [];
1313
bing_res.on('data', (chunk) => {
14-
bing_body.push(chunk);
14+
chunks.push(chunk);
1515
});
1616
bing_res.on('end', () => {
17-
bing_body = Buffer.concat(bing_body);
18-
bing_data = JSON.parse(bing_body.toString());
19-
let img_array = bing_data.images;
20-
let img_url = [];
21-
img_array.forEach(img => {
22-
img_url.push(img.url);
23-
});
24-
var jsonpStr = "getBingImages(" + JSON.stringify(img_url) + ")";
17+
const bing_data = Buffer.concat(chunks).toString();
18+
const data = JSON.parse(bing_data);
19+
const img_url = data.images.map(img => img.url);
20+
const jsonpStr = "getBingImages(" + JSON.stringify(img_url) + ")";
2521
fs.writeFile('./assets/json/images.json', jsonpStr, (err) => {
2622
if (err) {
2723
throw err;

assets/js/main.js

Lines changed: 85 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,45 @@ var iUp = (function () {
2727
};
2828
})();
2929

30+
// Bing image URL pattern: validates format and prevents CSS injection
31+
var BING_IMAGE_URL_PATTERN = /^\/th\?id=OHR\.[a-zA-Z0-9_\-]+\.jpg(&[a-zA-Z0-9=._\-]+)*$/;
32+
3033
function getBingImages(imgUrls) {
3134
/**
3235
* 获取Bing壁纸
3336
* 先使用 GitHub Action 每天获取 Bing 壁纸 URL 并更新 images.json 文件
3437
* 然后读取 images.json 文件中的数据
3538
*/
36-
var indexName = "bing-image-index";
37-
var index = sessionStorage.getItem(indexName);
3839
var panel = document.querySelector('#panel');
39-
if (isNaN(index) || index == 7) index = 0;
40-
else index++;
40+
if (!panel || !imgUrls || !Array.isArray(imgUrls) || imgUrls.length === 0) {
41+
return;
42+
}
43+
44+
var indexName = "bing-image-index";
45+
var index = parseInt(sessionStorage.getItem(indexName), 10);
46+
var maxIndex = imgUrls.length - 1;
47+
48+
if (isNaN(index) || index > maxIndex) {
49+
index = 0;
50+
} else {
51+
index++;
52+
if (index > maxIndex) {
53+
index = 0;
54+
}
55+
}
56+
4157
var imgUrl = imgUrls[index];
58+
// Validate URL format to prevent CSS injection
59+
if (!imgUrl || typeof imgUrl !== 'string' || !imgUrl.match(BING_IMAGE_URL_PATTERN)) {
60+
return;
61+
}
62+
63+
// Use backgroundImage property with proper escaping to prevent CSS injection
4264
var url = "https://www.cn.bing.com" + imgUrl;
43-
panel.style.background = "url('" + url + "') center center no-repeat #666";
65+
panel.style.backgroundImage = "url('" + url.replace(/['\\]/g, '\\$&') + "')";
66+
panel.style.backgroundPosition = "center center";
67+
panel.style.backgroundRepeat = "no-repeat";
68+
panel.style.backgroundColor = "#666";
4469
panel.style.backgroundSize = "cover";
4570
sessionStorage.setItem(indexName, index);
4671
}
@@ -52,56 +77,70 @@ function decryptEmail(encoded) {
5277

5378
document.addEventListener('DOMContentLoaded', function () {
5479
// 获取一言数据
55-
var xhr = new XMLHttpRequest();
56-
xhr.onreadystatechange = function () {
57-
if (this.readyState == 4 && this.status == 200) {
58-
var res = JSON.parse(this.responseText);
59-
document.getElementById('description').innerHTML = res.hitokoto + "<br/> -「<strong>" + res.from + "</strong>」";
60-
}
61-
};
62-
xhr.open("GET", "https://v1.hitokoto.cn", true);
63-
xhr.send();
80+
fetch("https://v1.hitokoto.cn")
81+
.then(function(response) {
82+
return response.json();
83+
})
84+
.then(function(res) {
85+
var descElement = document.getElementById('description');
86+
if (descElement && res.hitokoto && res.from) {
87+
// Create text nodes to prevent XSS
88+
var textNode = document.createTextNode(res.hitokoto);
89+
var br = document.createElement('br');
90+
var fromText = document.createTextNode(' -「');
91+
var strong = document.createElement('strong');
92+
strong.textContent = res.from;
93+
var endText = document.createTextNode('」');
94+
95+
descElement.innerHTML = '';
96+
descElement.appendChild(textNode);
97+
descElement.appendChild(br);
98+
descElement.appendChild(fromText);
99+
descElement.appendChild(strong);
100+
descElement.appendChild(endText);
101+
}
102+
})
103+
.catch(function(error) {
104+
console.error('Error fetching hitokoto:', error);
105+
});
64106

65107
var iUpElements = document.querySelectorAll(".iUp");
66-
iUpElements.forEach(function (element) {
67-
iUp.up(element);
68-
});
108+
for (var i = 0; i < iUpElements.length; i++) {
109+
iUp.up(iUpElements[i]);
110+
}
69111

70112
var avatarElement = document.querySelector(".js-avatar");
71-
avatarElement.addEventListener('load', function () {
72-
avatarElement.classList.add("show");
73-
});
113+
if (avatarElement) {
114+
avatarElement.addEventListener('load', function () {
115+
avatarElement.classList.add("show");
116+
});
117+
}
74118
});
75119

76120
var btnMobileMenu = document.querySelector('.btn-mobile-menu__icon');
77121
var navigationWrapper = document.querySelector('.navigation-wrapper');
78122

79-
btnMobileMenu.addEventListener('click', function () {
80-
if (navigationWrapper.style.display == "block") {
81-
navigationWrapper.addEventListener('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function () {
82-
navigationWrapper.classList.toggle('visible');
83-
navigationWrapper.classList.toggle('animated');
84-
navigationWrapper.classList.toggle('bounceOutUp');
85-
navigationWrapper.removeEventListener('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', arguments.callee);
86-
});
87-
navigationWrapper.classList.toggle('animated');
88-
navigationWrapper.classList.toggle('bounceInDown');
89-
navigationWrapper.classList.toggle('animated');
90-
navigationWrapper.classList.toggle('bounceOutUp');
91-
} else {
92-
navigationWrapper.classList.toggle('visible');
93-
navigationWrapper.classList.toggle('animated');
94-
navigationWrapper.classList.toggle('bounceInDown');
95-
}
96-
btnMobileMenu.classList.toggle('social');
97-
btnMobileMenu.classList.toggle('iconfont');
98-
btnMobileMenu.classList.toggle('icon-list');
99-
btnMobileMenu.classList.toggle('social');
100-
btnMobileMenu.classList.toggle('iconfont');
101-
btnMobileMenu.classList.toggle('icon-angleup');
102-
btnMobileMenu.classList.toggle('animated');
103-
btnMobileMenu.classList.toggle('fadeIn');
104-
});
123+
if (btnMobileMenu && navigationWrapper) {
124+
btnMobileMenu.addEventListener('click', function () {
125+
var isVisible = navigationWrapper.classList.contains('visible');
126+
127+
function handleAnimationEnd() {
128+
navigationWrapper.classList.remove('visible', 'animated', 'bounceOutUp');
129+
navigationWrapper.removeEventListener('animationend', handleAnimationEnd);
130+
}
131+
132+
if (isVisible) {
133+
navigationWrapper.addEventListener('animationend', handleAnimationEnd);
134+
navigationWrapper.classList.remove('bounceInDown');
135+
navigationWrapper.classList.add('animated', 'bounceOutUp');
136+
} else {
137+
navigationWrapper.classList.add('visible', 'animated', 'bounceInDown');
138+
}
139+
140+
btnMobileMenu.classList.toggle('icon-list');
141+
btnMobileMenu.classList.toggle('icon-angleup');
142+
});
143+
}
105144

106145
function showWeChatModal() {
107146
const modal = document.getElementById('wechatModal');

0 commit comments

Comments
 (0)