From 5c2381c3a880056b4a4c5ac6482a52924595d61b Mon Sep 17 00:00:00 2001 From: wzj <244142824@qq.com> Date: Sun, 15 Jun 2025 07:56:35 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=89=B9=E9=87=8F=E5=88=A0?= =?UTF-8?q?=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.py | 235 +++++++++++++++++++++++++++++++- templates/ca_list.html | 126 ++++++++++++++++- templates/certificate_list.html | 115 ++++++++++++++-- 3 files changed, 458 insertions(+), 18 deletions(-) diff --git a/app.py b/app.py index b2c2efb..9d6cf17 100644 --- a/app.py +++ b/app.py @@ -1093,19 +1093,50 @@ def logout(): return redirect(url_for('login')) +from math import ceil + +# 每页显示的数量 +PER_PAGE = 10 + + @app.route('/cas') @login_required def ca_list(): + page = request.args.get('page', 1, type=int) conn = get_db_connection() if conn: try: cursor = conn.cursor(dictionary=True) + + # 获取总数 if current_user.is_admin: - cursor.execute("SELECT * FROM certificate_authorities") + cursor.execute("SELECT COUNT(*) as total FROM certificate_authorities") else: - cursor.execute("SELECT * FROM certificate_authorities WHERE created_by = %s", (current_user.id,)) + cursor.execute("SELECT COUNT(*) as total FROM certificate_authorities WHERE created_by = %s", + (current_user.id,)) + total = cursor.fetchone()['total'] + total_pages = ceil(total / PER_PAGE) + + # 获取分页数据 + offset = (page - 1) * PER_PAGE + if current_user.is_admin: + cursor.execute("SELECT * FROM certificate_authorities ORDER BY created_at DESC LIMIT %s OFFSET %s", + (PER_PAGE, offset)) + else: + cursor.execute(""" + SELECT * FROM certificate_authorities + WHERE created_by = %s + ORDER BY created_at DESC + LIMIT %s OFFSET %s + """, (current_user.id, PER_PAGE, offset)) cas = cursor.fetchall() - return render_template('ca_list.html', cas=cas, get_username=get_username) + + return render_template('ca_list.html', + cas=cas, + page=page, + total_pages=total_pages, + total=total, + get_username=get_username) except Error as e: print(f"Database error: {e}") flash('获取CA列表失败', 'danger') @@ -1117,6 +1148,204 @@ def ca_list(): return redirect(url_for('index')) +@app.route('/cas/batch_delete', methods=['POST']) +@login_required +def batch_delete_cas(): + if not request.is_json: + return jsonify({'success': False, 'message': 'Invalid request'}), 400 + + data = request.get_json() + ca_ids = data.get('ids', []) + + if not ca_ids: + return jsonify({'success': False, 'message': 'No CAs selected'}), 400 + + conn = get_db_connection() + if not conn: + return jsonify({'success': False, 'message': 'Database connection failed'}), 500 + + try: + cursor = conn.cursor() + + # 检查权限并删除 + for ca_id in ca_ids: + # 验证CA存在且用户有权限 + cursor.execute("SELECT created_by FROM certificate_authorities WHERE id = %s", (ca_id,)) + ca = cursor.fetchone() + + if not ca: + continue + + if not current_user.is_admin and ca['created_by'] != current_user.id: + continue + + # 检查是否有关联证书 + cursor.execute("SELECT COUNT(*) as count FROM certificates WHERE ca_id = %s", (ca_id,)) + result = cursor.fetchone() + if result['count'] > 0: + continue + + # 获取CA信息以便删除文件 + cursor.execute("SELECT cert_path, key_path FROM certificate_authorities WHERE id = %s", (ca_id,)) + ca_info = cursor.fetchone() + + if ca_info: + # 删除文件 + try: + if os.path.exists(ca_info['cert_path']): + os.remove(ca_info['cert_path']) + if os.path.exists(ca_info['key_path']): + os.remove(ca_info['key_path']) + + # 删除CA目录 + ca_dir = os.path.dirname(ca_info['cert_path']) + if os.path.exists(ca_dir): + shutil.rmtree(ca_dir) # 递归删除目录 + except OSError as e: + print(f"文件删除错误: {e}") + continue + + # 删除数据库记录 + cursor.execute("DELETE FROM certificate_revocation_list WHERE ca_id = %s", (ca_id,)) + cursor.execute("DELETE FROM certificate_authorities WHERE id = %s", (ca_id,)) + + conn.commit() + return jsonify({'success': True, 'message': '批量删除成功'}) + + except Error as e: + conn.rollback() + print(f"Database error: {e}") + return jsonify({'success': False, 'message': '数据库操作失败'}), 500 + finally: + if conn.is_connected(): + cursor.close() + conn.close() + + +@app.route('/certificates') +@login_required +def certificate_list(): + page = request.args.get('page', 1, type=int) + conn = get_db_connection() + if conn: + try: + cursor = conn.cursor(dictionary=True) + + # 获取总数 + if current_user.is_admin: + cursor.execute("SELECT COUNT(*) as total FROM certificates") + else: + cursor.execute("SELECT COUNT(*) as total FROM certificates WHERE created_by = %s", (current_user.id,)) + total = cursor.fetchone()['total'] + total_pages = ceil(total / PER_PAGE) + + # 获取分页数据 + offset = (page - 1) * PER_PAGE + if current_user.is_admin: + cursor.execute(""" + SELECT c.*, ca.name as ca_name + FROM certificates c + JOIN certificate_authorities ca ON c.ca_id = ca.id + ORDER BY c.created_at DESC + LIMIT %s OFFSET %s + """, (PER_PAGE, offset)) + else: + cursor.execute(""" + SELECT c.*, ca.name as ca_name + FROM certificates c + JOIN certificate_authorities ca ON c.ca_id = ca.id + WHERE c.created_by = %s + ORDER BY c.created_at DESC + LIMIT %s OFFSET %s + """, (current_user.id, PER_PAGE, offset)) + certificates = cursor.fetchall() + + return render_template('certificate_list.html', + certificates=certificates, + page=page, + total_pages=total_pages, + total=total, + get_username=get_username) + except Error as e: + print(f"Database error: {e}") + flash('获取证书列表失败', 'danger') + return redirect(url_for('index')) + finally: + if conn.is_connected(): + cursor.close() + conn.close() + return redirect(url_for('index')) + + +@app.route('/certificates/batch_delete', methods=['POST']) +@login_required +def batch_delete_certificates(): + if not request.is_json: + return jsonify({'success': False, 'message': 'Invalid request'}), 400 + + data = request.get_json() + cert_ids = data.get('ids', []) + + if not cert_ids: + return jsonify({'success': False, 'message': 'No certificates selected'}), 400 + + conn = get_db_connection() + if not conn: + return jsonify({'success': False, 'message': 'Database connection failed'}), 500 + + try: + cursor = conn.cursor(dictionary=True) + + # 检查权限并删除 + for cert_id in cert_ids: + # 验证证书存在且用户有权限 + cursor.execute("SELECT created_by, cert_path, key_path, csr_path FROM certificates WHERE id = %s", + (cert_id,)) + cert = cursor.fetchone() + + if not cert: + continue + + if not current_user.is_admin and cert['created_by'] != current_user.id: + continue + + # 删除文件 + try: + files_to_delete = [ + cert['cert_path'], + cert['key_path'], + cert['csr_path'] + ] + + # 删除所有指定文件 + for file_path in files_to_delete: + if file_path and os.path.exists(file_path): + os.remove(file_path) + + # 删除证书目录 + cert_dir = os.path.dirname(cert['cert_path']) + if os.path.exists(cert_dir): + shutil.rmtree(cert_dir) # 递归删除目录 + except OSError as e: + print(f"文件删除错误: {e}") + continue + + # 删除数据库记录 + cursor.execute("DELETE FROM certificates WHERE id = %s", (cert_id,)) + + conn.commit() + return jsonify({'success': True, 'message': '批量删除成功'}) + + except Error as e: + conn.rollback() + print(f"Database error: {e}") + return jsonify({'success': False, 'message': '数据库操作失败'}), 500 + finally: + if conn.is_connected(): + cursor.close() + conn.close() + + @app.route('/cas/create', methods=['GET', 'POST']) @login_required def create_ca_view(): diff --git a/templates/ca_list.html b/templates/ca_list.html index fa00d2e..f24ab25 100644 --- a/templates/ca_list.html +++ b/templates/ca_list.html @@ -7,12 +7,17 @@

