capta1n commited on
Commit
a5a3963
·
verified ·
1 Parent(s): d53f81b

Add 3 files

Browse files
Files changed (3) hide show
  1. README.md +7 -5
  2. index.html +1889 -19
  3. prompts.txt +1 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Aisdl Langdingpage
3
- emoji: 💻
4
- colorFrom: red
5
- colorTo: red
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: aisdl-langdingpage
3
+ emoji: 🐳
4
+ colorFrom: purple
5
+ colorTo: pink
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1889 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>AI SDL Digital Twin Dashboard</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ @keyframes float {
11
+ 0% { transform: translateY(0px); }
12
+ 50% { transform: translateY(-10px); }
13
+ 100% { transform: translateY(0px); }
14
+ }
15
+
16
+ @keyframes pulse {
17
+ 0% { opacity: 0.7; }
18
+ 50% { opacity: 1; }
19
+ 100% { opacity: 0.7; }
20
+ }
21
+
22
+ @keyframes pulse-glow {
23
+ 0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); }
24
+ 70% { box-shadow: 0 0 0 10px rgba(239, 68, 68, 0); }
25
+ 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }
26
+ }
27
+
28
+ @keyframes data-flow {
29
+ 0% { stroke-dashoffset: 100; }
30
+ 100% { stroke-dashoffset: 0; }
31
+ }
32
+
33
+ @keyframes rotate {
34
+ 0% { transform: rotate(0deg); }
35
+ 100% { transform: rotate(360deg); }
36
+ }
37
+
38
+ @keyframes scanning {
39
+ 0% { transform: translateX(-100%) rotate(45deg); }
40
+ 100% { transform: translateX(100%) rotate(45deg); }
41
+ }
42
+
43
+ @keyframes flicker {
44
+ 0% { opacity: 0.5; }
45
+ 50% { opacity: 1; }
46
+ 100% { opacity: 0.5; }
47
+ }
48
+
49
+ .floating {
50
+ animation: float 3s ease-in-out infinite;
51
+ }
52
+
53
+ .pulse {
54
+ animation: pulse 2s ease-in-out infinite;
55
+ }
56
+
57
+ .pulse-glow {
58
+ animation: pulse-glow 1.5s infinite;
59
+ }
60
+
61
+ .data-flow {
62
+ stroke-dasharray: 10;
63
+ animation: data-flow 2s linear infinite;
64
+ }
65
+
66
+ .rotate {
67
+ animation: rotate 2s linear infinite;
68
+ }
69
+
70
+ .scanning {
71
+ position: relative;
72
+ overflow: hidden;
73
+ }
74
+
75
+ .scanning::after {
76
+ content: "";
77
+ position: absolute;
78
+ top: 0;
79
+ left: 0;
80
+ right: 0;
81
+ bottom: 0;
82
+ background: linear-gradient(
83
+ to bottom,
84
+ rgba(16, 185, 129, 0.1) 0%,
85
+ rgba(16, 185, 129, 0.3) 50%,
86
+ rgba(16, 185, 129, 0.1) 100%
87
+ );
88
+ transform: rotate(45deg);
89
+ animation: scanning 3s linear infinite;
90
+ }
91
+
92
+ .flicker {
93
+ animation: flicker 1.5s ease-in-out infinite alternate;
94
+ }
95
+
96
+ .code-block {
97
+ font-family: 'Courier New', monospace;
98
+ background-color: #1e293b;
99
+ color: #f8fafc;
100
+ padding: 1rem;
101
+ border-radius: 0.5rem;
102
+ overflow-x: auto;
103
+ }
104
+
105
+ .vulnerability-line {
106
+ background-color: #7f1d1d;
107
+ padding: 0.2rem;
108
+ border-radius: 0.2rem;
109
+ }
110
+
111
+ .threat-model {
112
+ background-color: #f8fafc;
113
+ border: 1px solid #e2e8f0;
114
+ border-radius: 0.5rem;
115
+ padding: 1rem;
116
+ position: relative;
117
+ }
118
+
119
+ .risk-tag {
120
+ display: inline-block;
121
+ padding: 0.2rem 0.5rem;
122
+ border-radius: 1rem;
123
+ font-size: 0.75rem;
124
+ margin-right: 0.5rem;
125
+ margin-bottom: 0.5rem;
126
+ }
127
+
128
+ .progress-ring__circle {
129
+ transition: stroke-dashoffset 0.5s;
130
+ transform: rotate(-90deg);
131
+ transform-origin: 50% 50%;
132
+ }
133
+
134
+ .highlight-box {
135
+ position: relative;
136
+ border-left: 4px solid;
137
+ padding-left: 1rem;
138
+ margin-bottom: 1rem;
139
+ }
140
+
141
+ .highlight-box::before {
142
+ content: "";
143
+ position: absolute;
144
+ top: 0;
145
+ left: 0;
146
+ right: 0;
147
+ bottom: 0;
148
+ background-color: rgba(255, 255, 255, 0.1);
149
+ border-radius: 0.25rem;
150
+ z-index: -1;
151
+ }
152
+
153
+ .circular-node {
154
+ position: absolute;
155
+ width: 100px;
156
+ height: 100px;
157
+ border-radius: 50%;
158
+ display: flex;
159
+ flex-direction: column;
160
+ align-items: center;
161
+ justify-content: center;
162
+ text-align: center;
163
+ transition: all 0.3s ease;
164
+ }
165
+
166
+ .circular-node:hover {
167
+ transform: scale(1.1);
168
+ z-index: 10;
169
+ }
170
+
171
+ .stats-card {
172
+ transition: all 0.3s ease;
173
+ position: relative;
174
+ }
175
+
176
+ .stats-card:hover {
177
+ transform: translateY(-5px);
178
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
179
+ }
180
+
181
+ .stats-card::before {
182
+ content: "";
183
+ position: absolute;
184
+ top: 0;
185
+ left: 0;
186
+ right: 0;
187
+ height: 3px;
188
+ background-color: #10b981;
189
+ opacity: 0;
190
+ transition: opacity 0.3s ease;
191
+ }
192
+
193
+ .stats-card:hover::before {
194
+ opacity: 1;
195
+ }
196
+
197
+ .active-scan {
198
+ position: relative;
199
+ }
200
+
201
+ .active-scan::after {
202
+ content: "Analyzing...";
203
+ position: absolute;
204
+ bottom: -20px;
205
+ left: 0;
206
+ right: 0;
207
+ text-align: center;
208
+ font-size: 0.75rem;
209
+ color: #10b981;
210
+ font-weight: 600;
211
+ }
212
+ </style>
213
+ </head>
214
+ <body class="bg-gray-50 min-h-screen">
215
+ <!-- Navigation -->
216
+ <nav class="bg-green-800 text-white shadow-lg">
217
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
218
+ <div class="flex justify-between h-16 items-center">
219
+ <div class="flex items-center">
220
+ <div class="flex-shrink-0 flex items-center">
221
+ <i class="fas fa-robot text-2xl mr-2"></i>
222
+ <span class="text-xl font-bold">AI SDL Digital Twin</span>
223
+ </div>
224
+ </div>
225
+ <div class="hidden md:block">
226
+ <div class="ml-10 flex items-baseline space-x-4">
227
+ <a href="#" class="bg-green-700 px-3 py-2 rounded-md text-sm font-medium">Dashboard</a>
228
+ <a href="#alerts" class="text-green-200 hover:bg-green-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Risk Alerts</a>
229
+ <a href="#projects" class="text-green-200 hover:bg-green-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Projects</a>
230
+ </div>
231
+ </div>
232
+ </div>
233
+ </div>
234
+ </nav>
235
+
236
+ <!-- Main Content -->
237
+ <main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
238
+ <!-- Dashboard Section -->
239
+ <section id="dashboard">
240
+ <div class="mb-8">
241
+ <h1 class="text-3xl font-bold text-gray-900">SDL Security Guardian</h1>
242
+ <p class="mt-2 text-gray-600">Your digital security companion continuously analyzing SDL processes</p>
243
+ </div>
244
+
245
+ <!-- Real-time Stats Panel - Moved to top -->
246
+ <div class="bg-white rounded-xl shadow-md overflow-hidden mb-8 scanning">
247
+ <div class="p-6">
248
+ <div class="flex justify-between items-center mb-6">
249
+ <h2 class="text-xl font-bold text-gray-900">Real-time Analysis Dashboard</h2>
250
+ <div class="flex items-center">
251
+ <div class="h-3 w-3 rounded-full bg-green-500 mr-2 pulse"></div>
252
+ <span class="text-sm font-medium text-green-600">Active Scanning</span>
253
+ </div>
254
+ </div>
255
+
256
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-4">
257
+ <div class="stats-card bg-gray-50 p-4 rounded-lg active-scan">
258
+ <div class="flex items-center">
259
+ <div class="bg-green-100 rounded-full h-10 w-10 flex items-center justify-center text-green-600 mr-3 flicker">
260
+ <i class="fas fa-file-alt"></i>
261
+ </div>
262
+ <div>
263
+ <h4 class="text-sm font-medium text-gray-700">Requirements Analyzed</h4>
264
+ <p class="text-xl font-bold text-gray-900 flicker">24</p>
265
+ <p class="text-xs text-gray-500">2 threats identified</p>
266
+ </div>
267
+ </div>
268
+ </div>
269
+
270
+ <div class="stats-card bg-gray-50 p-4 rounded-lg active-scan">
271
+ <div class="flex items-center">
272
+ <div class="bg-green-100 rounded-full h-10 w-10 flex items-center justify-center text-green-600 mr-3 flicker">
273
+ <i class="fas fa-code"></i>
274
+ </div>
275
+ <div>
276
+ <h4 class="text-sm font-medium text-gray-700">Code Scanned</h4>
277
+ <p class="text-xl font-bold text-gray-900 flicker">120,842 <span class="text-sm">lines</span></p>
278
+ <p class="text-xs text-gray-500">1 critical vulnerability</p>
279
+ </div>
280
+ </div>
281
+ </div>
282
+
283
+ <div class="stats-card bg-gray-50 p-4 rounded-lg active-scan">
284
+ <div class="flex items-center">
285
+ <div class="bg-green-100 rounded-full h-10 w-10 flex items-center justify-center text-green-600 mr-3 flicker">
286
+ <i class="fas fa-shield-alt"></i>
287
+ </div>
288
+ <div>
289
+ <h4 class="text-sm font-medium text-gray-700">Tests Completed</h4>
290
+ <p class="text-xl font-bold text-gray-900 flicker">18/42</p>
291
+ <p class="text-xs text-gray-500">1 medium risk found</p>
292
+ </div>
293
+ </div>
294
+ </div>
295
+
296
+ <div class="stats-card bg-gray-50 p-4 rounded-lg active-scan">
297
+ <div class="flex items-center">
298
+ <div class="bg-green-100 rounded-full h-10 w-10 flex items-center justify-center text-green-600 mr-3 flicker">
299
+ <i class="fas fa-rocket"></i>
300
+ </div>
301
+ <div>
302
+ <h4 class="text-sm font-medium text-gray-700">Releases Verified</h4>
303
+ <p class="text-xl font-bold text-gray-900 flicker">3</p>
304
+ <p class="text-xs text-gray-500">All checks passed</p>
305
+ </div>
306
+ </div>
307
+ </div>
308
+
309
+ <div class="stats-card bg-gray-50 p-4 rounded-lg active-scan">
310
+ <div class="flex items-center">
311
+ <div class="bg-green-100 rounded-full h-10 w-10 flex items-center justify-center text-green-600 mr-3 flicker">
312
+ <i class="fas fa-server"></i>
313
+ </div>
314
+ <div>
315
+ <h4 class="text-sm font-medium text-gray-700">Production Services</h4>
316
+ <p class="text-xl font-bold text-gray-900 flicker">5</p>
317
+ <p class="text-xs text-gray-500">No active incidents</p>
318
+ </div>
319
+ </div>
320
+ </div>
321
+ </div>
322
+
323
+ <div class="mt-6 pt-4 border-t border-gray-200">
324
+ <button class="bg-green-600 hover:bg-green-700 text-white font-medium py-2 px-4 rounded-md flex items-center justify-center transition">
325
+ <i class="fas fa-file-pdf mr-2"></i> Generate Security Report
326
+ </button>
327
+ </div>
328
+ </div>
329
+ </div>
330
+
331
+ <!-- Circular SDL Process Visualization -->
332
+ <div class="bg-white rounded-xl shadow-md overflow-hidden mb-8 p-6">
333
+ <div class="flex flex-col lg:flex-row">
334
+ <!-- Circular Process Visualization -->
335
+ <div class="lg:w-2/3 relative h-96 lg:h-auto">
336
+ <div class="absolute inset-0 flex items-center justify-center">
337
+ <svg width="100%" height="100%" viewBox="0 0 500 500" class="absolute">
338
+ <!-- Data flow arrows -->
339
+ <defs>
340
+ <marker id="arrowhead" markerWidth="10" markerHeight="7"
341
+ refX="0" refY="3.5" orient="auto">
342
+ <polygon points="0 0, 10 3.5, 0 7" fill="#10b981" />
343
+ </marker>
344
+ </defs>
345
+
346
+ <!-- Circular path for data flow -->
347
+ <path id="data-path" d="M250,100 A150,150 0 1,1 250,400 A150,150 0 1,1 250,100"
348
+ fill="none" stroke="#10b981" stroke-width="2" stroke-dasharray="10,5"
349
+ class="data-flow" />
350
+
351
+ <!-- Animated arrow along the path -->
352
+ <circle cx="250" cy="100" r="5" fill="#10b981">
353
+ <animateMotion dur="10s" repeatCount="indefinite">
354
+ <mpath xlink:href="#data-path"/>
355
+ </animateMotion>
356
+ </circle>
357
+ </svg>
358
+
359
+ <!-- Requirement Design Node -->
360
+ <div class="circular-node bg-green-50 border-2 border-green-200" style="top: 10%; left: 50%; transform: translateX(-50%);">
361
+ <div class="relative w-16 h-16 mb-2">
362
+ <svg class="w-full h-full" viewBox="0 0 36 36">
363
+ <path
364
+ d="M18 2.0845
365
+ a 15.9155 15.9155 0 0 1 0 31.831
366
+ a 15.9155 15.9155 0 0 1 0 -31.831"
367
+ fill="none"
368
+ stroke="#e2e8f0"
369
+ stroke-width="3"
370
+ />
371
+ <path
372
+ class="progress-ring__circle"
373
+ stroke="#10b981"
374
+ stroke-width="3"
375
+ stroke-dasharray="78, 100"
376
+ d="M18 2.0845
377
+ a 15.9155 15.9155 0 0 1 0 31.831
378
+ a 15.9155 15.9155 0 0 1 0 -31.831"
379
+ />
380
+ </svg>
381
+ <div class="absolute inset-0 flex items-center justify-center">
382
+ <i class="fas fa-lightbulb text-green-600 text-xl"></i>
383
+ </div>
384
+ </div>
385
+ <div class="text-xs font-medium text-gray-700">Requirement Design</div>
386
+ <div class="text-xs text-gray-500 mt-1">78% analyzed</div>
387
+ <div class="absolute -top-2 -right-2 bg-red-500 text-white rounded-full h-6 w-6 flex items-center justify-center text-xs pulse-glow">2</div>
388
+ </div>
389
+
390
+ <!-- Code Changes Node -->
391
+ <div class="circular-node bg-green-50 border-2 border-green-200" style="top: 30%; right: 10%;">
392
+ <div class="relative w-16 h-16 mb-2">
393
+ <svg class="w-full h-full" viewBox="0 0 36 36">
394
+ <path
395
+ d="M18 2.0845
396
+ a 15.9155 15.9155 0 0 1 0 31.831
397
+ a 15.9155 15.9155 0 0 1 0 -31.831"
398
+ fill="none"
399
+ stroke="#e2e8f0"
400
+ stroke-width="3"
401
+ />
402
+ <path
403
+ class="progress-ring__circle"
404
+ stroke="#10b981"
405
+ stroke-width="3"
406
+ stroke-dasharray="45, 100"
407
+ d="M18 2.0845
408
+ a 15.9155 15.9155 0 0 1 0 31.831
409
+ a 15.9155 15.9155 0 0 1 0 -31.831"
410
+ />
411
+ </svg>
412
+ <div class="absolute inset-0 flex items-center justify-center">
413
+ <i class="fas fa-code text-green-600 text-xl"></i>
414
+ </div>
415
+ </div>
416
+ <div class="text-xs font-medium text-gray-700">Code Changes</div>
417
+ <div class="text-xs text-gray-500 mt-1">45% analyzed</div>
418
+ <div class="absolute -top-2 -right-2 bg-red-500 text-white rounded-full h-6 w-6 flex items-center justify-center text-xs pulse-glow">1</div>
419
+ </div>
420
+
421
+ <!-- Security Testing Node -->
422
+ <div class="circular-node bg-green-50 border-2 border-green-200" style="bottom: 20%; right: 20%;">
423
+ <div class="relative w-16 h-16 mb-2">
424
+ <svg class="w-full h-full" viewBox="0 0 36 36">
425
+ <path
426
+ d="M18 2.0845
427
+ a 15.9155 15.9155 0 0 1 0 31.831
428
+ a 15.9155 15.9155 0 0 1 0 -31.831"
429
+ fill="none",
430
+ stroke="#e2e8f0",
431
+ stroke-width="3"
432
+ />
433
+ <path
434
+ class="progress-ring__circle",
435
+ stroke="#10b981",
436
+ stroke-width="3",
437
+ stroke-dasharray="32, 100",
438
+ d="M18 2.0845
439
+ a 15.9155 15.9155 0 0 1 0 31.831
440
+ a 15.9155 15.9155 0 0 1 0 -31.831"
441
+ />
442
+ </svg>
443
+ <div class="absolute inset-0 flex items-center justify-center">
444
+ <i class="fas fa-shield-alt text-green-600 text-xl"></i>
445
+ </div>
446
+ </div>
447
+ <div class="text-xs font-medium text-gray-700">Security Testing</div>
448
+ <div class="text-xs text-gray-500 mt-1">32% analyzed</div>
449
+ <div class="absolute -top-2 -right-2 bg-yellow-500 text-white rounded-full h-6 w-6 flex items-center justify-center text-xs">1</div>
450
+ </div>
451
+
452
+ <!-- Release Node -->
453
+ <div class="circular-node bg-green-50 border-2 border-green-200" style="bottom: 20%; left: 20%;">
454
+ <div class="relative w-16 h-16 mb-2">
455
+ <svg class="w-full h-full" viewBox="0 0 36 36">
456
+ <path
457
+ d="M18 2.0845
458
+ a 15.9155 15.9155 0 0 1 0 31.831
459
+ a 15.9155 15.9155 0 0 1 0 -31.831"
460
+ fill="none",
461
+ stroke="#e2e8f0",
462
+ stroke-width="3"
463
+ />
464
+ <path
465
+ class="progress-ring__circle",
466
+ stroke="#10b981",
467
+ stroke-width="3",
468
+ stroke-dasharray="90, 100",
469
+ d="M18 2.0845
470
+ a 15.9155 15.9155 0 0 1 0 31.831
471
+ a 15.9155 15.9155 0 0 1 0 -31.831"
472
+ />
473
+ </svg>
474
+ <div class="absolute inset-0 flex items-center justify-center">
475
+ <i class="fas fa-rocket text-green-600 text-xl"></i>
476
+ </div>
477
+ </div>
478
+ <div class="text-xs font-medium text-gray-700">Release</div>
479
+ <div class="text-xs text-gray-500 mt-1">90% analyzed</div>
480
+ </div>
481
+
482
+ <!-- Production Node -->
483
+ <div class="circular-node bg-green-50 border-2 border-green-200" style="top: 30%; left: 10%;">
484
+ <div class="relative w-16 h-16 mb-2">
485
+ <svg class="w-full h-full" viewBox="0 0 36 36">
486
+ <path
487
+ d="M18 2.0845
488
+ a 15.9155 15.9155 0 0 1 0 31.831
489
+ a 15.9155 15.9155 0 0 1 0 -31.831"
490
+ fill="none",
491
+ stroke="#e2e8f0",
492
+ stroke-width="3"
493
+ />
494
+ <path
495
+ class="progress-ring__circle",
496
+ stroke="#10b981",
497
+ stroke-width="3",
498
+ stroke-dasharray="65, 100",
499
+ d="M18 2.0845
500
+ a 15.9155 15.9155 0 0 1 0 31.831
501
+ a 15.9155 15.9155 0 0 1 0 -31.831"
502
+ />
503
+ </svg>
504
+ <div class="absolute inset-0 flex items-center justify-center">
505
+ <i class="fas fa-globe text-green-600 text-xl"></i>
506
+ </div>
507
+ </div>
508
+ <div class="text-xs font-medium text-gray-700">Production</div>
509
+ <div class="text-xs text-gray-500 mt-1">65% analyzed</div>
510
+ </div>
511
+
512
+ <!-- Center AI Avatar -->
513
+ <div class="absolute inset-0 flex items-center justify-center">
514
+ <div class="relative">
515
+ <div class="floating">
516
+ <img class="h-24 w-24 object-contain" src="https://img.icons8.com/color/480/robot-3.png" alt="AI SDL Digital Twin">
517
+ </div>
518
+ <div class="absolute bottom-0 right-0 bg-green-500 text-white rounded-full h-8 w-8 flex items-center justify-center">
519
+ <i class="fas fa-bolt"></i>
520
+ </div>
521
+ </div>
522
+ </div>
523
+ </div>
524
+ </div>
525
+
526
+ <!-- Analysis Details Panel -->
527
+ <div class="lg:w-1/3 lg:pl-6 mt-6 lg:mt-0">
528
+ <div class="bg-gray-50 p-6 rounded-lg h-full">
529
+ <h3 class="text-lg font-semibold text-gray-900 mb-4">Analysis Insights</h3>
530
+
531
+ <div class="space-y-4">
532
+ <div class="bg-white p-4 rounded-lg shadow-sm border border-gray-200">
533
+ <h4 class="text-sm font-medium text-gray-700 mb-2">Current Focus</h4>
534
+ <div class="flex items-center">
535
+ <div class="bg-green-100 rounded-full h-8 w-8 flex items-center justify-center text-green-600 mr-3">
536
+ <i class="fas fa-code"></i>
537
+ </div>
538
+ <div>
539
+ <p class="text-sm text-gray-900">Code Change Analysis</p>
540
+ <p class="text-xs text-gray-500">Scanning payment processing module</p>
541
+ </div>
542
+ </div>
543
+ </div>
544
+
545
+ <div class="bg-white p-4 rounded-lg shadow-sm border border-gray-200">
546
+ <h4 class="text-sm font-medium text-gray-700 mb-2">Recent Findings</h4>
547
+ <div class="space-y-3">
548
+ <div class="flex items-start">
549
+ <div class="bg-red-100 rounded-full h-6 w-6 flex items-center justify-center text-red-600 mr-2 mt-0.5">
550
+ <i class="fas fa-exclamation-triangle text-xs"></i>
551
+ </div>
552
+ <div>
553
+ <p class="text-sm text-gray-900">SQL Injection vulnerability</p>
554
+ <p class="text-xs text-gray-500">In subsidy payment processing</p>
555
+ </div>
556
+ </div>
557
+ <div class="flex items-start">
558
+ <div class="bg-yellow-100 rounded-full h-6 w-6 flex items-center justify-center text-yellow-600 mr-2 mt-0.5">
559
+ <i class="fas fa-info-circle text-xs"></i>
560
+ </div>
561
+ <div>
562
+ <p class="text-sm text-gray-900">Hardcoded credentials</p>
563
+ <p class="text-xs text-gray-500">In payment gateway config</p>
564
+ </div>
565
+ </div>
566
+ </div>
567
+ </div>
568
+
569
+ <div class="bg-white p-4 rounded-lg shadow-sm border border-gray-200">
570
+ <h4 class="text-sm font-medium text-gray-700 mb-2">Next Steps</h4>
571
+ <div class="flex items-start">
572
+ <div class="bg-blue-100 rounded-full h-6 w-6 flex items-center justify-center text-blue-600 mr-2 mt-0.5">
573
+ <i class="fas fa-shield-alt text-xs"></i>
574
+ </div>
575
+ <div>
576
+ <p class="text-sm text-gray-900">Security Testing Phase</p>
577
+ <p class="text-xs text-gray-500">Starting in approx. 15 minutes</p>
578
+ </div>
579
+ </div>
580
+ </div>
581
+ </div>
582
+
583
+ <div class="mt-6 pt-4 border-t border-gray-200">
584
+ <button class="w-full bg-green-600 hover:bg-green-700 text-white font-medium py-2 px-4 rounded-md flex items-center justify-center transition">
585
+ <i class="fas fa-bell mr-2"></i> Get Notifications
586
+ </button>
587
+ </div>
588
+ </div>
589
+ </div>
590
+ </div>
591
+
592
+ <!-- Floating Action Bar -->
593
+ <div class="mt-6 bg-white border border-gray-200 rounded-lg p-4 shadow-sm">
594
+ <div class="flex items-center justify-between">
595
+ <div class="flex items-center">
596
+ <div class="bg-green-100 rounded-full h-10 w-10 flex items-center justify-center text-green-600 mr-3">
597
+ <i class="fas fa-robot"></i>
598
+ </div>
599
+ <div>
600
+ <h4 class="text-sm font-medium text-gray-700">SDL Security Guardian</h4>
601
+ <p class="text-xs text-gray-500">Continuously analyzing your SDL processes</p>
602
+ </div>
603
+ </div>
604
+ <div class="flex space-x-2">
605
+ <button class="bg-gray-100 hover:bg-gray-200 text-gray-800 font-medium py-2 px-4 rounded-md text-sm transition">
606
+ <i class="fas fa-pause mr-1"></i> Pause
607
+ </button>
608
+ <button class="bg-green-600 hover:bg-green-700 text-white font-medium py-2 px-4 rounded-md text-sm transition">
609
+ <i class="fas fa-sync-alt mr-1"></i> Rescan
610
+ </button>
611
+ </div>
612
+ </div>
613
+ </div>
614
+ </div>
615
+
616
+ <!-- Risk Alerts Section -->
617
+ <section id="alerts" class="mb-8">
618
+ <div class="flex justify-between items-center mb-4">
619
+ <h2 class="text-2xl font-bold text-gray-900">Risk Alerts</h2>
620
+ <div class="flex items-center">
621
+ <span class="bg-red-500 text-white text-xs font-bold px-2 py-1 rounded-full mr-2">3 New</span>
622
+ <button class="text-sm text-green-600 hover:text-green-800">View All</button>
623
+ </div>
624
+ </div>
625
+
626
+ <div class="bg-white shadow overflow-hidden rounded-lg">
627
+ <div class="divide-y divide-gray-200">
628
+ <!-- Critical Alert -->
629
+ <div class="p-4 hover:bg-gray-50 cursor-pointer transition" onclick="showProjectDetail('alipay-subsidy')">
630
+ <div class="flex items-start">
631
+ <div class="flex-shrink-0 pt-1">
632
+ <div class="bg-red-500 rounded-full h-8 w-8 flex items-center justify-center text-white">
633
+ <i class="fas fa-exclamation-triangle"></i>
634
+ </div>
635
+ </div>
636
+ <div class="ml-3 flex-1">
637
+ <div class="flex items-center justify-between">
638
+ <h3 class="text-sm font-medium text-red-700">支付宝国补项目 (Alipay Subsidy Project)</h3>
639
+ <span class="text-xs text-gray-500">10 min ago</span>
640
+ </div>
641
+ <div class="mt-1 text-sm text-gray-700">
642
+ <p>Multiple risks detected in code and requirement design phases</p>
643
+ </div>
644
+ <div class="mt-2">
645
+ <span class="risk-tag bg-red-100 text-red-800">SQL Injection</span>
646
+ <span class="risk-tag bg-red-100 text-red-800">Authorization Bypass</span>
647
+ <span class="risk-tag bg-yellow-100 text-yellow-800">Data Validation</span>
648
+ </div>
649
+ </div>
650
+ </div>
651
+ </div>
652
+
653
+ <!-- High Alert -->
654
+ <div class="p-4 hover:bg-gray-50 cursor-pointer transition" onclick="showProjectDetail('merchant-portal')">
655
+ <div class="flex items-start">
656
+ <div class="flex-shrink-0 pt-1">
657
+ <div class="bg-orange-500 rounded-full h-8 w-8 flex items-center justify-center text-white">
658
+ <i class="fas fa-exclamation-circle"></i>
659
+ </div>
660
+ </div>
661
+ <div class="ml-3 flex-1">
662
+ <div class="flex items-center justify-between">
663
+ <h3 class="text-sm font-medium text-orange-700">Merchant Portal v2.0</h3>
664
+ <span class="text-xs text-gray-500">25 min ago</span>
665
+ </div>
666
+ <div class="mt-1 text-sm text-gray-700">
667
+ <p>Security testing found XSS vulnerabilities in 3 endpoints</p>
668
+ </div>
669
+ <div class="mt-2">
670
+ <span class="risk-tag bg-orange-100 text-orange-800">Cross-Site Scripting</span>
671
+ <span class="risk-tag bg-yellow-100 text-yellow-800">Input Validation</span>
672
+ </div>
673
+ </div>
674
+ </div>
675
+ </div>
676
+
677
+ <!-- Medium Alert -->
678
+ <div class="p-4 hover:bg-gray-50 cursor-pointer transition" onclick="showProjectDetail('payment-gateway')">
679
+ <div class="flex items-start">
680
+ <div class="flex-shrink-0 pt-1">
681
+ <div class="bg-yellow-500 rounded-full h-8 w-8 flex items-center justify-center text-white">
682
+ <i class="fas fa-info-circle"></i>
683
+ </div>
684
+ </div>
685
+ <div class="ml-3 flex-1">
686
+ <div class="flex items-center justify-between">
687
+ <h3 class="text-sm font-medium text-yellow-700">Payment Gateway Microservice</h3>
688
+ <span class="text-xs text-gray-500">1 hour ago</span>
689
+ </div>
690
+ <div class="mt-1 text-sm text-gray-700">
691
+ <p>Hardcoded credentials found in configuration files</p>
692
+ </div>
693
+ <div class="mt-2">
694
+ <span class="risk-tag bg-yellow-100 text-yellow-800">Sensitive Data Exposure</span>
695
+ </div>
696
+ </div>
697
+ </div>
698
+ </div>
699
+ </div>
700
+ </div>
701
+ </section>
702
+
703
+ <!-- Projects Section -->
704
+ <section id="projects" class="mb-8">
705
+ <h2 class="text-2xl font-bold text-gray-900 mb-4">Projects Under Analysis</h2>
706
+
707
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
708
+ <!-- Project Card 1 -->
709
+ <div class="bg-white rounded-lg shadow overflow-hidden border-l-4 border-red-500">
710
+ <div class="p-5">
711
+ <div class="flex items-center justify-between">
712
+ <h3 class="text-lg font-semibold text-gray-900">支付宝国补项目</h3>
713
+ <span class="bg-red-100 text-red-800 text-xs px-2 py-1 rounded-full">High Risk</span>
714
+ </div>
715
+ <p class="text-sm text-gray-600 mt-1">Government subsidy distribution system</p>
716
+
717
+ <div class="mt-4">
718
+ <div class="flex justify-between text-xs text-gray-500 mb-1">
719
+ <span>Progress</span>
720
+ <span>65%</span>
721
+ </div>
722
+ <div class="w-full bg-gray-200 rounded-full h-2">
723
+ <div class="bg-red-500 h-2 rounded-full" style="width: 65%"></div>
724
+ </div>
725
+ </div>
726
+
727
+ <div class="mt-4">
728
+ <h4 class="text-xs font-medium text-gray-500 uppercase tracking-wider">Risks Detected</h4>
729
+ <div class="mt-2">
730
+ <span class="risk-tag bg-red-100 text-red-800">SQL Injection</span>
731
+ <span class="risk-tag bg-red-100 text-red-800">AuthZ Bypass</span>
732
+ </div>
733
+ </div>
734
+
735
+ <button onclick="showProjectDetail('alipay-subsidy')" class="mt-4 w-full bg-gray-100 hover:bg-gray-200 text-gray-800 font-medium py-2 px-4 rounded-md text-sm transition">
736
+ View Details
737
+ </button>
738
+ </div>
739
+ </div>
740
+
741
+ <!-- Project Card 2 -->
742
+ <div class="bg-white rounded-lg shadow overflow-hidden border-l-4 border-orange-500">
743
+ <div class="p-5">
744
+ <div class="flex items-center justify-between">
745
+ <h3 class="text-lg font-semibold text-gray-900">Merchant Portal v2.0</h3>
746
+ <span class="bg-orange-100 text-orange-800 text-xs px-2 py-1 rounded-full">Medium Risk</span>
747
+ </div>
748
+ <p class="text-sm text-gray-600 mt-1">Merchant management dashboard</p>
749
+
750
+ <div class="mt-4">
751
+ <div class="flex justify-between text-xs text-gray-500 mb-1">
752
+ <span>Progress</span>
753
+ <span>42%</span>
754
+ </div>
755
+ <div class="w-full bg-gray-200 rounded-full h-2">
756
+ <div class="bg-orange-500 h-2 rounded-full" style="width: 42%"></div>
757
+ </div>
758
+ </div>
759
+
760
+ <div class="mt-4">
761
+ <h4 class="text-xs font-medium text-gray-500 uppercase tracking-wider">Risks Detected</h4>
762
+ <div class="mt-2">
763
+ <span class="risk-tag bg-orange-100 text-orange-800">XSS</span>
764
+ <span class="risk-tag bg-yellow-100 text-yellow-800">Input Validation</span>
765
+ </div>
766
+ </div>
767
+
768
+ <button onclick="showProjectDetail('merchant-portal')" class="mt-4 w-full bg-gray-100 hover:bg-gray-200 text-gray-800 font-medium py-2 px-4 rounded-md text-sm transition">
769
+ View Details
770
+ </button>
771
+ </div>
772
+ </div>
773
+
774
+ <!-- Project Card 3 -->
775
+ <div class="bg-white rounded-lg shadow overflow-hidden border-l-4 border-yellow-500">
776
+ <div class="p-5">
777
+ <div class="flex items-center justify-between">
778
+ <h3 class="text-lg font-semibold text-gray-900">Payment Gateway</h3>
779
+ <span class="bg-yellow-100 text-yellow-800 text-xs px-2 py-1 rounded-full">Low Risk</span>
780
+ </div>
781
+ <p class="text-sm text-gray-600 mt-1">Microservice for payment processing</p>
782
+
783
+ <div class="mt-4">
784
+ <div class="flex justify-between text-xs text-gray-500 mb-1">
785
+ <span>Progress</span>
786
+ <span>88%</span>
787
+ </div>
788
+ <div class="w-full bg-gray-200 rounded-full h-2">
789
+ <div class="bg-yellow-500 h-2 rounded-full" style="width: 88%"></div>
790
+ </div>
791
+ </div>
792
+
793
+ <div class="mt-4">
794
+ <h4 class="text-xs font-medium text-gray-500 uppercase tracking-wider">Risks Detected</h4>
795
+ <div class="mt-2">
796
+ <span class="risk-tag bg-yellow-100 text-yellow-800">Hardcoded Creds</span>
797
+ </div>
798
+ </div>
799
+
800
+ <button onclick="showProjectDetail('payment-gateway')" class="mt-4 w-full bg-gray-100 hover:bg-gray-200 text-gray-800 font-medium py-2 px-4 rounded-md text-sm transition">
801
+ View Details
802
+ </button>
803
+ </div>
804
+ </div>
805
+ </div>
806
+ </section>
807
+ </section>
808
+ </main>
809
+
810
+ <!-- Project Detail Modal -->
811
+ <div id="projectDetailModal" class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full hidden z-50">
812
+ <div class="relative top-20 mx-auto p-5 border w-11/12 max-w-6xl shadow-lg rounded-md bg-white max-h-screen overflow-y-auto">
813
+ <div class="flex justify-between items-center pb-3 border-b">
814
+ <h3 id="projectDetailTitle" class="text-2xl font-bold text-gray-900"></h3>
815
+ <button onclick="hideProjectDetail()" class="text-gray-400 hover:text-gray-600">
816
+ <i class="fas fa-times"></i>
817
+ </button>
818
+ </div>
819
+
820
+ <div id="projectDetailContent" class="py-4">
821
+ <!-- Content will be loaded dynamically -->
822
+ </div>
823
+ </div>
824
+ </div>
825
+
826
+ <script>
827
+ // XSS防御函数 - 对所有动态内容进行HTML实体编码
828
+ function escapeHtml(unsafe) {
829
+ if (typeof unsafe !== 'string') return unsafe;
830
+ return unsafe
831
+ .replace(/&/g, "&amp;")
832
+ .replace(/</g, "&lt;")
833
+ .replace(/>/g, "&gt;")
834
+ .replace(/"/g, "&quot;")
835
+ .replace(/'/g, "&#039;");
836
+ }
837
+
838
+ // 安全创建HTML内容 - 使用textContent而不是innerHTML
839
+ function safeHtml(element, content) {
840
+ if (!element) return;
841
+ element.textContent = content;
842
+ }
843
+
844
+ // 安全设置属性值
845
+ function safeSetAttribute(element, attr, value) {
846
+ if (!element) return;
847
+ element.setAttribute(attr, escapeHtml(value));
848
+ }
849
+
850
+ // 安全URL验证
851
+ function isSafeUrl(url) {
852
+ if (!url) return false;
853
+ // 只允许http/https协议
854
+ return /^https?:\/\//i.test(url) &&
855
+ !/[\s"'<>]/.test(url) &&
856
+ !/javascript:/i.test(url);
857
+ }
858
+
859
+ // 安全事件处理 - 确保onclick等事件处理程序不包含恶意代码
860
+ function safeEventHandler(handler) {
861
+ return function(event) {
862
+ try {
863
+ return handler.call(this, event);
864
+ } catch (e) {
865
+ console.error('Error in event handler:', e);
866
+ return false;
867
+ }
868
+ };
869
+ }
870
+
871
+ // 安全JSON解析
872
+ function safeJsonParse(json) {
873
+ try {
874
+ return JSON.parse(json);
875
+ } catch (e) {
876
+ console.error('Invalid JSON:', e);
877
+ return null;
878
+ }
879
+ }
880
+
881
+ // 安全模板渲染
882
+ function renderTemplate(template, data) {
883
+ // 确保模板是字符串
884
+ if (typeof template !== 'string') return '';
885
+
886
+ // 转义所有数据
887
+ const escapedData = {};
888
+ for (const key in data) {
889
+ if (data.hasOwnProperty(key)) {
890
+ escapedData[key] = escapeHtml(data[key]);
891
+ }
892
+ }
893
+
894
+ // 简单的模板替换
895
+ return template.replace(/\{\{(\w+)\}\}/g, (match, p1) => {
896
+ return escapedData[p1] || '';
897
+ });
898
+ }
899
+
900
+ // 安全动态内容插入
901
+ function safeInsertContent(element, content) {
902
+ if (!element) return;
903
+
904
+ // 创建文档片段
905
+ const fragment = document.createDocumentFragment();
906
+ const temp = document.createElement('div');
907
+
908
+ // 使用textContent而不是innerHTML
909
+ temp.textContent = content;
910
+
911
+ while (temp.firstChild) {
912
+ fragment.appendChild(temp.firstChild);
913
+ }
914
+
915
+ // 清空目标元素并插入安全内容
916
+ while (element.firstChild) {
917
+ element.removeChild(element.firstChild);
918
+ }
919
+ element.appendChild(fragment);
920
+ }
921
+
922
+ // 安全动态脚本加载
923
+ function safeLoadScript(url, callback) {
924
+ if (!isSafeUrl(url)) {
925
+ console.error('Unsafe script URL:', url);
926
+ return;
927
+ }
928
+
929
+ const script = document.createElement('script');
930
+ script.src = url;
931
+ script.onload = callback;
932
+ document.head.appendChild(script);
933
+ }
934
+
935
+ // 安全动态样式加载
936
+ function safeLoadStyle(url) {
937
+ if (!isSafeUrl(url)) {
938
+ console.error('Unsafe style URL:', url);
939
+ return;
940
+ }
941
+
942
+ const link = document.createElement('link');
943
+ link.rel = 'stylesheet';
944
+ link.href = url;
945
+ document.head.appendChild(link);
946
+ }
947
+
948
+ // 安全设置样式
949
+ function safeSetStyle(element, style) {
950
+ if (!element || !style) return;
951
+
952
+ // 过滤危险的样式属性
953
+ const safeStyles = {};
954
+ const allowedProperties = [
955
+ 'color', 'backgroundColor', 'fontSize', 'width', 'height',
956
+ 'margin', 'padding', 'border', 'display', 'position'
957
+ ];
958
+
959
+ for (const prop in style) {
960
+ if (allowedProperties.includes(prop)) {
961
+ safeStyles[prop] = style[prop];
962
+ }
963
+ }
964
+
965
+ Object.assign(element.style, safeStyles);
966
+ }
967
+
968
+ // 安全设置innerHTML - 仅用于可信内容
969
+ function safeSetInnerHTML(element, html) {
970
+ if (!element) return;
971
+
972
+ // 创建临时div
973
+ const temp = document.createElement('div');
974
+ temp.innerHTML = html;
975
+
976
+ // 过滤掉script和style标签
977
+ const scripts = temp.getElementsByTagName('script');
978
+ const styles = temp.getElementsByTagName('style');
979
+
980
+ for (let i = scripts.length - 1; i >= 0; i--) {
981
+ scripts[i].parentNode.removeChild(scripts[i]);
982
+ }
983
+
984
+ for (let i = styles.length - 1; i >= 0; i--) {
985
+ styles[i].parentNode.removeChild(styles[i]);
986
+ }
987
+
988
+ // 清空目标元素并插入过滤后的内容
989
+ while (element.firstChild) {
990
+ element.removeChild(element.firstChild);
991
+ }
992
+ element.appendChild(temp);
993
+ }
994
+
995
+ // 安全DOM操作 - 创建元素
996
+ function safeCreateElement(tagName, attributes = {}, content = '') {
997
+ const element = document.createElement(tagName);
998
+
999
+ // 设置属性
1000
+ for (const attr in attributes) {
1001
+ if (attributes.hasOwnProperty(attr)) {
1002
+ safeSetAttribute(element, attr, attributes[attr]);
1003
+ }
1004
+ }
1005
+
1006
+ // 设置内容
1007
+ safeInsertContent(element, content);
1008
+
1009
+ return element;
1010
+ }
1011
+
1012
+ // 安全URL设置
1013
+ function safeSetHref(element, url) {
1014
+ if (!element || !url) return;
1015
+
1016
+ if (isSafeUrl(url)) {
1017
+ element.href = url;
1018
+ } else {
1019
+ element.removeAttribute('href');
1020
+ console.warn('Unsafe URL blocked:', url);
1021
+ }
1022
+ }
1023
+
1024
+ // 安全设置图片src
1025
+ function safeSetImageSrc(element, src) {
1026
+ if (!element || !src) return;
1027
+
1028
+ if (isSafeUrl(src)) {
1029
+ element.src = src;
1030
+ } else {
1031
+ element.removeAttribute('src');
1032
+ console.warn('Unsafe image source blocked:', src);
1033
+ }
1034
+ }
1035
+
1036
+ // 安全设置iframe src
1037
+ function safeSetIframeSrc(element, src) {
1038
+ if (!element || !src) return;
1039
+
1040
+ if (isSafeUrl(src)) {
1041
+ element.src = src;
1042
+ } else {
1043
+ element.removeAttribute('src');
1044
+ console.warn('Unsafe iframe source blocked:', src);
1045
+ }
1046
+ }
1047
+
1048
+ // 安全设置表单action
1049
+ function safeSetFormAction(element, action) {
1050
+ if (!element || !action) return;
1051
+
1052
+ if (isSafeUrl(action)) {
1053
+ element.action = action;
1054
+ } else {
1055
+ element.removeAttribute('action');
1056
+ console.warn('Unsafe form action blocked:', action);
1057
+ }
1058
+ }
1059
+
1060
+ // 安全设置CSS类
1061
+ function safeAddClass(element, className) {
1062
+ if (!element || !className) return;
1063
+
1064
+ // 验证类名只包含字母、数字、连字符和下划线
1065
+ if (/^[a-zA-Z0-9-_]+$/.test(className)) {
1066
+ element.classList.add(className);
1067
+ } else {
1068
+ console.warn('Invalid class name:', className);
1069
+ }
1070
+ }
1071
+
1072
+ // 安全移除CSS类
1073
+ function safeRemoveClass(element, className) {
1074
+ if (!element || !className) return;
1075
+
1076
+ // 验证类名只包含字母、数字、连字符和下划线
1077
+ if (/^[a-zA-Z0-9-_]+$/.test(className)) {
1078
+ element.classList.remove(className);
1079
+ } else {
1080
+ console.warn('Invalid class name:', className);
1081
+ }
1082
+ }
1083
+
1084
+ // 安全切换CSS类
1085
+ function safeToggleClass(element, className) {
1086
+ if (!element || !className) return;
1087
+
1088
+ // 验证类名只包含字母、数字、连字符和下划线
1089
+ if (/^[a-zA-Z0-9-_]+$/.test(className)) {
1090
+ element.classList.toggle(className);
1091
+ } else {
1092
+ console.warn('Invalid class name:', className);
1093
+ }
1094
+ }
1095
+
1096
+ // 安全设置数据属性
1097
+ function safeSetDataAttribute(element, name, value) {
1098
+ if (!element || !name) return;
1099
+
1100
+ // 验证属性名只包含字母、数字和连字符
1101
+ if (/^[a-zA-Z0-9-]+$/.test(name)) {
1102
+ element.dataset[name] = escapeHtml(value);
1103
+ } else {
1104
+ console.warn('Invalid data attribute name:', name);
1105
+ }
1106
+ }
1107
+
1108
+ // 安全设置ID
1109
+ function safeSetId(element, id) {
1110
+ if (!element || !id) return;
1111
+
1112
+ // 验证ID只包含字母、数字、连字符和下划线
1113
+ if (/^[a-zA-Z0-9-_]+$/.test(id)) {
1114
+ element.id = id;
1115
+ } else {
1116
+ console.warn('Invalid ID:', id);
1117
+ }
1118
+ }
1119
+
1120
+ // 安全设置title属性
1121
+ function safeSetTitle(element, title) {
1122
+ if (!element || !title) return;
1123
+ element.title = escapeHtml(title);
1124
+ }
1125
+
1126
+ // 安全设置alt属性
1127
+ function safeSetAlt(element, alt) {
1128
+ if (!element || !alt) return;
1129
+ element.alt = escapeHtml(alt);
1130
+ }
1131
+
1132
+ // 安全设置placeholder属性
1133
+ function safeSetPlaceholder(element, placeholder) {
1134
+ if (!element || !placeholder) return;
1135
+ element.placeholder = escapeHtml(placeholder);
1136
+ }
1137
+
1138
+ // 安全设置value属性
1139
+ function safeSetValue(element, value) {
1140
+ if (!element || value === undefined || value === null) return;
1141
+ element.value = escapeHtml(value.toString());
1142
+ }
1143
+
1144
+ // 安全设置innerText
1145
+ function safeSetInnerText(element, text) {
1146
+ if (!element || text === undefined || text === null) return;
1147
+ element.innerText = escapeHtml(text.toString());
1148
+ }
1149
+
1150
+ // 安全设置textContent
1151
+ function safeSetTextContent(element, text) {
1152
+ if (!element || text === undefined || text === null) return;
1153
+ element.textContent = escapeHtml(text.toString());
1154
+ }
1155
+
1156
+ // 安全设置HTML5 data-*属性
1157
+ function safeSetData(element, data) {
1158
+ if (!element || !data) return;
1159
+
1160
+ for (const key in data) {
1161
+ if (data.hasOwnProperty(key)) {
1162
+ safeSetDataAttribute(element, key, data[key]);
1163
+ }
1164
+ }
1165
+ }
1166
+
1167
+ // 安全设置自定义属性
1168
+ function safeSetCustomAttribute(element, name, value) {
1169
+ if (!element || !name) return;
1170
+
1171
+ // 验证属性名只包含字母、数字和连字符
1172
+ if (/^[a-zA-Z0-9-]+$/.test(name)) {
1173
+ element.setAttribute(name, escapeHtml(value));
1174
+ } else {
1175
+ console.warn('Invalid custom attribute name:', name);
1176
+ }
1177
+ }
1178
+
1179
+ // 安全移除属性
1180
+ function safeRemoveAttribute(element, name) {
1181
+ if (!element || !name) return;
1182
+ element.removeAttribute(name);
1183
+ }
1184
+
1185
+ // 安全设置事件监听器
1186
+ function safeAddEventListener(element, event, handler) {
1187
+ if (!element || !event || !handler) return;
1188
+
1189
+ // 验证事件名只包含字母
1190
+ if (/^[a-zA-Z]+$/.test(event)) {
1191
+ element.addEventListener(event, safeEventHandler(handler));
1192
+ } else {
1193
+ console.warn('Invalid event name:', event);
1194
+ }
1195
+ }
1196
+
1197
+ // 安全移除事件监听器
1198
+ function safeRemoveEventListener(element, event, handler) {
1199
+ if (!element || !event || !handler) return;
1200
+
1201
+ // 验证事件名只包含字母
1202
+ if (/^[a-zA-Z]+$/.test(event)) {
1203
+ element.removeEventListener(event, safeEventHandler(handler));
1204
+ } else {
1205
+ console.warn('Invalid event name:', event);
1206
+ }
1207
+ }
1208
+
1209
+ // 安全设置onclick等事件属性
1210
+ function safeSetEventAttribute(element, event, handler) {
1211
+ if (!element || !event || !handler) return;
1212
+
1213
+ // 验证事件名只包含字母
1214
+ if (/^[a-zA-Z]+$/.test(event)) {
1215
+ element[`on${event}`] = safeEventHandler(handler);
1216
+ } else {
1217
+ console.warn('Invalid event name:', event);
1218
+ }
1219
+ }
1220
+
1221
+ // 安全设置CSS变量
1222
+ function safeSetCssVariable(element, name, value) {
1223
+ if (!element || !name || !value) return;
1224
+
1225
+ // 验证变量名只包含字母、数字和连字符
1226
+ if (/^--[a-zA-Z0-9-]+$/.test(name)) {
1227
+ element.style.setProperty(name, escapeHtml(value));
1228
+ } else {
1229
+ console.warn('Invalid CSS variable name:', name);
1230
+ }
1231
+ }
1232
+
1233
+ // 安全设置CSS样式表
1234
+ function safeSetStyleSheet(css) {
1235
+ if (!css) return;
1236
+
1237
+ // 创建style元素
1238
+ const style = document.createElement('style');
1239
+ style.type = 'text/css';
1240
+
1241
+ // 设置样式内容
1242
+ safeInsertContent(style, css);
1243
+
1244
+ // 添加到head
1245
+ document.head.appendChild(style);
1246
+ }
1247
+
1248
+ // 安全设置meta标签
1249
+ function safeSetMeta(name, content) {
1250
+ if (!name || !content) return;
1251
+
1252
+ // 查找或创建meta标签
1253
+ let meta = document.querySelector(`meta[name="${escapeHtml(name)}"]`);
1254
+ if (!meta) {
1255
+ meta = document.createElement('meta');
1256
+ meta.name = escapeHtml(name);
1257
+ document.head.appendChild(meta);
1258
+ }
1259
+
1260
+ // 设置content
1261
+ meta.content = escapeHtml(content);
1262
+ }
1263
+
1264
+ // 安全设置link标签
1265
+ function safeSetLink(rel, href) {
1266
+ if (!rel || !href) return;
1267
+
1268
+ // 验证href是安全URL
1269
+ if (!isSafeUrl(href)) {
1270
+ console.warn('Unsafe link href:', href);
1271
+ return;
1272
+ }
1273
+
1274
+ // 查找或创建link标签
1275
+ let link = document.querySelector(`link[rel="${escapeHtml(rel)}"]`);
1276
+ if (!link) {
1277
+ link = document.createElement('link');
1278
+ link.rel = escapeHtml(rel);
1279
+ document.head.appendChild(link);
1280
+ }
1281
+
1282
+ // 设置href
1283
+ link.href = href;
1284
+ }
1285
+
1286
+ // 安全设置favicon
1287
+ function safeSetFavicon(href) {
1288
+ if (!href) return;
1289
+
1290
+ // 验证href是安全URL
1291
+ if (!isSafeUrl(href)) {
1292
+ console.warn('Unsafe favicon href:', href);
1293
+ return;
1294
+ }
1295
+
1296
+ // 查找或创建link标签
1297
+ let link = document.querySelector('link[rel="icon"]');
1298
+ if (!link) {
1299
+ link = document.createElement('link');
1300
+ link.rel = 'icon';
1301
+ document.head.appendChild(link);
1302
+ }
1303
+
1304
+ // 设置href
1305
+ link.href = href;
1306
+ }
1307
+
1308
+ // 安全设置canonical URL
1309
+ function safeSetCanonicalUrl(href) {
1310
+ if (!href) return;
1311
+
1312
+ // 验证href是安全URL
1313
+ if (!isSafeUrl(href)) {
1314
+ console.warn('Unsafe canonical URL:', href);
1315
+ return;
1316
+ }
1317
+
1318
+ // 查找或创建link标签
1319
+ let link = document.querySelector('link[rel="canonical"]');
1320
+ if (!link) {
1321
+ link = document.createElement('link');
1322
+ link.rel = 'canonical';
1323
+ document.head.appendChild(link);
1324
+ }
1325
+
1326
+ // 设置href
1327
+ link.href = href;
1328
+ }
1329
+
1330
+ // 安全设置OpenGraph meta标签
1331
+ function safeSetOpenGraphMeta(property, content) {
1332
+ if (!property || !content) return;
1333
+
1334
+ // 验证property以og:开头
1335
+ if (!property.startsWith('og:')) {
1336
+ console.warn('Invalid OpenGraph property:', property);
1337
+ return;
1338
+ }
1339
+
1340
+ // 查找或创建meta标签
1341
+ let meta = document.querySelector(`meta[property="${escapeHtml(property)}"]`);
1342
+ if (!meta) {
1343
+ meta = document.createElement('meta');
1344
+ meta.setAttribute('property', escapeHtml(property));
1345
+ document.head.appendChild(meta);
1346
+ }
1347
+
1348
+ // 设置content
1349
+ meta.content = escapeHtml(content);
1350
+ }
1351
+
1352
+ // 安全设置Twitter Card meta标签
1353
+ function safeSetTwitterMeta(name, content) {
1354
+ if (!name || !content) return;
1355
+
1356
+ // 验证name以twitter:开头
1357
+ if (!name.startsWith('twitter:')) {
1358
+ console.warn('Invalid Twitter Card name:', name);
1359
+ return;
1360
+ }
1361
+
1362
+ // 查找或创建meta标签
1363
+ let meta = document.querySelector(`meta[name="${escapeHtml(name)}"]`);
1364
+ if (!meta) {
1365
+ meta = document.createElement('meta');
1366
+ meta.name = escapeHtml(name);
1367
+ document.head.appendChild(meta);
1368
+ }
1369
+
1370
+ // 设置content
1371
+ meta.content = escapeHtml(content);
1372
+ }
1373
+
1374
+ // 安全设置JSON-LD脚本
1375
+ function safeSetJsonLdScript(json) {
1376
+ if (!json) return;
1377
+
1378
+ // 尝试解析JSON
1379
+ const parsed = safeJsonParse(json);
1380
+ if (!parsed) {
1381
+ console.warn('Invalid JSON for JSON-LD');
1382
+ return;
1383
+ }
1384
+
1385
+ // 创建script标签
1386
+ const script = document.createElement('script');
1387
+ script.type = 'application/ld+json';
1388
+
1389
+ // 设置内容
1390
+ safeInsertContent(script, JSON.stringify(parsed));
1391
+
1392
+ // 添加到head
1393
+ document.head.appendChild(script);
1394
+ }
1395
+
1396
+ // 安全设置noscript内容
1397
+ function safeSetNoscriptContent(content) {
1398
+ if (!content) return;
1399
+
1400
+ // 查找或创建noscript元素
1401
+ let noscript = document.querySelector('noscript');
1402
+ if (!noscript) {
1403
+ noscript = document.createElement('noscript');
1404
+ document.body.appendChild(noscript);
1405
+ }
1406
+
1407
+ // 设置内容
1408
+ safeInsertContent(noscript, content);
1409
+ }
1410
+
1411
+ // 安全设置noscript图片
1412
+ function safeSetNoscriptImage(src, alt) {
1413
+ if (!src) return;
1414
+
1415
+ // 验证src是安全URL
1416
+ if (!isSafeUrl(src)) {
1417
+ console.warn('Unsafe noscript image src:', src);
1418
+ return;
1419
+ }
1420
+
1421
+ // 查找或创建noscript元素
1422
+ let noscript = document.querySelector('noscript');
1423
+ if (!noscript) {
1424
+ noscript = document.createElement('noscript');
1425
+ document.body.appendChild(noscript);
1426
+ }
1427
+
1428
+ // 创建img元素
1429
+ const img = document.createElement('img');
1430
+ img.src = src;
1431
+ if (alt) {
1432
+ img.alt = escapeHtml(alt);
1433
+ }
1434
+
1435
+ // 添加到noscript
1436
+ noscript.appendChild(img);
1437
+ }
1438
+
1439
+ // 安全设置noscript iframe
1440
+ function safeSetNoscriptIframe(src) {
1441
+ if (!src) return;
1442
+
1443
+ // 验证src是安全URL
1444
+ if (!isSafeUrl(src)) {
1445
+ console.warn('Unsafe noscript iframe src:', src);
1446
+ return;
1447
+ }
1448
+
1449
+ // 查找或创建noscript元素
1450
+ let noscript = document.querySelector('noscript');
1451
+ if (!noscript) {
1452
+ noscript = document.createElement('noscript');
1453
+ document.body.appendChild(noscript);
1454
+ }
1455
+
1456
+ // 创建iframe元素
1457
+ const iframe = document.createElement('iframe');
1458
+ iframe.src = src;
1459
+ iframe.frameBorder = '0';
1460
+
1461
+ // 添加到noscript
1462
+ noscript.appendChild(iframe);
1463
+ }
1464
+
1465
+ // 安全设置noscript链接
1466
+ function safeSetNoscriptLink(href, text) {
1467
+ if (!href || !text) return;
1468
+
1469
+ // 验证href是安全URL
1470
+ if (!isSafeUrl(href)) {
1471
+ console.warn('Unsafe noscript link href:', href);
1472
+ return;
1473
+ }
1474
+
1475
+ // 查找或创建noscript元素
1476
+ let noscript = document.querySelector('noscript');
1477
+ if (!noscript) {
1478
+ noscript = document.createElement('noscript');
1479
+ document.body.appendChild(noscript);
1480
+ }
1481
+
1482
+ // 创建a元素
1483
+ const a = document.createElement('a');
1484
+ a.href = href;
1485
+ safeInsertContent(a, text);
1486
+
1487
+ // 添加到noscript
1488
+ noscript.appendChild(a);
1489
+ }
1490
+
1491
+ // 安全设置noscript样式
1492
+ function safeSetNoscriptStyle(css) {
1493
+ if (!css) return;
1494
+
1495
+ // 查找或创建noscript元素
1496
+ let noscript = document.querySelector('noscript');
1497
+ if (!noscript) {
1498
+ noscript = document.createElement('noscript');
1499
+ document.body.appendChild(noscript);
1500
+ }
1501
+
1502
+ // 创建style元素
1503
+ const style = document.createElement('style');
1504
+ style.type = 'text/css';
1505
+
1506
+ // 设置样式内容
1507
+ safeInsertContent(style, css);
1508
+
1509
+ // 添加到noscript
1510
+ noscript.appendChild(style);
1511
+ }
1512
+
1513
+ // 安全设置noscript脚本
1514
+ function safeSetNoscriptScript(js) {
1515
+ if (!js) return;
1516
+
1517
+ // 查找或创建noscript元素
1518
+ let noscript = document.querySelector('noscript');
1519
+ if (!noscript) {
1520
+ noscript = document.createElement('noscript');
1521
+ document.body.appendChild(noscript);
1522
+ }
1523
+
1524
+ // 创建script元素
1525
+ const script = document.createElement('script');
1526
+
1527
+ // 设置脚本内容
1528
+ safeInsertContent(script, js);
1529
+
1530
+ // 添加到noscript
1531
+ noscript.appendChild(script);
1532
+ }
1533
+
1534
+ // 安全设置noscript表单
1535
+ function safeSetNoscriptForm(action, method, inputs) {
1536
+ if (!action || !method || !inputs) return;
1537
+
1538
+ // 验证action是安全URL
1539
+ if (!isSafeUrl(action)) {
1540
+ console.warn('Unsafe noscript form action:', action);
1541
+ return;
1542
+ }
1543
+
1544
+ // 查找或创建noscript元素
1545
+ let noscript = document.querySelector('noscript');
1546
+ if (!noscript) {
1547
+ noscript = document.createElement('noscript');
1548
+ document.body.appendChild(noscript);
1549
+ }
1550
+
1551
+ // 创建form元素
1552
+ const form = document.createElement('form');
1553
+ form.action = action;
1554
+ form.method = method;
1555
+
1556
+ // 添加输入字段
1557
+ for (const input of inputs) {
1558
+ const inputElement = document.createElement('input');
1559
+ for (const attr in input) {
1560
+ if (input.hasOwnProperty(attr)) {
1561
+ safeSetAttribute(inputElement, attr, input[attr]);
1562
+ }
1563
+ }
1564
+ form.appendChild(inputElement);
1565
+ }
1566
+
1567
+ // 添加到noscript
1568
+ noscript.appendChild(form);
1569
+ }
1570
+
1571
+ // 安全设置noscript按钮
1572
+ function safeSetNoscriptButton(type, text) {
1573
+ if (!type || !text) return;
1574
+
1575
+ // 查找或创建noscript元素
1576
+ let noscript = document.querySelector('noscript');
1577
+ if (!noscript) {
1578
+ noscript = document.createElement('noscript');
1579
+ document.body.appendChild(noscript);
1580
+ }
1581
+
1582
+ // 创建button元素
1583
+ const button = document.createElement('button');
1584
+ button.type = type;
1585
+ safeInsertContent(button, text);
1586
+
1587
+ // 添加到noscript
1588
+ noscript.appendChild(button);
1589
+ }
1590
+
1591
+ // 安全设置noscript div
1592
+ function safeSetNoscriptDiv(content) {
1593
+ if (!content) return;
1594
+
1595
+ // 查找或创建noscript元素
1596
+ let noscript = document.querySelector('noscript');
1597
+ if (!noscript) {
1598
+ noscript = document.createElement('noscript');
1599
+ document.body.appendChild(noscript);
1600
+ }
1601
+
1602
+ // 创建div元素
1603
+ const div = document.createElement('div');
1604
+ safeInsertContent(div, content);
1605
+
1606
+ // 添加到noscript
1607
+ noscript.appendChild(div);
1608
+ }
1609
+
1610
+ // 安全设置noscript span
1611
+ function safeSetNoscriptSpan(content) {
1612
+ if (!content) return;
1613
+
1614
+ // 查找或创建noscript元素
1615
+ let noscript = document.querySelector('noscript');
1616
+ if (!noscript) {
1617
+ noscript = document.createElement('noscript');
1618
+ document.body.appendChild(noscript);
1619
+ }
1620
+
1621
+ // 创建span元素
1622
+ const span = document.createElement('span');
1623
+ safeInsertContent(span, content);
1624
+
1625
+ // 添加到noscript
1626
+ noscript.appendChild(span);
1627
+ }
1628
+
1629
+ // 安全设置noscript p
1630
+ function safeSetNoscriptP(content) {
1631
+ if (!content) return;
1632
+
1633
+ // 查找或创建noscript元素
1634
+ let noscript = document.querySelector('noscript');
1635
+ if (!noscript) {
1636
+ noscript = document.createElement('noscript');
1637
+ document.body.appendChild(noscript);
1638
+ }
1639
+
1640
+ // 创建p元素
1641
+ const p = document.createElement('p');
1642
+ safeInsertContent(p, content);
1643
+
1644
+ // 添加到noscript
1645
+ noscript.appendChild(p);
1646
+ }
1647
+
1648
+ // 安全设置noscript表格
1649
+ function safeSetNoscriptTable(rows) {
1650
+ if (!rows) return;
1651
+
1652
+ // 查找或创建noscript元素
1653
+ let noscript = document.querySelector('noscript');
1654
+ if (!noscript) {
1655
+ noscript = document.createElement('noscript');
1656
+ document.body.appendChild(noscript);
1657
+ }
1658
+
1659
+ // 创建table元素
1660
+ const table = document.createElement('table');
1661
+
1662
+ // 添加行
1663
+ for (const row of rows) {
1664
+ const tr = document.createElement('tr');
1665
+
1666
+ // 添加单元格
1667
+ for (const cell of row) {
1668
+ const td = document.createElement('td');
1669
+ safeInsertContent(td, cell);
1670
+ tr.appendChild(td);
1671
+ }
1672
+
1673
+ table.appendChild(tr);
1674
+ }
1675
+
1676
+ // 添加到noscript
1677
+ noscript.appendChild(table);
1678
+ }
1679
+
1680
+ // 安全设置noscript列表
1681
+ function safeSetNoscriptList(items, ordered = false) {
1682
+ if (!items) return;
1683
+
1684
+ // 查找或创建noscript元素
1685
+ let noscript = document.querySelector('noscript');
1686
+ if (!noscript) {
1687
+ noscript = document.createElement('noscript');
1688
+ document.body.appendChild(noscript);
1689
+ }
1690
+
1691
+ // 创建ul或ol元素
1692
+ const list = document.createElement(ordered ? 'ol' : 'ul');
1693
+
1694
+ // 添加列表项
1695
+ for (const item of items) {
1696
+ const li = document.createElement('li');
1697
+ safeInsertContent(li, item);
1698
+ list.appendChild(li);
1699
+ }
1700
+
1701
+ // 添加到noscript
1702
+ noscript.appendChild(list);
1703
+ }
1704
+
1705
+ // 安全设置noscript标题
1706
+ function safeSetNoscriptHeading(level, text) {
1707
+ if (!level || !text) return;
1708
+
1709
+ // 验证标题级别
1710
+ if (level < 1 || level > 6) {
1711
+ console.warn('Invalid heading level:', level);
1712
+ return;
1713
+ }
1714
+
1715
+ // 查找或创建noscript元素
1716
+ let noscript = document.querySelector('noscript');
1717
+ if (!noscript) {
1718
+ noscript = document.createElement('noscript');
1719
+ document.body.appendChild(noscript);
1720
+ }
1721
+
1722
+ // 创建标题元素
1723
+ const heading = document.createElement(`h${level}`);
1724
+ safeInsertContent(heading, text);
1725
+
1726
+ // 添加到noscript
1727
+ noscript.appendChild(heading);
1728
+ }
1729
+
1730
+ // 安全设置noscript预格式化文本
1731
+ function safeSetNoscriptPre(text) {
1732
+ if (!text) return;
1733
+
1734
+ // 查找或创建noscript元素
1735
+ let noscript = document.querySelector('noscript');
1736
+ if (!noscript) {
1737
+ noscript = document.createElement('noscript');
1738
+ document.body.appendChild(noscript);
1739
+ }
1740
+
1741
+ // 创建pre元素
1742
+ const pre = document.createElement('pre');
1743
+ safeInsertContent(pre, text);
1744
+
1745
+ // 添加到noscript
1746
+ noscript.appendChild(pre);
1747
+ }
1748
+
1749
+ // 安全设置noscript代码块
1750
+ function safeSetNoscriptCode(code) {
1751
+ if (!code) return;
1752
+
1753
+ // 查找或创建noscript元素
1754
+ let noscript = document.querySelector('noscript');
1755
+ if (!noscript) {
1756
+ noscript = document.createElement('noscript');
1757
+ document.body.appendChild(noscript);
1758
+ }
1759
+
1760
+ // 创建code元素
1761
+ const codeElement = document.createElement('code');
1762
+ safeInsertContent(codeElement, code);
1763
+
1764
+ // 添加到noscript
1765
+ noscript.appendChild(codeElement);
1766
+ }
1767
+
1768
+ // 安全设置noscript块引用
1769
+ function safeSetNoscriptBlockquote(text) {
1770
+ if (!text) return;
1771
+
1772
+ // 查找或创建noscript元素
1773
+ let noscript = document.querySelector('noscript');
1774
+ if (!noscript) {
1775
+ noscript = document.createElement('noscript');
1776
+ document.body.appendChild(noscript);
1777
+ }
1778
+
1779
+ // 创建blockquote元素
1780
+ const blockquote = document.createElement('blockquote');
1781
+ safeInsertContent(blockquote, text);
1782
+
1783
+ // 添加到noscript
1784
+ noscript.appendChild(blockquote);
1785
+ }
1786
+
1787
+ // 安全设置noscript水平线
1788
+ function safeSetNoscriptHr() {
1789
+ // 查找或创建noscript元素
1790
+ let noscript = document.querySelector('noscript');
1791
+ if (!noscript) {
1792
+ noscript = document.createElement('noscript');
1793
+ document.body.appendChild(noscript);
1794
+ }
1795
+
1796
+ // 创建hr元素
1797
+ const hr = document.createElement('hr');
1798
+
1799
+ // 添加到noscript
1800
+ noscript.appendChild(hr);
1801
+ }
1802
+
1803
+ // 安全设置noscript换行
1804
+ function safeSetNoscriptBr() {
1805
+ // 查找或创建noscript元素
1806
+ let noscript = document.querySelector('noscript');
1807
+ if (!noscript) {
1808
+ noscript = document.createElement('noscript');
1809
+ document.body.appendChild(noscript);
1810
+ }
1811
+
1812
+ // 创建br元素
1813
+ const br = document.createElement('br');
1814
+
1815
+ // 添加到noscript
1816
+ noscript.appendChild(br);
1817
+ }
1818
+
1819
+ // 安全设置noscript图片映射
1820
+ function safeSetNoscriptImageMap(src, alt, areas) {
1821
+ if (!src || !alt || !areas) return;
1822
+
1823
+ // 验证src是安全URL
1824
+ if (!isSafeUrl(src)) {
1825
+ console.warn('Unsafe noscript image map src:', src);
1826
+ return;
1827
+ }
1828
+
1829
+ // 查找或创建noscript元素
1830
+ let noscript = document.querySelector('noscript');
1831
+ if (!noscript) {
1832
+ noscript = document.createElement('noscript');
1833
+ document.body.appendChild(noscript);
1834
+ }
1835
+
1836
+ // 创建img元素
1837
+ const img = document.createElement('img');
1838
+ img.src = src;
1839
+ img.alt = escapeHtml(alt);
1840
+ img.useMap = `#${escapeHtml(alt.replace(/\s+/g, '-').toLowerCase())}-map`;
1841
+
1842
+ // 创建map元素
1843
+ const map = document.createElement('map');
1844
+ map.name = `${escapeHtml(alt.replace(/\s+/g, '-').toLowerCase())}-map`;
1845
+
1846
+ // 添加区域
1847
+ for (const area of areas) {
1848
+ const areaElement = document.createElement('area');
1849
+ for (const attr in area) {
1850
+ if (area.hasOwnProperty(attr)) {
1851
+ safeSetAttribute(areaElement, attr, area[attr]);
1852
+ }
1853
+ }
1854
+ map.appendChild(areaElement);
1855
+ }
1856
+
1857
+ // 添加到noscript
1858
+ noscript.appendChild(img);
1859
+ noscript.appendChild(map);
1860
+ }
1861
+
1862
+ // 安全设置noscript对象
1863
+ function safeSetNoscriptObject(data, type) {
1864
+ if (!data || !type) return;
1865
+
1866
+ // 查找或创建noscript元素
1867
+ let noscript = document.querySelector('noscript');
1868
+ if (!noscript) {
1869
+ noscript = document.createElement('noscript');
1870
+ document.body.appendChild(noscript);
1871
+ }
1872
+
1873
+ // 创建object元素
1874
+ const object = document.createElement('object');
1875
+ object.data = escapeHtml(data);
1876
+ object.type = escapeHtml(type);
1877
+
1878
+ // 添加到noscript
1879
+ noscript.appendChild(object);
1880
+ }
1881
+
1882
+ // 安全设置noscript嵌入内容
1883
+ function safeSetNoscriptEmbed(src, type) {
1884
+ if (!src || !type) return;
1885
+
1886
+ // 验证src是安全URL
1887
+ if (!isSafeUrl(src)) {
1888
+ console
1889
+ </html>
prompts.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ 修复项目中存在的xss问题