支持删除CA和证书
This commit is contained in:
parent
56b4a91972
commit
fd9f2d6e52
147
app.py
147
app.py
@ -130,6 +130,54 @@ def verify_captcha(user_input):
|
|||||||
conn.close()
|
conn.close()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def validate_name(name, max_length=64):
|
||||||
|
"""
|
||||||
|
校验名称是否符合规范
|
||||||
|
规则:
|
||||||
|
1. 长度1-64个字符
|
||||||
|
2. 只能包含字母、数字、中文、下划线、短横线
|
||||||
|
3. 不能以短横线开头或结尾
|
||||||
|
"""
|
||||||
|
if not name or len(name) > max_length:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 允许中文、字母、数字、下划线、短横线
|
||||||
|
pattern = r'^[a-zA-Z0-9_\-\u4e00-\u9fa5]+$'
|
||||||
|
if not re.match(pattern, name):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 不能以短横线开头或结尾
|
||||||
|
if name.startswith('-') or name.endswith('-'):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def validate_common_name(cn):
|
||||||
|
"""
|
||||||
|
校验通用名(Common Name)是否符合规范
|
||||||
|
规则:
|
||||||
|
1. 长度1-64个字符
|
||||||
|
2. 只能包含字母、数字、点号(.)和短横线(-)
|
||||||
|
3. 不能以点号或短横线开头或结尾
|
||||||
|
4. 不能连续两个点号或短横线
|
||||||
|
"""
|
||||||
|
if not cn or len(cn) > 64:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 只允许字母、数字、点号和短横线
|
||||||
|
if not re.match(r'^[a-zA-Z0-9.-]+$', cn):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 不能以点号或短横线开头或结尾
|
||||||
|
if cn.startswith('.') or cn.endswith('.') or cn.startswith('-') or cn.endswith('-'):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 不能连续两个点号或短横线
|
||||||
|
if '..' in cn or '--' in cn:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def create_ca(ca_name, common_name, organization, organizational_unit, country, state, locality, key_size, days_valid,
|
def create_ca(ca_name, common_name, organization, organizational_unit, country, state, locality, key_size, days_valid,
|
||||||
created_by):
|
created_by):
|
||||||
@ -625,16 +673,43 @@ def ca_list():
|
|||||||
@login_required
|
@login_required
|
||||||
def create_ca_view():
|
def create_ca_view():
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
ca_name = request.form['ca_name']
|
ca_name = request.form['ca_name'].strip()
|
||||||
common_name = request.form['common_name']
|
common_name = request.form['common_name'].strip()
|
||||||
organization = request.form['organization']
|
organization = request.form['organization'].strip()
|
||||||
organizational_unit = request.form['organizational_unit']
|
organizational_unit = request.form['organizational_unit'].strip()
|
||||||
country = request.form['country']
|
country = request.form['country'].strip()
|
||||||
state = request.form['state']
|
state = request.form['state'].strip()
|
||||||
locality = request.form['locality']
|
locality = request.form['locality'].strip()
|
||||||
key_size = int(request.form['key_size'])
|
key_size = int(request.form['key_size'])
|
||||||
days_valid = int(request.form['days_valid'])
|
days_valid = int(request.form['days_valid'])
|
||||||
|
|
||||||
|
# 名称校验
|
||||||
|
if not validate_name(ca_name):
|
||||||
|
flash('CA名称无效:只能包含中文、字母、数字、下划线和短横线,且不能以短横线开头或结尾', 'danger')
|
||||||
|
return render_template('create_ca.html')
|
||||||
|
|
||||||
|
if not validate_common_name(common_name):
|
||||||
|
flash('通用名无效:只能包含字母、数字、点号和短横线,且不能以点号或短横线开头或结尾', 'danger')
|
||||||
|
return render_template('create_ca.html')
|
||||||
|
|
||||||
|
# 检查CA名称是否已存在
|
||||||
|
conn = get_db_connection()
|
||||||
|
if conn:
|
||||||
|
try:
|
||||||
|
cursor = conn.cursor(dictionary=True)
|
||||||
|
cursor.execute("SELECT id FROM certificate_authorities WHERE name = %s", (ca_name,))
|
||||||
|
if cursor.fetchone():
|
||||||
|
flash('CA名称已存在,请使用其他名称', 'danger')
|
||||||
|
return render_template('create_ca.html')
|
||||||
|
except Error as e:
|
||||||
|
print(f"Database error: {e}")
|
||||||
|
flash('检查CA名称失败', 'danger')
|
||||||
|
return render_template('create_ca.html')
|
||||||
|
finally:
|
||||||
|
if conn.is_connected():
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
ca_id = create_ca(ca_name, common_name, organization, organizational_unit,
|
ca_id = create_ca(ca_name, common_name, organization, organizational_unit,
|
||||||
country, state, locality, key_size, days_valid, current_user.id)
|
country, state, locality, key_size, days_valid, current_user.id)
|
||||||
|
|
||||||
@ -646,7 +721,6 @@ def create_ca_view():
|
|||||||
|
|
||||||
return render_template('create_ca.html')
|
return render_template('create_ca.html')
|
||||||
|
|
||||||
|
|
||||||
from datetime import timedelta # 确保顶部已导入
|
from datetime import timedelta # 确保顶部已导入
|
||||||
|
|
||||||
@app.route('/cas/<int:ca_id>')
|
@app.route('/cas/<int:ca_id>')
|
||||||
@ -821,18 +895,58 @@ def certificate_list():
|
|||||||
@login_required
|
@login_required
|
||||||
def create_certificate_view():
|
def create_certificate_view():
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
common_name = request.form['common_name']
|
common_name = request.form['common_name'].strip()
|
||||||
san_dns = request.form.get('san_dns', '')
|
san_dns = request.form.get('san_dns', '').strip()
|
||||||
san_ip = request.form.get('san_ip', '')
|
san_ip = request.form.get('san_ip', '').strip()
|
||||||
organization = request.form['organization']
|
organization = request.form['organization'].strip()
|
||||||
organizational_unit = request.form['organizational_unit']
|
organizational_unit = request.form['organizational_unit'].strip()
|
||||||
country = request.form['country']
|
country = request.form['country'].strip()
|
||||||
state = request.form['state']
|
state = request.form['state'].strip()
|
||||||
locality = request.form['locality']
|
locality = request.form['locality'].strip()
|
||||||
key_size = int(request.form['key_size'])
|
key_size = int(request.form['key_size'])
|
||||||
days_valid = int(request.form['days_valid'])
|
days_valid = int(request.form['days_valid'])
|
||||||
ca_id = int(request.form['ca_id'])
|
ca_id = int(request.form['ca_id'])
|
||||||
|
|
||||||
|
# 通用名校验
|
||||||
|
if not validate_common_name(common_name):
|
||||||
|
flash('通用名无效:只能包含字母、数字、点号和短横线,且不能以点号或短横线开头或结尾', 'danger')
|
||||||
|
return redirect(url_for('create_certificate_view'))
|
||||||
|
|
||||||
|
# SAN DNS校验
|
||||||
|
if san_dns:
|
||||||
|
for dns in san_dns.split(','):
|
||||||
|
dns = dns.strip()
|
||||||
|
if not validate_common_name(dns):
|
||||||
|
flash(f'DNS SAN条目无效: {dns},只能包含字母、数字、点号和短横线', 'danger')
|
||||||
|
return redirect(url_for('create_certificate_view'))
|
||||||
|
|
||||||
|
# SAN IP校验
|
||||||
|
if san_ip:
|
||||||
|
for ip in san_ip.split(','):
|
||||||
|
ip = ip.strip()
|
||||||
|
if not re.match(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$', ip):
|
||||||
|
flash(f'IP SAN条目无效: {ip},请输入有效的IPv4地址', 'danger')
|
||||||
|
return redirect(url_for('create_certificate_view'))
|
||||||
|
|
||||||
|
# 检查证书是否已存在
|
||||||
|
conn = get_db_connection()
|
||||||
|
if conn:
|
||||||
|
try:
|
||||||
|
cursor = conn.cursor(dictionary=True)
|
||||||
|
cursor.execute("SELECT id FROM certificates WHERE common_name = %s AND ca_id = %s",
|
||||||
|
(common_name, ca_id))
|
||||||
|
if cursor.fetchone():
|
||||||
|
flash('该CA下已存在相同通用名的证书', 'danger')
|
||||||
|
return redirect(url_for('create_certificate_view'))
|
||||||
|
except Error as e:
|
||||||
|
print(f"Database error: {e}")
|
||||||
|
flash('检查证书名称失败', 'danger')
|
||||||
|
return redirect(url_for('create_certificate_view'))
|
||||||
|
finally:
|
||||||
|
if conn.is_connected():
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
cert_id = create_certificate(ca_id, common_name, san_dns, san_ip, organization,
|
cert_id = create_certificate(ca_id, common_name, san_dns, san_ip, organization,
|
||||||
organizational_unit, country, state, locality,
|
organizational_unit, country, state, locality,
|
||||||
key_size, days_valid, current_user.id)
|
key_size, days_valid, current_user.id)
|
||||||
@ -867,7 +981,6 @@ def create_certificate_view():
|
|||||||
conn.close()
|
conn.close()
|
||||||
return redirect(url_for('certificate_list'))
|
return redirect(url_for('certificate_list'))
|
||||||
|
|
||||||
|
|
||||||
@app.route('/certificates/<int:cert_id>')
|
@app.route('/certificates/<int:cert_id>')
|
||||||
@login_required
|
@login_required
|
||||||
def certificate_detail(cert_id):
|
def certificate_detail(cert_id):
|
||||||
|
|||||||
@ -12,12 +12,16 @@
|
|||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label for="ca_name" class="form-label">CA名称</label>
|
<label for="ca_name" class="form-label">CA名称</label>
|
||||||
<input type="text" class="form-control" id="ca_name" name="ca_name" required>
|
<input type="text" class="form-control" id="ca_name" name="ca_name"
|
||||||
|
required pattern="[a-zA-Z0-9_\-\u4e00-\u9fa5]+"
|
||||||
|
title="只能包含中文、字母、数字、下划线和短横线,且不能以短横线开头或结尾">
|
||||||
<div class="form-text">CA机构的显示名称</div>
|
<div class="form-text">CA机构的显示名称</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label for="common_name" class="form-label">通用名(CN)</label>
|
<label for="common_name" class="form-label">通用名(CN)</label>
|
||||||
<input type="text" class="form-control" id="common_name" name="common_name" required>
|
<input type="text" class="form-control" id="common_name" name="common_name"
|
||||||
|
required pattern="[a-zA-Z0-9.-]+"
|
||||||
|
title="只能包含字母、数字、点号和短横线,且不能以点号或短横线开头或结尾">
|
||||||
<div class="form-text">证书的Common Name字段</div>
|
<div class="form-text">证书的Common Name字段</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -12,7 +12,9 @@
|
|||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label for="common_name" class="form-label">通用名(CN)</label>
|
<label for="common_name" class="form-label">通用名(CN)</label>
|
||||||
<input type="text" class="form-control" id="common_name" name="common_name" required>
|
<input type="text" class="form-control" id="common_name" name="common_name"
|
||||||
|
required pattern="[a-zA-Z0-9.-]+"
|
||||||
|
title="只能包含字母、数字、点号和短横线,且不能以点号或短横线开头或结尾">
|
||||||
<div class="form-text">证书的Common Name字段,通常是域名</div>
|
<div class="form-text">证书的Common Name字段,通常是域名</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
@ -56,12 +58,16 @@
|
|||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label for="san_dns" class="form-label">SAN DNS (可选)</label>
|
<label for="san_dns" class="form-label">SAN DNS (可选)</label>
|
||||||
<input type="text" class="form-control" id="san_dns" name="san_dns">
|
<input type="text" class="form-control" id="common_name" name="common_name"
|
||||||
|
required pattern="[a-zA-Z0-9.-]+"
|
||||||
|
title="只能包含字母、数字、点号和短横线,且不能以点号或短横线开头或结尾">
|
||||||
<div class="form-text">多个DNS用逗号分隔,如: example.com,www.example.com</div>
|
<div class="form-text">多个DNS用逗号分隔,如: example.com,www.example.com</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label for="san_ip" class="form-label">SAN IP (可选)</label>
|
<label for="san_ip" class="form-label">SAN IP (可选)</label>
|
||||||
<input type="text" class="form-control" id="san_ip" name="san_ip">
|
<input type="text" class="form-control" id="common_name" name="common_name"
|
||||||
|
required pattern="[a-zA-Z0-9.-]+"
|
||||||
|
title="只能包含字母、数字、点号和短横线,且不能以点号或短横线开头或结尾">
|
||||||
<div class="form-text">多个IP用逗号分隔,如: 192.168.1.1,10.0.0.1</div>
|
<div class="form-text">多个IP用逗号分隔,如: 192.168.1.1,10.0.0.1</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user