修改代码,使得action token具有与已登录用户等同的权限,对其他公开仓库有只读权限 #59
@@ -3964,6 +3964,28 @@ manage = Container Management
|
||||
registry_username = Registry Username
|
||||
registry_password = Registry Password
|
||||
save_tip = 💡 Tip: It is recommended to prioritize using <strong>Build From Dockerfile</strong> to save images. Saving images directly from containers is opaque and storage-bloated, while building through Dockerfile ensures image reproducibility and minimization.
|
||||
security_disclaimer_title = [Important Notice] Data Security Disclaimer
|
||||
security_disclaimer_warning_title = ⚠️ You have selected direct container commit mode
|
||||
security_disclaimer_warning_content = This mode will save all runtime data of the container. Before saving, please ensure that you have manually cleaned all sensitive data, including but not limited to:
|
||||
security_disclaimer_key_credentials = Keys and credentials: SSH keys, API keys, access tokens, passwords, etc.
|
||||
security_disclaimer_personal_docs = Personal documents: Personal files, business secrets, unpublished code, etc.
|
||||
security_disclaimer_connection_info = Connection information: Database connection strings, service endpoints, authentication information, etc.
|
||||
security_disclaimer_history = History records: Command history, log files, etc.
|
||||
security_disclaimer_config_files = Configuration files: API keys and tokens in code, passwords and credentials in configuration files
|
||||
security_disclaimer_env_vars = Environment variables: Sensitive information in environment variables
|
||||
security_disclaimer_temp_files = Temporary files: Temporary files and cache data
|
||||
security_disclaimer_auto_clean = System will automatically clean: SSH keys (authorized_keys), SSH host keys, command history, Git configuration, temporary files and other system-generated data.
|
||||
security_disclaimer_manual_clean = ⚠️ However, the system cannot clean data you have added manually (such as keys in code, personal documents, etc.), which requires manual cleanup!
|
||||
security_disclaimer_risk_warning = If not cleaned properly, others using your saved container image may cause data leakage. The risk of data leakage and related responsibilities arising from this shall be borne by the user!
|
||||
security_disclaimer_view_link = View Disclaimer
|
||||
security_disclaimer_accept_label = I have read and understood the risks above and confirm that all sensitive data has been cleaned
|
||||
security_disclaimer_cancel_button = Cancel
|
||||
security_disclaimer_accept_button = I understand the risks and confirm
|
||||
security_disclaimer_validation_error = Please read and confirm the data security disclaimer first
|
||||
save_image_modal_title = Save as Container Image
|
||||
save_image_submit_button = Submit
|
||||
save_image_cancel_button = Cancel
|
||||
save_image_required_fields_error = Please fill in all required fields
|
||||
scripts = ShellScripts
|
||||
scripts.management = ShellScripts Management
|
||||
scripts.creation = Add ShellScript
|
||||
|
||||
@@ -3953,6 +3953,28 @@ manage=容器管理
|
||||
registry_username = 镜像仓库用户名
|
||||
registry_password = 镜像仓库密码
|
||||
save_tip = 💡 提示:建议优先使用 <strong>Build From Dockerfile</strong> 方式保存镜像。从容器直接保存镜像不透明且存储臃肿,而通过Dockerfile构建可以确保镜像的可重现性和最小化。
|
||||
security_disclaimer_title = 【重要提示】数据安全免责声明
|
||||
security_disclaimer_warning_title = ⚠️ 您选择了直接提交容器模式
|
||||
security_disclaimer_warning_content = 此模式会保存容器的所有运行时数据,在保存前请务必自行清理所有敏感数据,包括但不限于:
|
||||
security_disclaimer_key_credentials = 密钥和凭证:SSH密钥、API密钥、访问令牌、密码等
|
||||
security_disclaimer_personal_docs = 个人文档:个人文件、商业机密、未公开代码等
|
||||
security_disclaimer_connection_info = 连接信息:数据库连接字符串、服务端点、认证信息等
|
||||
security_disclaimer_history = 历史记录:命令历史、日志文件等
|
||||
security_disclaimer_config_files = 配置文件:代码中的API密钥和令牌、配置文件中的密码和凭证
|
||||
security_disclaimer_env_vars = 环境变量:环境变量中的敏感信息
|
||||
security_disclaimer_temp_files = 临时文件:临时文件和缓存数据
|
||||
security_disclaimer_auto_clean = 系统将自动清理:SSH密钥(authorized_keys)、SSH主机密钥、命令历史记录、Git配置、临时文件等系统生成的数据。
|
||||
security_disclaimer_manual_clean = ⚠️ 但系统无法清理您自行添加的数据(如代码中的密钥、个人文档等),需要您手动清理!
|
||||
security_disclaimer_risk_warning = 如未清理干净,他人使用您保存的容器镜像时可能造成数据泄露,由此带来的数据泄露风险及相关责任由用户自行承担!
|
||||
security_disclaimer_view_link = 查看免责声明
|
||||
security_disclaimer_accept_label = 我已阅读并理解上述风险,确认已清理所有敏感数据
|
||||
security_disclaimer_cancel_button = 取消
|
||||
security_disclaimer_accept_button = 我已了解风险并确认
|
||||
security_disclaimer_validation_error = 请先阅读并确认数据安全免责声明
|
||||
save_image_modal_title = 保存为容器镜像
|
||||
save_image_submit_button = 提交
|
||||
save_image_cancel_button = 取消
|
||||
save_image_required_fields_error = 请填写所有必填字段
|
||||
scripts=脚本管理
|
||||
scripts.management=脚本管理
|
||||
scripts.creation=添加脚本
|
||||
|
||||
@@ -392,6 +392,95 @@ func StopDevContainerByDocker(ctx context.Context, devContainerName string) erro
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CleanSensitiveDataBeforeCommit 在提交容器前清理敏感数据
|
||||
// 清理系统自动生成的敏感数据,如SSH密钥、历史记录等
|
||||
func CleanSensitiveDataBeforeCommit(ctx context.Context, cli *client.Client, containerName string) error {
|
||||
// 构建清理命令
|
||||
// 清理SSH相关数据、历史记录、Git配置和临时文件
|
||||
cleanupCommand := `
|
||||
# 清理SSH密钥(authorized_keys)
|
||||
rm -f ~/.ssh/authorized_keys 2>/dev/null || true
|
||||
rm -f /root/.ssh/authorized_keys 2>/dev/null || true
|
||||
|
||||
# 清理SSH主机密钥(容器重启时会重新生成)
|
||||
rm -f /etc/ssh/ssh_host_* 2>/dev/null || true
|
||||
|
||||
# 清理SSH known_hosts(可能包含服务器指纹信息)
|
||||
rm -f ~/.ssh/known_hosts 2>/dev/null || true
|
||||
rm -f ~/.ssh/known_hosts.old 2>/dev/null || true
|
||||
rm -f /root/.ssh/known_hosts 2>/dev/null || true
|
||||
rm -f /root/.ssh/known_hosts.old 2>/dev/null || true
|
||||
|
||||
# 清理命令历史记录
|
||||
rm -f ~/.bash_history ~/.zsh_history ~/.history ~/.fish_history 2>/dev/null || true
|
||||
rm -f /root/.bash_history /root/.zsh_history /root/.history /root/.fish_history 2>/dev/null || true
|
||||
# 同时清空当前会话的历史
|
||||
history -c 2>/dev/null || true
|
||||
|
||||
# 清理Git配置和凭证(可能包含用户信息和token)
|
||||
rm -f ~/.gitconfig 2>/dev/null || true
|
||||
rm -f /root/.gitconfig 2>/dev/null || true
|
||||
rm -f ~/.git-credentials 2>/dev/null || true
|
||||
rm -f /root/.git-credentials 2>/dev/null || true
|
||||
|
||||
# 清理Docker凭证(可能包含registry认证信息)
|
||||
rm -f ~/.docker/config.json 2>/dev/null || true
|
||||
rm -f /root/.docker/config.json 2>/dev/null || true
|
||||
|
||||
# 清理AWS凭证和配置
|
||||
rm -f ~/.aws/credentials 2>/dev/null || true
|
||||
rm -f ~/.aws/config 2>/dev/null || true
|
||||
rm -f /root/.aws/credentials 2>/dev/null || true
|
||||
rm -f /root/.aws/config 2>/dev/null || true
|
||||
|
||||
# 清理npm/yarn凭证(可能包含registry token)
|
||||
rm -f ~/.npmrc 2>/dev/null || true
|
||||
rm -f ~/.yarnrc 2>/dev/null || true
|
||||
rm -f /root/.npmrc 2>/dev/null || true
|
||||
rm -f /root/.yarnrc 2>/dev/null || true
|
||||
|
||||
# 清理pip凭证(Python包管理器)
|
||||
rm -f ~/.pip/pip.conf 2>/dev/null || true
|
||||
rm -f ~/.pypirc 2>/dev/null || true
|
||||
rm -f /root/.pip/pip.conf 2>/dev/null || true
|
||||
rm -f /root/.pypirc 2>/dev/null || true
|
||||
|
||||
# 清理其他包管理器凭证
|
||||
rm -f ~/.composer/auth.json 2>/dev/null || true
|
||||
rm -f /root/.composer/auth.json 2>/dev/null || true
|
||||
rm -f ~/.m2/settings.xml 2>/dev/null || true
|
||||
rm -f /root/.m2/settings.xml 2>/dev/null || true
|
||||
rm -f ~/.gradle/gradle.properties 2>/dev/null || true
|
||||
rm -f /root/.gradle/gradle.properties 2>/dev/null || true
|
||||
|
||||
# 清理SSH私钥(如果存在)
|
||||
rm -f ~/.ssh/id_rsa ~/.ssh/id_ed25519 ~/.ssh/id_ecdsa ~/.ssh/id_dsa 2>/dev/null || true
|
||||
rm -f /root/.ssh/id_rsa /root/.ssh/id_ed25519 /root/.ssh/id_ecdsa /root/.ssh/id_dsa 2>/dev/null || true
|
||||
rm -f ~/.ssh/id_rsa.pub ~/.ssh/id_ed25519.pub ~/.ssh/id_ecdsa.pub ~/.ssh/id_dsa.pub 2>/dev/null || true
|
||||
rm -f /root/.ssh/id_rsa.pub /root/.ssh/id_ed25519.pub /root/.ssh/id_ecdsa.pub /root/.ssh/id_dsa.pub 2>/dev/null || true
|
||||
|
||||
# 清理临时文件和缓存
|
||||
rm -rf /tmp/* /var/tmp/* 2>/dev/null || true
|
||||
rm -rf ~/.cache/* /root/.cache/* 2>/dev/null || true
|
||||
|
||||
# 清理系统日志(用户可访问的部分)
|
||||
rm -rf /var/log/*.log 2>/dev/null || true
|
||||
|
||||
echo "敏感数据清理完成"
|
||||
`
|
||||
|
||||
// 执行清理命令
|
||||
output, err := docker_module.ExecCommandInContainer(ctx, cli, containerName, cleanupCommand)
|
||||
if err != nil {
|
||||
log.Warn("清理敏感数据时出现错误: %v, 输出: %s", err, output)
|
||||
// 清理失败不阻止提交,但记录警告日志
|
||||
return fmt.Errorf("清理敏感数据时出错: %v (输出: %s)", err, output)
|
||||
}
|
||||
log.Info("容器 %s 敏感数据清理完成,输出: %s", containerName, output)
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdateDevContainerByDocker(ctx context.Context, devContainerInfo *devcontainer_models.Devcontainer, updateInfo *UpdateInfo, repo *gitea_context.Repository, doer *user.User) error {
|
||||
// 创建docker client
|
||||
cli, err := docker_module.CreateDockerClient(ctx)
|
||||
@@ -497,6 +586,14 @@ func UpdateDevContainerByDocker(ctx context.Context, devContainerInfo *devcontai
|
||||
}
|
||||
|
||||
} else {
|
||||
// 非Dockerfile模式:直接提交容器
|
||||
// 在提交前清理敏感数据
|
||||
log.Info("开始清理容器 %s 的敏感数据...", devContainerInfo.Name)
|
||||
if err := CleanSensitiveDataBeforeCommit(ctx, cli, devContainerInfo.Name); err != nil {
|
||||
log.Warn("清理敏感数据时出现警告: %v,继续执行提交操作", err)
|
||||
// 清理失败不阻止提交,但已记录警告
|
||||
}
|
||||
|
||||
// 获取容器 ID
|
||||
containerID, err := docker_module.GetContainerID(cli, devContainerInfo.Name)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class="ui g-modal-confirm delete modal" style="width: 35%" id="updatemodal">
|
||||
<div class="header">
|
||||
保存为容器镜像
|
||||
{{ctx.Locale.Tr "devcontainer.save_image_modal_title"}}
|
||||
</div>
|
||||
<div class="content" style="position: relative;">
|
||||
<form class="ui form tw-max-w-2xl tw-m-auto" id="updateForm">
|
||||
@@ -35,21 +35,35 @@
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
{{if .HasDevContainerDockerfile}}
|
||||
<input type="checkbox" id="SaveMethod" name="SaveMethod" value="on" checked>
|
||||
<input type="checkbox" id="SaveMethod" name="SaveMethod" value="on" checked onchange="handleSaveMethodChange(); checkSubmitButtonState();">
|
||||
<label for="SaveMethod">Build From Dockerfile{{if .DockerfilePath}}: <a id="dockerfileLinkStatic" href="{{.Repository.Link}}/_edit/{{.Repository.DefaultBranch | PathEscapeSegments}}/{{.DockerfilePath | PathEscapeSegments}}" target="_blank" style="color: #2185d0; text-decoration: underline;">{{.DockerfilePath}}</a>{{end}}<span id="dockerfilePathSpan" style="display: none;">: <a id="dockerfileLink" href="#" target="_blank" style="color: #2185d0; text-decoration: underline;"></a></span></label>
|
||||
{{else}}
|
||||
<input type="checkbox" id="SaveMethod" name="SaveMethod" value="on" checked>
|
||||
<input type="checkbox" id="SaveMethod" name="SaveMethod" value="on" checked onchange="handleSaveMethodChange(); checkSubmitButtonState();">
|
||||
<label for="SaveMethod">Build From Dockerfile<span id="dockerfilePathSpan" style="display: none;">: <a id="dockerfileLink" href="#" target="_blank" style="color: #2185d0; text-decoration: underline;"></a></span></label>
|
||||
{{end}}
|
||||
</div>
|
||||
<div style="color: #2185d0; font-size: 13px; margin-top: 12px; padding: 10px; background-color: #f0f8ff; border-left: 3px solid #2185d0; border-radius: 3px;">
|
||||
{{ctx.Locale.TrHTML "devcontainer.save_tip"}}
|
||||
</div>
|
||||
<!-- 用户确认复选框(仅在未勾选Build From Dockerfile时显示) -->
|
||||
<div class="field" id="securityDisclaimerCheckbox" style="display: none; margin-top: 15px;">
|
||||
<div style="margin-bottom: 8px;">
|
||||
<a href="javascript:void(0);" id="showDisclaimerLink" style="color: #2185d0; text-decoration: underline; cursor: pointer;">
|
||||
<i class="warning circle icon" style="margin-right: 4px;"></i>{{ctx.Locale.Tr "devcontainer.security_disclaimer_view_link"}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" id="SecurityDisclaimerAccepted" name="SecurityDisclaimerAccepted" onchange="checkSubmitButtonState()">
|
||||
<label for="SecurityDisclaimerAccepted" style="font-weight: bold;">
|
||||
{{ctx.Locale.Tr "devcontainer.security_disclaimer_accept_label"}}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button class="ui primary button" type="button" id="updateSubmitButton">提交</button>
|
||||
<button class="ui cancel button" type="button" id="updateCloseButton">取消</button>
|
||||
<button class="ui primary button" type="button" id="updateSubmitButton">{{ctx.Locale.Tr "devcontainer.save_image_submit_button"}}</button>
|
||||
<button class="ui cancel button" type="button" id="updateCloseButton">{{ctx.Locale.Tr "devcontainer.save_image_cancel_button"}}</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
@@ -61,6 +75,56 @@
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 免责声明遮罩层和弹窗(不使用语义UI的modal,避免关闭保存模态框) -->
|
||||
<div id="securityDisclaimerOverlay" class="security-disclaimer-overlay" style="display: none;">
|
||||
<div class="security-disclaimer-modal">
|
||||
<div class="security-disclaimer-header">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<i class="warning circle icon" style="color: #d01919; margin-right: 10px;"></i>
|
||||
{{ctx.Locale.Tr "devcontainer.security_disclaimer_title"}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="security-disclaimer-body">
|
||||
<div class="ui negative message">
|
||||
<div class="header">{{ctx.Locale.Tr "devcontainer.security_disclaimer_warning_title"}}</div>
|
||||
<p style="margin: 10px 0; font-weight: bold;">{{ctx.Locale.Tr "devcontainer.security_disclaimer_warning_content"}}</p>
|
||||
</div>
|
||||
|
||||
<div class="security-disclaimer-content" style="margin-top: 15px;">
|
||||
<ul style="margin: 10px 0; padding-left: 20px; line-height: 1.8;">
|
||||
<li><strong>{{ctx.Locale.Tr "devcontainer.security_disclaimer_key_credentials"}}</strong></li>
|
||||
<li><strong>{{ctx.Locale.Tr "devcontainer.security_disclaimer_personal_docs"}}</strong></li>
|
||||
<li><strong>{{ctx.Locale.Tr "devcontainer.security_disclaimer_connection_info"}}</strong></li>
|
||||
<li><strong>{{ctx.Locale.Tr "devcontainer.security_disclaimer_history"}}</strong></li>
|
||||
<li><strong>{{ctx.Locale.Tr "devcontainer.security_disclaimer_config_files"}}</strong></li>
|
||||
<li><strong>{{ctx.Locale.Tr "devcontainer.security_disclaimer_env_vars"}}</strong></li>
|
||||
<li><strong>{{ctx.Locale.Tr "devcontainer.security_disclaimer_temp_files"}}</strong></li>
|
||||
</ul>
|
||||
|
||||
<div class="ui info message" style="margin-top: 15px;">
|
||||
<p style="margin: 8px 0;">
|
||||
<strong>{{ctx.Locale.Tr "devcontainer.security_disclaimer_auto_clean"}}</strong>
|
||||
</p>
|
||||
<p style="margin: 8px 0; color: #d01919; font-weight: bold;">
|
||||
{{ctx.Locale.Tr "devcontainer.security_disclaimer_manual_clean"}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="ui negative message" style="margin-top: 15px;">
|
||||
<p style="margin: 10px 0; color: #d01919; font-weight: bold; font-size: 16px;">
|
||||
{{ctx.Locale.Tr "devcontainer.security_disclaimer_risk_warning"}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="security-disclaimer-actions">
|
||||
<button class="ui cancel button" type="button" id="disclaimerCancelButton">{{ctx.Locale.Tr "devcontainer.security_disclaimer_cancel_button"}}</button>
|
||||
<button class="ui primary button" type="button" id="disclaimerAcceptButton">{{ctx.Locale.Tr "devcontainer.security_disclaimer_accept_button"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
// 保存模态框相关功能 - 可复用组件
|
||||
(function() {
|
||||
@@ -79,6 +143,73 @@
|
||||
}
|
||||
};
|
||||
|
||||
// 检查提交按钮状态
|
||||
window.checkSubmitButtonState = function() {
|
||||
const saveMethodCheckbox = document.getElementById('SaveMethod');
|
||||
const disclaimerAcceptedCheckbox = document.getElementById('SecurityDisclaimerAccepted');
|
||||
const submitButton = document.getElementById('updateSubmitButton');
|
||||
|
||||
if (!submitButton) return;
|
||||
|
||||
// 如果Build From Dockerfile已勾选,允许提交
|
||||
if (saveMethodCheckbox && saveMethodCheckbox.checked) {
|
||||
submitButton.disabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果Build From Dockerfile未勾选,必须勾选免责声明才能提交
|
||||
if (disclaimerAcceptedCheckbox && disclaimerAcceptedCheckbox.checked) {
|
||||
submitButton.disabled = false;
|
||||
} else {
|
||||
submitButton.disabled = true;
|
||||
}
|
||||
};
|
||||
|
||||
// 显示免责声明遮罩层
|
||||
window.showDisclaimerOverlay = function() {
|
||||
const disclaimerOverlay = document.getElementById('securityDisclaimerOverlay');
|
||||
if (disclaimerOverlay) {
|
||||
disclaimerOverlay.style.display = 'flex';
|
||||
}
|
||||
};
|
||||
|
||||
// 处理SaveMethod变更,显示/隐藏警告和确认框
|
||||
window.handleSaveMethodChange = function() {
|
||||
const saveMethodCheckbox = document.getElementById('SaveMethod');
|
||||
const securityDisclaimerCheckbox = document.getElementById('securityDisclaimerCheckbox');
|
||||
const disclaimerAcceptedCheckbox = document.getElementById('SecurityDisclaimerAccepted');
|
||||
const disclaimerOverlay = document.getElementById('securityDisclaimerOverlay');
|
||||
|
||||
if (!saveMethodCheckbox.checked) {
|
||||
// 非Dockerfile模式(直接提交容器)- 显示免责声明遮罩层
|
||||
// 先重置确认框状态
|
||||
if (disclaimerAcceptedCheckbox) {
|
||||
disclaimerAcceptedCheckbox.checked = false;
|
||||
}
|
||||
// 隐藏确认框(等待用户确认免责声明后再显示)
|
||||
if (securityDisclaimerCheckbox) {
|
||||
securityDisclaimerCheckbox.style.display = 'none';
|
||||
}
|
||||
// 显示免责声明遮罩层(在保存模态框之上,但不关闭保存模态框)
|
||||
if (disclaimerOverlay) {
|
||||
disclaimerOverlay.style.display = 'flex';
|
||||
}
|
||||
} else {
|
||||
// Dockerfile模式 - 隐藏确认框和免责声明遮罩层
|
||||
if (securityDisclaimerCheckbox) {
|
||||
securityDisclaimerCheckbox.style.display = 'none';
|
||||
}
|
||||
if (disclaimerAcceptedCheckbox) {
|
||||
disclaimerAcceptedCheckbox.checked = false;
|
||||
}
|
||||
if (disclaimerOverlay) {
|
||||
disclaimerOverlay.style.display = 'none';
|
||||
}
|
||||
}
|
||||
// 检查提交按钮状态
|
||||
checkSubmitButtonState();
|
||||
};
|
||||
|
||||
// 提交保存表单
|
||||
// targetUrl: 保存请求的URL
|
||||
// statusUrl: 状态检查URL(用于轮询)
|
||||
@@ -95,10 +226,29 @@
|
||||
const RepositoryPassword = formData.get('RepositoryPassword');
|
||||
const SaveMethod = formData.get('SaveMethod');
|
||||
const ImageName = formData.get('ImageName');
|
||||
const SecurityDisclaimerAccepted = formData.get('SecurityDisclaimerAccepted');
|
||||
|
||||
// 验证必填字段
|
||||
if (!ImageName || !RepositoryUsername || !RepositoryPassword) {
|
||||
alert('请填写所有必填字段');
|
||||
const requiredFieldsError = '{{ctx.Locale.Tr "devcontainer.save_image_required_fields_error"}}';
|
||||
alert(requiredFieldsError);
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证用户已接受免责声明(仅在非Dockerfile模式时需要)
|
||||
// 注意:这里再次检查是因为按钮可能被手动启用,需要双重验证
|
||||
if (!SaveMethod && !SecurityDisclaimerAccepted) {
|
||||
const errorMsg = '{{ctx.Locale.Tr "devcontainer.security_disclaimer_validation_error"}}';
|
||||
alert(errorMsg);
|
||||
const disclaimerCheckbox = document.getElementById('SecurityDisclaimerAccepted');
|
||||
if (disclaimerCheckbox) {
|
||||
disclaimerCheckbox.focus();
|
||||
disclaimerCheckbox.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
// 禁用提交按钮
|
||||
if (submitButton) {
|
||||
submitButton.disabled = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -239,6 +389,28 @@
|
||||
|
||||
// 打开模态框
|
||||
window.openSaveModal = function(repoLink, dockerfilePath) {
|
||||
// 重置状态
|
||||
const securityDisclaimerCheckbox = document.getElementById('securityDisclaimerCheckbox');
|
||||
const saveMethodCheckbox = document.getElementById('SaveMethod');
|
||||
const disclaimerOverlay = document.getElementById('securityDisclaimerOverlay');
|
||||
const disclaimerAcceptedCheckbox = document.getElementById('SecurityDisclaimerAccepted');
|
||||
if (securityDisclaimerCheckbox) {
|
||||
securityDisclaimerCheckbox.style.display = 'none';
|
||||
}
|
||||
if (saveMethodCheckbox) {
|
||||
saveMethodCheckbox.checked = true;
|
||||
}
|
||||
if (disclaimerOverlay) {
|
||||
disclaimerOverlay.style.display = 'none';
|
||||
}
|
||||
if (disclaimerAcceptedCheckbox) {
|
||||
disclaimerAcceptedCheckbox.checked = false;
|
||||
}
|
||||
// 检查提交按钮状态
|
||||
setTimeout(function() {
|
||||
checkSubmitButtonState();
|
||||
}, 100);
|
||||
|
||||
// 如果提供了repoLink,尝试检查Dockerfile是否存在(管理页面场景)
|
||||
if (repoLink) {
|
||||
const dockerfileLink = document.getElementById('dockerfileLink');
|
||||
@@ -289,10 +461,24 @@
|
||||
$('#updatemodal').modal('hide');
|
||||
const form = document.getElementById('updateForm');
|
||||
const loadingOverlay = document.getElementById('saveLoadingOverlay');
|
||||
const securityDisclaimerCheckbox = document.getElementById('securityDisclaimerCheckbox');
|
||||
const saveMethodCheckbox = document.getElementById('SaveMethod');
|
||||
const disclaimerOverlay = document.getElementById('securityDisclaimerOverlay');
|
||||
|
||||
form.reset();
|
||||
if (loadingOverlay) {
|
||||
loadingOverlay.style.display = 'none';
|
||||
}
|
||||
// 重置状态
|
||||
if (securityDisclaimerCheckbox) {
|
||||
securityDisclaimerCheckbox.style.display = 'none';
|
||||
}
|
||||
if (saveMethodCheckbox) {
|
||||
saveMethodCheckbox.checked = true;
|
||||
}
|
||||
if (disclaimerOverlay) {
|
||||
disclaimerOverlay.style.display = 'none';
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭按钮事件
|
||||
@@ -303,6 +489,66 @@
|
||||
closeSaveModal();
|
||||
});
|
||||
}
|
||||
|
||||
// 免责声明遮罩层按钮事件
|
||||
const disclaimerCancelButton = document.getElementById('disclaimerCancelButton');
|
||||
if (disclaimerCancelButton) {
|
||||
disclaimerCancelButton.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
// 隐藏免责声明遮罩层
|
||||
const disclaimerOverlay = document.getElementById('securityDisclaimerOverlay');
|
||||
if (disclaimerOverlay) {
|
||||
disclaimerOverlay.style.display = 'none';
|
||||
}
|
||||
// 恢复勾选Build From Dockerfile
|
||||
const saveMethodCheckbox = document.getElementById('SaveMethod');
|
||||
if (saveMethodCheckbox) {
|
||||
saveMethodCheckbox.checked = true;
|
||||
}
|
||||
// 隐藏确认框
|
||||
const securityDisclaimerCheckbox = document.getElementById('securityDisclaimerCheckbox');
|
||||
if (securityDisclaimerCheckbox) {
|
||||
securityDisclaimerCheckbox.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const disclaimerAcceptButton = document.getElementById('disclaimerAcceptButton');
|
||||
if (disclaimerAcceptButton) {
|
||||
disclaimerAcceptButton.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
// 隐藏免责声明遮罩层
|
||||
const disclaimerOverlay = document.getElementById('securityDisclaimerOverlay');
|
||||
if (disclaimerOverlay) {
|
||||
disclaimerOverlay.style.display = 'none';
|
||||
}
|
||||
// 显示确认框并自动勾选
|
||||
const securityDisclaimerCheckbox = document.getElementById('securityDisclaimerCheckbox');
|
||||
const disclaimerAcceptedCheckbox = document.getElementById('SecurityDisclaimerAccepted');
|
||||
if (securityDisclaimerCheckbox) {
|
||||
securityDisclaimerCheckbox.style.display = 'block';
|
||||
}
|
||||
if (disclaimerAcceptedCheckbox) {
|
||||
disclaimerAcceptedCheckbox.checked = true;
|
||||
}
|
||||
// 检查提交按钮状态
|
||||
checkSubmitButtonState();
|
||||
});
|
||||
}
|
||||
|
||||
// 查看免责声明链接事件
|
||||
const showDisclaimerLink = document.getElementById('showDisclaimerLink');
|
||||
if (showDisclaimerLink) {
|
||||
showDisclaimerLink.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
showDisclaimerOverlay();
|
||||
});
|
||||
}
|
||||
|
||||
// 初始化时检查提交按钮状态
|
||||
checkSubmitButtonState();
|
||||
})();
|
||||
</script>
|
||||
|
||||
@@ -337,4 +583,65 @@
|
||||
0%{-webkit-transform:rotate(0deg)}
|
||||
100%{-webkit-transform:rotate(360deg)}
|
||||
}
|
||||
.security-disclaimer-content {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
padding: 5px 0;
|
||||
}
|
||||
.security-disclaimer-content ul {
|
||||
margin: 10px 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
.security-disclaimer-content li {
|
||||
margin: 5px 0;
|
||||
}
|
||||
/* 免责声明遮罩层样式 */
|
||||
.security-disclaimer-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1002;
|
||||
}
|
||||
|
||||
.security-disclaimer-modal {
|
||||
background: white;
|
||||
border-radius: 4px;
|
||||
width: 50%;
|
||||
max-width: 700px;
|
||||
max-height: 80vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.security-disclaimer-header {
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid #d4d4d5;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.security-disclaimer-body {
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.security-disclaimer-actions {
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #d4d4d5;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.security-disclaimer-actions .button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user