Skip to content

Commit

Permalink
1.2.1-pro
Browse files Browse the repository at this point in the history
  • Loading branch information
Xingsandesu committed Jan 15, 2024
1 parent 05d594f commit 5f0e18b
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 25 deletions.
68 changes: 67 additions & 1 deletion app.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import base64
import json
import os
import platform
import re

from flask import Flask, request, jsonify, render_template, send_from_directory
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.asymmetric import rsa
from flask import Flask, request, jsonify, render_template, send_from_directory, abort
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from tornado.wsgi import WSGIContainer
Expand All @@ -13,6 +20,62 @@

asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

# 检查公钥文件是否存在
if not os.path.exists("public_key.pem") or not os.path.exists("private_key.pem"):
# 生成私钥
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)

# 生成公钥
public_key = private_key.public_key()

# 将私钥保存到文件
with open("private_key.pem", "wb") as key_file:
key_file.write(
private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
)

# 将公钥保存到文件
with open("public_key.pem", "wb") as key_file:
key_file.write(
public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
)

# 读取公钥
with open("public_key.pem", "rb") as key_file:
public_key = serialization.load_pem_public_key(key_file.read())


def verify_signature(request):
signature = request.headers.get('X-Signature')
if not signature:
abort(401, '缺少签名')

signature = base64.b64decode(signature)
try:
public_key.verify(
signature,
request.data,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
except InvalidSignature:
abort(401, '无效的签名')


app = Flask(__name__)


Expand Down Expand Up @@ -45,6 +108,7 @@ def docker_run():

@app.route('/confirm', methods=['POST'])
def confirm():
verify_signature(request)
container_config = request.json.get('container_config')
description = request.json.get('description') # 获取软件简介
try:
Expand Down Expand Up @@ -90,6 +154,7 @@ def app_json():

@app.route('/delete/<app_name>', methods=['DELETE'])
def delete_app(app_name):
verify_signature(request)
try:
# 删除 run.json 文件
run_json_path = f'app/{app_name}/run.json'
Expand Down Expand Up @@ -117,6 +182,7 @@ def delete_app(app_name):
except json.JSONDecodeError as e:
return jsonify({"message": f"JSON操作错误: {str(e)}"}), 500


if __name__ == '__main__':
s = HTTPServer(WSGIContainer(app))
port = 10010
Expand Down
6 changes: 5 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,8 @@ fushin/taichi_os_software_source

## TaiChi OS 软件商店部署

左上角-软件商店-TaiChi OS软件源-安装
左上角-软件商店-TaiChi OS软件源-安装

## Pro分支

添加公私钥加密的版本
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
Flask~=3.0.0
tornado == 6.4
tornado == 6.4
cryptography
112 changes: 90 additions & 22 deletions templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,37 +57,65 @@ <h5>联系方式</h5>
<div id="description-editor" class="mt-4" style="height: 100px;"></div>
<button id="confirm" class="btn btn-success mt-2" disabled>确认</button>
</div>

<input type="file" id="private-key" class="form-control mt-4" style="display: none;">
<button id="upload-private-key" class="btn btn-secondary mt-2">上传私钥</button>
<script>
async function signData(privateKey, data) {
const encoder = new TextEncoder();
const encodedData = encoder.encode(data);

const signature = await window.crypto.subtle.sign(
{
name: "RSASSA-PKCS1-v1_5",
},
privateKey,
encodedData
);

return window.btoa(String.fromCharCode.apply(null, new Uint8Array(signature)));
}

function refreshSoftwareList() {
$('#software-table').empty();
$.getJSON('app.json', function(data) {
$.getJSON('app.json', async function (data) {
var table = $('<table>').addClass('table');
var thead = $('<thead>');
var tbody = $('<tbody>');
thead.append('<tr><th>已有软件</th><th>链接</th><th>描述</th><th>操作</th></tr>'); // 添加新的表头
thead.append('<tr><th>已有软件</th><th>链接</th><th>描述</th><th>操作</th></tr>');
table.append(thead);

$.each(data, function(key, value) {
$.each(data, async function (key, value) {
var row = $('<tr>');
row.append($('<td>').text(key));
row.append($('<td>').html('<a href="' + value.url + '">' + value.url + '</a>')); // 修改链接的获取方式
row.append($('<td>').text(value.description || '')); // 添加新的描述列
var deleteButton = $('<button>').text('删除').addClass('btn btn-danger btn-sm'); // 创建删除按钮
row.append($('<td>').append(deleteButton)); // 将删除按钮添加到行中
row.append($('<td>').html('<a href="' + value.url + '">' + value.url + '</a>'));
row.append($('<td>').text(value.description || ''));
var deleteButton = $('<button>').text('删除').addClass('btn btn-danger btn-sm');
row.append($('<td>').append(deleteButton));
tbody.append(row);

// 为删除按钮添加点击事件处理器
deleteButton.click(function () {
deleteButton.click(async function () {
var privateKey = sessionStorage.getItem('privateKey');
if (!privateKey) {
alert('请先上传私钥');
return;
}
const signature = await signData(privateKey, '/delete/' + key);
$.ajax({
url: '/delete/' + key,
type: 'DELETE',
headers: {
'X-Signature': signature
},
success: function (data) {
alert(data.message);
refreshSoftwareList(); // 刷新软件源列表
refreshSoftwareList();
},
error: function (jqXHR) {
alert('删除失败: ' + jqXHR.responseJSON.message);
var message = '删除失败';
if (jqXHR.responseJSON && jqXHR.responseJSON.message) {
message += ': ' + jqXHR.responseJSON.message;
}
alert(message);
}
});
});
Expand All @@ -97,6 +125,7 @@ <h5>联系方式</h5>
$('#software-table').append(table);
});
}

var editor = ace.edit("editor");
editor.setTheme("ace/theme/monokai");
editor.session.setMode("ace/mode/json");
Expand All @@ -106,47 +135,86 @@ <h5>联系方式</h5>
descriptionEditor.session.setMode("ace/mode/text");
descriptionEditor.setValue("作者没有添加描述...");

$('#run').click(function() {
$('#run').click(async function () {
var command = $('#command').val();
var privateKey = sessionStorage.getItem('privateKey');
if (!privateKey) {
alert('请先上传私钥');
return;
}
const signature = await signData(privateKey, JSON.stringify({command: command}));
$.ajax({
url: '/source',
type: 'POST',
data: JSON.stringify({command: command}),
headers: {
'X-Signature': signature
},
contentType: 'application/json',
success: function(data) {
success: function (data) {
editor.setValue(JSON.stringify(data, null, 4));
$('#confirm').prop('disabled', false);
}
});
$('#command').val('');
});

$('#confirm').click(function() {
$('#confirm').click(async function () {
try {
var container_config = JSON.parse(editor.getValue());
var description = descriptionEditor.getValue(); // 获取软件简介
var description = descriptionEditor.getValue();
if (!container_config.hasOwnProperty('name')) {
throw new Error('缺少必需的属性: name');
}
var privateKey = sessionStorage.getItem('privateKey');
if (!privateKey) {
alert('请先上传私钥');
return;
}
const signature = await signData(privateKey, JSON.stringify({
container_config: container_config,
description: description,
privateKey: privateKey
}));
$.ajax({
url: '/confirm',
type: 'POST',
data: JSON.stringify({container_config: container_config, description: description}), // 将软件简介一起发送
data: JSON.stringify({
container_config: container_config,
description: description,
privateKey: privateKey
}),
headers: {
'X-Signature': signature
},
contentType: 'application/json',
success: function(data) {
success: function (data) {
alert(data.message);
$('#confirm').prop('disabled', true);
editor.setValue(''); // 清空编辑器内容
descriptionEditor.setValue(''); // 清空软件简介编辑器内容
refreshSoftwareList(); // 刷新软件源列表
editor.setValue('');
descriptionEditor.setValue('');
refreshSoftwareList();
}
});
} catch (e) {
alert('JSON 格式错误: ' + e.message);
}
});

refreshSoftwareList(); // 页面加载时刷新软件源列表
$('#upload-private-key').click(function () {
$('#private-key').click();
});

$('#private-key').change(function () {
var file = this.files[0];
var reader = new FileReader();
reader.onload = function (e) {
sessionStorage.setItem('privateKey', e.target.result);
};
reader.readAsText(file);
});

refreshSoftwareList();
</script>
</body>
</html>

0 comments on commit 5f0e18b

Please sign in to comment.