Skip to content

Commit e7cd569

Browse files
authored
Merge pull request #115 from LuSrackhall/albumExportSignature
专辑导出的流程中的签名功能实现, 包含签名申请, 签名申请的受理, 签名授权的导出, 签名授权的导入等功能。
2 parents e5d4338 + 75f4526 commit e7cd569

File tree

83 files changed

+18095
-168
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+18095
-168
lines changed

.github/workflows/cd.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on:
44
push:
55
tags:
66
- "*"
7+
workflow_dispatch:
78

89
jobs:
910
build:

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
/sdk/log.jsonl
88
/sdk/temporaryDebug
99

10+
# Private Keys
11+
private_keys.env
12+
1013
*.syso
1114

1215
.DS_Store

build.sh

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#!/bin/bash
2+
# =============================================================================
3+
# 统一构建入口脚本
4+
# 用法: ./build.sh <platform>
5+
# 支持平台: win | mac | linux
6+
# =============================================================================
7+
8+
set -euo pipefail # 黄金三件套,严格模式
9+
IFS=$'\n\t' # 安全的字段分隔符
10+
11+
cd sdk
12+
13+
# 颜色输出(好看 + 专业)
14+
RED='\033[0;31m'
15+
GREEN='\033[0;32m'
16+
YELLOW='\033[1;33m'
17+
NC='\033[0m' # No Color
18+
19+
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
20+
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
21+
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
22+
die() { error "$*"; exit 1; }
23+
24+
# ============ 参数解析 ============
25+
show_help() {
26+
cat << EOF
27+
用法: ./build.sh <平台>
28+
29+
支持的平台:
30+
win 构建 Windows 版本(默认)
31+
mac 构建 macOS 版本
32+
linux 构建 Linux 版本
33+
34+
示例:
35+
./build.sh win
36+
./build.sh mac
37+
./build.sh linux
38+
./build.sh -h 显示此帮助
39+
40+
提示: 你也可以直接运行 ./build.sh(不带参数)默认构建 Windows
41+
EOF
42+
}
43+
44+
PLATFORM="win" # 默认平台
45+
46+
while [[ $# -gt 0 ]]; do
47+
case $1 in
48+
-h|--help)
49+
show_help
50+
exit 0
51+
;;
52+
win|mac|linux)
53+
PLATFORM="$1"
54+
shift
55+
;;
56+
*)
57+
error "未知参数: $1"
58+
show_help
59+
exit 1
60+
;;
61+
esac
62+
done
63+
64+
info "目标平台: $PLATFORM"
65+
66+
# ============ 加载密钥环境(关键!)============
67+
info "正在加载密钥环境..."
68+
if source ./setup_build_env.sh; then
69+
info "密钥环境加载成功"
70+
else
71+
die "密钥环境加载失败,请检查 private_keys.env 是否存在并已填写"
72+
fi
73+
74+
# ============ 执行构建 ============
75+
76+
case "$PLATFORM" in
77+
win)
78+
info "开始构建 Windows 版本..."
79+
make win
80+
;;
81+
mac)
82+
info "开始构建 macOS 版本..."
83+
make mac
84+
;;
85+
linux)
86+
info "开始构建 Linux 版本..."
87+
make linux
88+
;;
89+
*)
90+
die "不支持的平台: $PLATFORM"
91+
;;
92+
esac
93+
94+
# ============ 成功提示 ============
95+
info "恭喜!$PLATFORM 构建完成!"
96+
echo
97+
echo "输出目录示例(根据你的 Makefile 实际为准):"
98+
case "$PLATFORM" in
99+
win) echo " ./dist/KeyToneSetup.exe" ;;
100+
mac) echo " ./dist/KeyTone.app" ;;
101+
linux) echo " ./dist/keytone-linux-x64" ;;
102+
esac
103+
echo

dev.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
cd sdk
5+
6+
# 加载密钥环境(失败直接退出,不需要额外提示)
7+
source ./setup_build_env.sh || exit 1
8+
9+
cd ../frontend
10+
quasar dev -m electron

frontend/src-electron/debug.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@
44
cd ../sdk || exit
55