CA机构列表

- 共 {{ cas|length }} 个CA机构 + 共 {{ total }} 个CA机构
- - 创建CA机构 - +
+ + + 创建CA机构 + +
@@ -21,7 +26,10 @@ - + + @@ -34,7 +42,10 @@ {% for ca in cas %} - + + {% else %} -
ID + + ID 名称 通用名 组织
{{ ca.id }} + + {{ ca.id }} {{ ca.name }} @@ -56,7 +67,7 @@
+

暂无CA机构记录

@@ -68,6 +79,107 @@
+ + {% if total_pages > 1 %} + + {% endif %} +{% endblock %} + +{% block scripts %} +{{ super() }} + {% endblock %} \ No newline at end of file diff --git a/templates/certificate_list.html b/templates/certificate_list.html index 38cfb84..353ffbe 100644 --- a/templates/certificate_list.html +++ b/templates/certificate_list.html @@ -7,12 +7,17 @@

证书列表

- 共 {{ certificates|length }} 个证书 + 共 {{ total }} 个证书
- - 创建证书 - +
+ + + 创建证书 + +
@@ -21,7 +26,10 @@ - + + @@ -33,7 +41,10 @@ {% for cert in certificates %} - + + {% else %} -
ID + + ID 通用名 CA机构 状态
{{ cert.id }} + + {{ cert.id }} {{ cert.common_name }} @@ -84,7 +95,7 @@
+

暂无证书记录

@@ -96,6 +107,32 @@
+ + {% if total_pages > 1 %} + + {% endif %} {% endblock %} @@ -103,12 +140,74 @@ {% block scripts %} {{ super() }} {% endblock %} \ No newline at end of file