Skip to content

Commit c39dc0d

Browse files
committed
feat: 添加校验码功能
1 parent c1565d2 commit c39dc0d

File tree

8 files changed

+84
-7
lines changed

8 files changed

+84
-7
lines changed

.github/workflows/release.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,3 @@ jobs:
139139
uses: actions/attest-build-provenance@f9eaf234fc1c2e333c1eca18177db0f44fa6ba52 # v2
140140
with:
141141
subject-path: ${{ join(fromJson(steps.download.outputs.downloaded_files), ', ') }}
142-
subject-name: ExCaller ${{ github.event.release.tag_name }}

bun.lock

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"": {
55
"devDependencies": {
66
"@antfu/eslint-config": "^4.3.0",
7+
"@aws-crypto/sha256-browser": "^5.2.0",
78
"@iconify-json/ant-design": "^1.2.5",
89
"@iconify-json/ep": "^1.2.2",
910
"@iconify-json/lucide": "^1.2.34",
@@ -64,6 +65,18 @@
6465

6566
"@antfu/utils": ["@antfu/[email protected]", "https://registry.npmmirror.com/@antfu/utils/-/utils-8.1.1.tgz", {}, "sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ=="],
6667

68+
"@aws-crypto/sha256-browser": ["@aws-crypto/[email protected]", "https://registry.npmmirror.com/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="],
69+
70+
"@aws-crypto/sha256-js": ["@aws-crypto/[email protected]", "https://registry.npmmirror.com/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA=="],
71+
72+
"@aws-crypto/supports-web-crypto": ["@aws-crypto/[email protected]", "https://registry.npmmirror.com/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg=="],
73+
74+
"@aws-crypto/util": ["@aws-crypto/[email protected]", "https://registry.npmmirror.com/@aws-crypto/util/-/util-5.2.0.tgz", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="],
75+
76+
"@aws-sdk/types": ["@aws-sdk/[email protected]", "https://registry.npmmirror.com/@aws-sdk/types/-/types-3.804.0.tgz", { "dependencies": { "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-A9qnsy9zQ8G89vrPPlNG9d1d8QcKRGqJKqwyGgS0dclJpwy6d1EWgQLIolKPl6vcFpLoe6avLOLxr+h8ur5wpg=="],
77+
78+
"@aws-sdk/util-locate-window": ["@aws-sdk/[email protected]", "https://registry.npmmirror.com/@aws-sdk/util-locate-window/-/util-locate-window-3.804.0.tgz", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-zVoRfpmBVPodYlnMjgVjfGoEZagyRF5IPn3Uo6ZvOZp24chnW/FRstH7ESDHDDRga4z3V+ElUQHKpFDXWyBW5A=="],
79+
6780
"@babel/code-frame": ["@babel/[email protected]", "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.26.2.tgz", { "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" } }, "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ=="],
6881

6982
"@babel/compat-data": ["@babel/[email protected]", "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.26.8.tgz", {}, "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ=="],
@@ -398,6 +411,14 @@
398411

399412
"@rrweb/utils": ["@rrweb/[email protected]", "https://registry.npmmirror.com/@rrweb/utils/-/utils-2.0.0-alpha.18.tgz", {}, "sha512-qV8azQYo9RuwW4NGRtOiQfTBdHNL1B0Q//uRLMbCSjbaKqJYd88Js17Bdskj65a0Vgp2dwTLPIZ0gK47dfjfaA=="],
400413

414+
"@smithy/is-array-buffer": ["@smithy/[email protected]", "https://registry.npmmirror.com/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
415+
416+
"@smithy/types": ["@smithy/[email protected]", "https://registry.npmmirror.com/@smithy/types/-/types-4.3.0.tgz", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+1iaIQHthDh9yaLhRzaoQxRk+l9xlk+JjMFxGRhNLz+m9vKOkjNeU8QuB4w3xvzHyVR/BVlp/4AXDHjoRIkfgQ=="],
417+
418+
"@smithy/util-buffer-from": ["@smithy/[email protected]", "https://registry.npmmirror.com/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
419+
420+
"@smithy/util-utf8": ["@smithy/[email protected]", "https://registry.npmmirror.com/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
421+
401422
"@stylistic/eslint-plugin": ["@stylistic/[email protected]", "https://registry.npmmirror.com/@stylistic/eslint-plugin/-/eslint-plugin-4.2.0.tgz", { "dependencies": { "@typescript-eslint/utils": "^8.23.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "estraverse": "^5.3.0", "picomatch": "^4.0.2" }, "peerDependencies": { "eslint": ">=9.0.0" } }, "sha512-8hXezgz7jexGHdo5WN6JBEIPHCSFyyU4vgbxevu4YLVS5vl+sxqAAGyXSzfNDyR6xMNSH5H1x67nsXcYMOHtZA=="],
402423

403424
"@tauri-apps/api": ["@tauri-apps/[email protected]", "https://registry.npmmirror.com/@tauri-apps/api/-/api-2.4.1.tgz", {}, "sha512-5sYwZCSJb6PBGbBL4kt7CnE5HHbBqwH+ovmOW6ZVju3nX4E3JX6tt2kRklFEH7xMOIwR0btRkZktuLhKvyEQYg=="],

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
},
1919
"devDependencies": {
2020
"@antfu/eslint-config": "^4.3.0",
21+
"@aws-crypto/sha256-browser": "^5.2.0",
2122
"@iconify-json/ant-design": "^1.2.5",
2223
"@iconify-json/ep": "^1.2.2",
2324
"@iconify-json/lucide": "^1.2.34",

src/components/settings/group.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import DynamicInput from '@/components/dynamic-input';
44
import { useConfigStore } from '@/stores/config';
55
import { useNamelistStore } from '@/stores/namelist';
66
import { MAX_GROUP_NAME_LENGTH } from '@/utils/config';
7-
import useNamelistMembers from '@/utils/namelist';
7+
import { useNamelistMembers } from '@/utils/namelist';
88
import { useMessage } from 'naive-ui';
99
import { computed, ref, toRaw, watch } from 'vue';
1010
import { useI18n } from 'vue-i18n';

src/components/settings/namelist.vue

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,16 @@ const namelist = useNamelistStore();
2222
watch(() => config.namelist, () => config.group = undefined);
2323
2424
const names = ref<RollCallOption[]>([]);
25-
watchImmediate(() => config.namelist, () => {
26-
names.value = namelist.use(config.namelist).names;
25+
const checksum = ref<string | undefined>();
26+
const expanded = ref(false);
27+
28+
watchImmediate(() => config.namelist, (n) => {
29+
names.value = namelist.use(n).names;
30+
namelist.calcChecksum(n).then(v => checksum.value = v);
2731
});
2832
watch(names, (v) => {
2933
namelist.use(config.namelist).names = v;
34+
namelist.calcChecksum(config.namelist).then(v => checksum.value = v);
3035
});
3136
3237
const limited = computed(() => namelist.list().length >= MAX_NAMELIST_COUNT);
@@ -121,6 +126,34 @@ async function handleExport() {
121126
/>
122127
</template>
123128
</DataOperations>
129+
130+
<p class="break-anywhere">
131+
{{ t('checksum.label') }}
132+
<span
133+
class="select-all mr-1"
134+
v-text="checksum ? (expanded ? checksum : checksum.slice(0, 5)) : '...'"
135+
/>
136+
137+
<NTooltip>
138+
<template #trigger>
139+
<ILucideCircleHelp class="align-sub" :size="20" />
140+
</template>
141+
{{ t('checksum.notes') }}
142+
</NTooltip>
143+
144+
<NTooltip v-if="!expanded">
145+
<template #trigger>
146+
<ILucidePlus class="align-sub" :size="20" @click="expanded = true" />
147+
</template>
148+
{{ t('checksum.expand') }}
149+
</NTooltip>
150+
<NTooltip v-else>
151+
<template #trigger>
152+
<ILucideMinus class="align-sub" :size="20" @click="expanded = false" />
153+
</template>
154+
{{ t('checksum.collapse') }}
155+
</NTooltip>
156+
</p>
124157
</template>
125158

126159
<style scoped>
@@ -147,11 +180,21 @@ en:
147180
namelist-created: New namelist {0} is created
148181
namelist-deleted: Namelist {0} is deleted
149182
detected-names: Detected {0} names, click "Next" to import.
183+
checksum:
184+
label: 'Checksum:'
185+
notes: Used to verify the integrity of the namelist. If the namelist is modified, the checksum will change.
186+
expand: Expand
187+
collapse: Collapse
150188
151189
zh-CN:
152190
current: 当前名单
153191
create-namelist: 新建名单
154192
namelist-created: 名单 {0} 创建成功
155193
namelist-deleted: 已删除名单 {0}
156194
detected: 共检测到 {0} 个名字,点击“下一步”即可导入。
195+
checksum:
196+
label: 校验码:
197+
notes: 用于验证名单的完整性,若名单被修改,校验码会发生变化。
198+
expand: 展开
199+
collapse: 收起
157200
</i18n>

src/components/settings/plan.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { SelectOption } from 'naive-ui/es/select/src/interface';
33
import DynamicInput from '@/components/dynamic-input.tsx';
44
import { useConfigStore } from '@/stores/config';
55
import { MAX_PLAN_QUEUE_SIZE } from '@/utils/config';
6-
import useNamelistMembers from '@/utils/namelist';
6+
import { useNamelistMembers } from '@/utils/namelist';
77
import { computed, onBeforeUnmount, ref } from 'vue';
88
import { useI18n } from 'vue-i18n';
99

src/stores/namelist.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,16 @@ import { getGroup, listGroups, removeGroup, setGroup } from '@/utils/group';
55
import { genNewNamelistName, getNamelist, listNamelists, removeNamelist, setNamelist } from '@/utils/namelist';
66
import { rollCallOptionToString } from '@/utils/roll-call';
77
import { getGlobalI18n } from '@/utils/ui';
8+
import { Sha256 } from '@aws-crypto/sha256-browser';
89
import { watchImmediate } from '@vueuse/core';
910
import { defineStore } from 'pinia';
10-
import { reactive, ref, toRef, watch } from 'vue';
11+
import { reactive, ref, toRaw, toRef, watch } from 'vue';
12+
13+
function toHex(array: Uint8Array) {
14+
return Array.from(array)
15+
.map(byte => byte.toString(16).padStart(2, '0'))
16+
.join('');
17+
}
1118

1219
type GroupData = Record<string, string[]>;
1320

@@ -162,5 +169,11 @@ export const useNamelistStore = defineStore('namelist', {
162169
} while (keys.includes(ret));
163170
return ret;
164171
},
172+
173+
async calcChecksum(name: string) {
174+
const s = new Sha256();
175+
s.update(JSON.stringify(toRaw(this.data[name].names)));
176+
return toHex(await s.digest());
177+
},
165178
},
166179
});

src/utils/namelist.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export async function exportNamelistToText(namelist: string) {
7171
);
7272
}
7373

74-
export default function useNamelistMembers(name: string) {
74+
export function useNamelistMembers(name: string) {
7575
return computed(
7676
() => useNamelistStore().use(name).names.map(rollCallOptionToString),
7777
);

0 commit comments

Comments
 (0)