66
# 执行 Go 构建命令
7-
go build -o ../frontend/src-electron/sdk-debug/KeyTone.exe
7+
# -ldflags "$EXTRA_LDFLAGS": 注入环境变量中定义的额外链接参数(如混淆后的密钥)
8+
# 如果 EXTRA_LDFLAGS 为空,则不注入任何额外参数,使用代码中的默认值。
9+
go build -ldflags "$EXTRA_LDFLAGS" -o ../frontend/src-electron/sdk-debug/KeyTone.exe

frontend/src/boot/query/keytonePkg-query.ts

Lines changed: 172 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
import { api } from 'boot/axios';
2+
import type {
3+
ApplySignatureConfigPayload,
4+
AlbumSignatureInfo,
5+
AvailableSignature,
6+
CheckSignatureInAlbumResult,
7+
} from 'src/types/export-flow';
28

39
export async function SendFileToServer(file: File) {
410
const formData = new FormData();
@@ -524,6 +530,158 @@ export async function GetAlbumMeta(file: File): Promise<AlbumMeta> {
524530
}
525531
}
526532

533+
// 加密专辑配置(仅在需要签名时调用)
534+
export async function EncryptAlbumConfig(albumPath: string): Promise<{
535+
message: string;
536+
encrypted?: boolean;
537+
already_encrypted?: boolean;
538+
}> {
539+
if (!albumPath) {
540+
throw new Error('缺少 albumPath');
541+
}
542+
return await api
543+
.post('/keytone_pkg/encrypt_album_config', { albumPath })
544+
.then((response) => {
545+
console.debug('status=', response.status, '->EncryptAlbumConfig 请求已成功执行并返回');
546+
if (response.status === 200) {
547+
return response.data;
548+
}
549+
throw new Error('加密配置失败');
550+
})
551+
.catch((error) => {
552+
console.group('EncryptAlbumConfig 请求执行失败');
553+
console.error('加密专辑配置失败:', error);
554+
if (error.response?.data?.message) {
555+
console.error('服务器返回:', error.response.data.message);
556+
}
557+
console.groupEnd();
558+
throw error;
559+
});
560+
}
561+
562+
// 将签名/授权决策发送到 SDK,供后续写入专辑配置
563+
export async function ApplySignatureConfig(payload: ApplySignatureConfigPayload): Promise<boolean> {
564+
return await api
565+
.post('/keytone_pkg/apply_signature_config', payload)
566+
.then((response) => {
567+
console.debug('status=', response.status, '->ApplySignatureConfig 请求已成功执行并返回->', response.data);
568+
if (response.status === 200) {
569+
return true;
570+
}
571+
throw new Error('应用签名配置失败');
572+
})
573+
.catch((error) => {
574+
console.group('ApplySignatureConfig 请求执行失败');
575+
if (error.response) {
576+
console.error('Error status:', error.response.status);
577+
console.error('Error data:', error.response.data);
578+
} else if (error.request) {
579+
console.error('Error:', '请求已经发出,但是没有收到响应');
580+
console.error('Error request:', error.request);
581+
} else {
582+
console.error('Error:', '请求未正常发出,请检查请求地址是否正确');
583+
console.error('Error message:', error.message);
584+
}
585+
console.error('Error config:', error.config);
586+
console.groupEnd();
587+
throw error;
588+
});
589+
}
590+
591+
/**
592+
* 获取专辑签名信息
593+
* 用于前端需求2(再次导出时的签名识别)和需求4(签名作者信息展示)
594+
*/
595+
export async function GetAlbumSignatureInfo(albumPath: string): Promise<AlbumSignatureInfo> {
596+
return await api
597+
.post('/keytone_pkg/get_album_signature_info', { albumPath })
598+
.then((response) => {
599+
console.debug('GetAlbumSignatureInfo 成功:', response.data);
600+
if (response.status === 200 && response.data.message === 'ok') {
601+
return response.data.data;
602+
}
603+
throw new Error('获取专辑签名信息失败');
604+
})
605+
.catch((error) => {
606+
console.error('GetAlbumSignatureInfo 失败:', error);
607+
throw error;
608+
});
609+
}
610+
611+
/**
612+
* 检查签名是否在专辑中
613+
* 用于前端需求3(标记已在专辑中的签名)
614+
*/
615+
export async function CheckSignatureInAlbum(
616+
albumPath: string,
617+
signatureId: string
618+
): Promise<CheckSignatureInAlbumResult> {
619+
return await api
620+
.post('/keytone_pkg/check_signature_in_album', { albumPath, signatureId })
621+
.then((response) => {
622+
console.debug('CheckSignatureInAlbum 成功:', response.data);
623+
if (response.status === 200 && response.data.message === 'ok') {
624+
return {
625+
isInAlbum: response.data.isInAlbum,
626+
qualificationCode: response.data.qualificationCode,
627+
hasChanges: response.data.hasChanges,
628+
};
629+
}
630+
throw new Error('检查签名失败');
631+
})
632+
.catch((error) => {
633+
console.error('CheckSignatureInAlbum 失败:', error);
634+
throw error;
635+
});
636+
}
637+
638+
/**
639+
* 检查签名授权状态
640+
* 用于前端需求3(使能/失能签名选项)
641+
*/
642+
export async function CheckSignatureAuthorization(
643+
albumPath: string,
644+
signatureId: string
645+
): Promise<{ isAuthorized: boolean; requireAuthorization: boolean; qualificationCode: string }> {
646+
return await api
647+
.post('/keytone_pkg/check_signature_authorization', { albumPath, signatureId })
648+
.then((response) => {
649+
console.debug('CheckSignatureAuthorization 成功:', response.data);
650+
if (response.status === 200 && response.data.message === 'ok') {
651+
return {
652+
isAuthorized: response.data.isAuthorized,
653+
requireAuthorization: response.data.requireAuthorization,
654+
qualificationCode: response.data.qualificationCode,
655+
};
656+
}
657+
throw new Error('检查签名授权失败');
658+
})
659+
.catch((error) => {
660+
console.error('CheckSignatureAuthorization 失败:', error);
661+
throw error;
662+
});
663+
}
664+
665+
/**
666+
* 获取可用于导出的签名列表
667+
* 用于前端需求3(签名选择页面增强)
668+
*/
669+
export async function GetAvailableSignatures(albumPath: string): Promise<AvailableSignature[]> {
670+
return await api
671+
.post('/keytone_pkg/get_available_signatures', { albumPath })
672+
.then((response) => {
673+
console.debug('GetAvailableSignatures 成功:', response.data);
674+
if (response.status === 200 && response.data.message === 'ok') {
675+
return response.data.signatures;
676+
}
677+
throw new Error('获取可用签名列表失败');
678+
})
679+
.catch((error) => {
680+
console.error('GetAvailableSignatures 失败:', error);
681+
throw error;
682+
});
683+
}
684+
527685
// 导出专辑,直接返回zip文件内容
528686
export async function ExportAlbum(albumPath: string): Promise<Blob> {
529687
return await api
@@ -644,14 +802,14 @@ export async function ImportAlbumAsNew(file: File, newAlbumId: string): Promise<
644802
},
645803
})
646804
.then((response) => {
647-
console.debug('status=', response.status, '->ImportAlbumOverwrite 请求已成功执行并返回->', response.data);
805+
console.debug('status=', response.status, '->ImportAlbumAsNew 请求已成功执行并返回->', response.data);
648806
if (response.data.message === 'ok') {
649807
return true;
650808
}
651809
return false;
652810
})
653811
.catch((error) => {
654-
console.group('ImportAlbumOverwrite 请求执行失败');
812+
console.group('ImportAlbumAsNew 请求执行失败');
655813
if (error.response) {
656814
console.error('Error:', '请求已经发出且收到响应,但是服务器返回了一个非 2xx 的状态码');
657815
console.error('Error status:', error.response.status);
@@ -673,3 +831,15 @@ export async function ImportAlbumAsNew(file: File, newAlbumId: string): Promise<
673831
return false;
674832
});
675833
}
834+
835+
/**
836+
* 获取可用于导出的签名列表
837+
*/
838+
export async function GetAvailableSignaturesForExport(albumPath: string): Promise<AvailableSignature[]> {
839+
return await api.post('/keytone_pkg/get_available_signatures', { albumPath }).then((response) => {
840+
if (response.status === 200 && response.data.message === 'ok') {
841+
return response.data.signatures;
842+
}
843+
throw new Error('获取可用签名列表失败');
844+
});
845+
}

0 commit comments

Comments
 (0)