mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-15 08:18:42 +01:00
admin: escape dynamic text in S3 bucket modals (#12625)
admin: escape dynamic text in bucket modals
This commit is contained in:
1 parent
d685709832
commit
4bc7598a43
3 files changed
+28
-8
No files matched your search
@@ -33,6 +33,26 @@ func TestAdminDashboardShowsDiskUsage(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestS3BucketModalsEscapeDynamicHTMLText(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
if err := S3Buckets(dash.S3BucketsData{}).Render(context.Background(), &buf); err != nil {
|
||||
t.Fatalf("render bucket page: %v", err)
|
||||
}
|
||||
|
||||
for _, want := range []string{
|
||||
"Bucket Details - ' + escapeHtml(bucketName)",
|
||||
"Lifecycle - ' + escapeHtml(bucketName)",
|
||||
"Error loading bucket details: ' + escapeHtml(data.error)",
|
||||
"Error loading bucket details: ' + escapeHtml(error.message)",
|
||||
"Error loading lifecycle rules: ' + escapeHtml(data.error || 'unknown error')",
|
||||
"Error loading lifecycle rules: ' + escapeHtml(error.message)",
|
||||
} {
|
||||
if !strings.Contains(buf.String(), want) {
|
||||
t.Errorf("rendered bucket page is missing escaped text expression %q", want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalculatePercent64PetabyteScale(t *testing.T) {
|
||||
const pib = int64(1) << 50
|
||||
if got := calculatePercent64(100*pib, 200*pib); got != 50 {
|
||||
|
||||
@@ -1181,7 +1181,7 @@ templ S3Buckets(data dash.S3BucketsData) {
|
||||
|
||||
// Update modal title
|
||||
document.getElementById('bucketDetailsModalLabel').innerHTML =
|
||||
'<i class="bi bi-box me-2"></i>Bucket Details - ' + bucketName;
|
||||
'<i class="bi bi-box me-2"></i>Bucket Details - ' + escapeHtml(bucketName);
|
||||
|
||||
// Show loading spinner
|
||||
document.getElementById('bucketDetailsContent').innerHTML =
|
||||
@@ -1202,7 +1202,7 @@ templ S3Buckets(data dash.S3BucketsData) {
|
||||
document.getElementById('bucketDetailsContent').innerHTML =
|
||||
'<div class="alert alert-danger">' +
|
||||
'<i class="bi bi-exclamation-triangle me-2"></i>' +
|
||||
'Error loading bucket details: ' + data.error +
|
||||
'Error loading bucket details: ' + escapeHtml(data.error) +
|
||||
'<\\/div>';
|
||||
} else {
|
||||
displayBucketDetails(data);
|
||||
@@ -1213,7 +1213,7 @@ templ S3Buckets(data dash.S3BucketsData) {
|
||||
document.getElementById('bucketDetailsContent').innerHTML =
|
||||
'<div class="alert alert-danger">' +
|
||||
'<i class="bi bi-exclamation-triangle me-2"></i>' +
|
||||
'Error loading bucket details: ' + error.message +
|
||||
'Error loading bucket details: ' + escapeHtml(error.message) +
|
||||
'<\\/div>';
|
||||
});
|
||||
});
|
||||
@@ -1229,7 +1229,7 @@ templ S3Buckets(data dash.S3BucketsData) {
|
||||
lifecycleEditor = { bucket: null, rules: [], editingIndex: null, editingRule: null, rawXml: '', hasTransition: false };
|
||||
|
||||
document.getElementById('bucketLifecycleModalLabel').innerHTML =
|
||||
'<i class="bi bi-recycle me-2"></i>Lifecycle - ' + bucketName;
|
||||
'<i class="bi bi-recycle me-2"></i>Lifecycle - ' + escapeHtml(bucketName);
|
||||
|
||||
document.getElementById('bucketLifecycleContent').innerHTML =
|
||||
'<div class="text-center py-4">' +
|
||||
@@ -1251,7 +1251,7 @@ templ S3Buckets(data dash.S3BucketsData) {
|
||||
document.getElementById('bucketLifecycleContent').innerHTML =
|
||||
'<div class="alert alert-danger">' +
|
||||
'<i class="bi bi-exclamation-triangle me-2"></i>' +
|
||||
'Error loading lifecycle rules: ' + (data.error || 'unknown error') +
|
||||
'Error loading lifecycle rules: ' + escapeHtml(data.error || 'unknown error') +
|
||||
'<\/div>';
|
||||
} else {
|
||||
displayBucketLifecycle(data);
|
||||
@@ -1263,7 +1263,7 @@ templ S3Buckets(data dash.S3BucketsData) {
|
||||
document.getElementById('bucketLifecycleContent').innerHTML =
|
||||
'<div class="alert alert-danger">' +
|
||||
'<i class="bi bi-exclamation-triangle me-2"></i>' +
|
||||
'Error loading lifecycle rules: ' + error.message +
|
||||
'Error loading lifecycle rules: ' + escapeHtml(error.message) +
|
||||
'<\/div>';
|
||||
});
|
||||
});
|
||||
@@ -2244,4 +2244,4 @@ func getQuotaInMB(quotaBytes int64) int64 {
|
||||
quotaBytes = -quotaBytes // Handle disabled quotas (negative values)
|
||||
}
|
||||
return quotaBytes / (1024 * 1024)
|
||||
}
|
||||
}
|
||||
@@ -880,7 +880,7 @@ func S3Buckets(data dash.S3BucketsData) templ.Component {
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 94, "<!-- Bucket Policy Modal --><div class=\"modal fade\" id=\"bucketPolicyModal\" tabindex=\"-1\" aria-labelledby=\"bucketPolicyModalLabel\" aria-hidden=\"true\"><div class=\"modal-dialog modal-xl\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\" id=\"bucketPolicyModalLabel\"><i class=\"bi bi-file-earmark-lock me-2\"></i>Bucket Policy</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\"></button></div><div class=\"modal-body\"><div id=\"bucketPolicyLoading\" class=\"text-center py-4\"><div class=\"spinner-border text-primary\" role=\"status\"><span class=\"visually-hidden\">Loading...</span></div><div class=\"mt-2\">Loading bucket policy...</div></div><div id=\"bucketPolicyError\" class=\"alert alert-danger\" style=\"display: none;\"></div><div id=\"bucketPolicyEditorWrapper\" style=\"display: none;\"><p class=\"text-muted small\">Every statement must specify a Principal, and every Resource must refer to this bucket. Leave the document empty and click Delete to remove the policy.</p><ul class=\"nav nav-tabs\" role=\"tablist\"><li class=\"nav-item\" role=\"presentation\"><button class=\"nav-link active\" id=\"bucketPolicyEditorTabBtn\" type=\"button\" data-bs-toggle=\"tab\" data-bs-target=\"#bucketPolicyEditorTab\" role=\"tab\" aria-controls=\"bucketPolicyEditorTab\" aria-selected=\"true\">Editor</button></li><li class=\"nav-item\" role=\"presentation\"><button class=\"nav-link\" id=\"bucketPolicyJsonTabBtn\" type=\"button\" data-bs-toggle=\"tab\" data-bs-target=\"#bucketPolicyJsonTab\" role=\"tab\" aria-controls=\"bucketPolicyJsonTab\" aria-selected=\"false\">JSON</button></li></ul><div class=\"tab-content border border-top-0 rounded-bottom p-3 mb-3\"><div class=\"tab-pane fade show active\" id=\"bucketPolicyEditorTab\" role=\"tabpanel\" aria-labelledby=\"bucketPolicyEditorTabBtn\"><div id=\"bucketPolicyEditorBody\"></div><button type=\"button\" class=\"btn btn-sm btn-outline-secondary\" id=\"bucketPolicyAddStatementBtn\"><i class=\"bi bi-plus me-1\"></i>Add statement</button></div><div class=\"tab-pane fade\" id=\"bucketPolicyJsonTab\" role=\"tabpanel\" aria-labelledby=\"bucketPolicyJsonTabBtn\"><textarea class=\"form-control\" id=\"bucketPolicyDocument\" rows=\"15\" style=\"font-family: monospace;\" spellcheck=\"false\" placeholder='{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":\"*\",\"Action\":\"s3:GetObject\",\"Resource\":\"arn:aws:s3:::bucket-name/*\"}]}'></textarea><div class=\"form-text\">Enter the bucket policy document as JSON</div></div></div><div class=\"mb-3\"><button type=\"button\" class=\"btn btn-outline-info btn-sm\" id=\"bucketPolicyInsertSampleBtn\"><i class=\"bi bi-file-earmark-text me-1\"></i>Use Sample Policy</button></div></div></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-outline-danger me-auto\" id=\"bucketPolicyDeleteBtn\"><i class=\"bi bi-trash me-1\"></i>Delete</button> <button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Cancel</button> <button type=\"button\" class=\"btn btn-primary\" id=\"bucketPolicySaveBtn\"><i class=\"bi bi-floppy me-1\"></i>Save</button></div></div></div></div><!-- Manage Owner Modal --><div class=\"modal fade\" id=\"manageOwnerModal\" tabindex=\"-1\" aria-labelledby=\"manageOwnerModalLabel\" aria-hidden=\"true\"><div class=\"modal-dialog\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\" id=\"manageOwnerModalLabel\"><i class=\"bi bi-person-gear me-2\"></i>Manage Bucket Owner</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\"></button></div><form id=\"ownerForm\"><div class=\"modal-body\"><div class=\"mb-3\"><label class=\"form-label\">Bucket Name</label> <input type=\"text\" class=\"form-control\" id=\"ownerBucketName\" readonly></div><div class=\"mb-3\"><label for=\"bucketOwnerSelect\" class=\"form-label\">Owner</label> <select class=\"form-select\" id=\"bucketOwnerSelect\" name=\"owner\"><option value=\"\">No owner (admin-only access)</option><!-- Options will be populated dynamically --></select><div class=\"form-text\">Select the S3 identity that owns this bucket. Non-admin users can only access buckets they own.</div></div><div id=\"ownerLoadingSpinner\" class=\"text-center py-2\" style=\"display: none;\"><div class=\"spinner-border spinner-border-sm text-primary\" role=\"status\"><span class=\"visually-hidden\">Loading users...</span></div><span class=\"ms-2\">Loading users...</span></div></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Cancel</button> <button type=\"submit\" class=\"btn btn-info\"><i class=\"bi bi-floppy me-1\"></i>Update Owner</button></div></form></div></div></div><!-- JavaScript for bucket management --><script>\n // Global state (shared between DOMContentLine truncated
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 94, "<!-- Bucket Policy Modal --><div class=\"modal fade\" id=\"bucketPolicyModal\" tabindex=\"-1\" aria-labelledby=\"bucketPolicyModalLabel\" aria-hidden=\"true\"><div class=\"modal-dialog modal-xl\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\" id=\"bucketPolicyModalLabel\"><i class=\"bi bi-file-earmark-lock me-2\"></i>Bucket Policy</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\"></button></div><div class=\"modal-body\"><div id=\"bucketPolicyLoading\" class=\"text-center py-4\"><div class=\"spinner-border text-primary\" role=\"status\"><span class=\"visually-hidden\">Loading...</span></div><div class=\"mt-2\">Loading bucket policy...</div></div><div id=\"bucketPolicyError\" class=\"alert alert-danger\" style=\"display: none;\"></div><div id=\"bucketPolicyEditorWrapper\" style=\"display: none;\"><p class=\"text-muted small\">Every statement must specify a Principal, and every Resource must refer to this bucket. Leave the document empty and click Delete to remove the policy.</p><ul class=\"nav nav-tabs\" role=\"tablist\"><li class=\"nav-item\" role=\"presentation\"><button class=\"nav-link active\" id=\"bucketPolicyEditorTabBtn\" type=\"button\" data-bs-toggle=\"tab\" data-bs-target=\"#bucketPolicyEditorTab\" role=\"tab\" aria-controls=\"bucketPolicyEditorTab\" aria-selected=\"true\">Editor</button></li><li class=\"nav-item\" role=\"presentation\"><button class=\"nav-link\" id=\"bucketPolicyJsonTabBtn\" type=\"button\" data-bs-toggle=\"tab\" data-bs-target=\"#bucketPolicyJsonTab\" role=\"tab\" aria-controls=\"bucketPolicyJsonTab\" aria-selected=\"false\">JSON</button></li></ul><div class=\"tab-content border border-top-0 rounded-bottom p-3 mb-3\"><div class=\"tab-pane fade show active\" id=\"bucketPolicyEditorTab\" role=\"tabpanel\" aria-labelledby=\"bucketPolicyEditorTabBtn\"><div id=\"bucketPolicyEditorBody\"></div><button type=\"button\" class=\"btn btn-sm btn-outline-secondary\" id=\"bucketPolicyAddStatementBtn\"><i class=\"bi bi-plus me-1\"></i>Add statement</button></div><div class=\"tab-pane fade\" id=\"bucketPolicyJsonTab\" role=\"tabpanel\" aria-labelledby=\"bucketPolicyJsonTabBtn\"><textarea class=\"form-control\" id=\"bucketPolicyDocument\" rows=\"15\" style=\"font-family: monospace;\" spellcheck=\"false\" placeholder='{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":\"*\",\"Action\":\"s3:GetObject\",\"Resource\":\"arn:aws:s3:::bucket-name/*\"}]}'></textarea><div class=\"form-text\">Enter the bucket policy document as JSON</div></div></div><div class=\"mb-3\"><button type=\"button\" class=\"btn btn-outline-info btn-sm\" id=\"bucketPolicyInsertSampleBtn\"><i class=\"bi bi-file-earmark-text me-1\"></i>Use Sample Policy</button></div></div></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-outline-danger me-auto\" id=\"bucketPolicyDeleteBtn\"><i class=\"bi bi-trash me-1\"></i>Delete</button> <button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Cancel</button> <button type=\"button\" class=\"btn btn-primary\" id=\"bucketPolicySaveBtn\"><i class=\"bi bi-floppy me-1\"></i>Save</button></div></div></div></div><!-- Manage Owner Modal --><div class=\"modal fade\" id=\"manageOwnerModal\" tabindex=\"-1\" aria-labelledby=\"manageOwnerModalLabel\" aria-hidden=\"true\"><div class=\"modal-dialog\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\" id=\"manageOwnerModalLabel\"><i class=\"bi bi-person-gear me-2\"></i>Manage Bucket Owner</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\"></button></div><form id=\"ownerForm\"><div class=\"modal-body\"><div class=\"mb-3\"><label class=\"form-label\">Bucket Name</label> <input type=\"text\" class=\"form-control\" id=\"ownerBucketName\" readonly></div><div class=\"mb-3\"><label for=\"bucketOwnerSelect\" class=\"form-label\">Owner</label> <select class=\"form-select\" id=\"bucketOwnerSelect\" name=\"owner\"><option value=\"\">No owner (admin-only access)</option><!-- Options will be populated dynamically --></select><div class=\"form-text\">Select the S3 identity that owns this bucket. Non-admin users can only access buckets they own.</div></div><div id=\"ownerLoadingSpinner\" class=\"text-center py-2\" style=\"display: none;\"><div class=\"spinner-border spinner-border-sm text-primary\" role=\"status\"><span class=\"visually-hidden\">Loading users...</span></div><span class=\"ms-2\">Loading users...</span></div></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Cancel</button> <button type=\"submit\" class=\"btn btn-info\"><i class=\"bi bi-floppy me-1\"></i>Update Owner</button></div></form></div></div></div><!-- JavaScript for bucket management --><script>\n // Global state (shared between DOMContentLine truncated
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user