feat: harden auth and study workflows

- replace plaintext login and unlock requests with RSA-OAEP/AES-GCM encrypted payloads

- add login challenge replay protection, production RSA key validation, and auth tests

- wire compose to environment-driven dev/prod settings without committing local secrets

- update setup-config smoke scripts and Postman docs for encrypted login

- add visit schedule migrations/tests and update study/subject setup workflows
This commit is contained in:
Cheng Zhou
2026-05-08 22:13:12 +08:00
parent a7bbcaa5dc
commit 74feca4467
47 changed files with 2423 additions and 534 deletions
+13 -2
View File
@@ -1,7 +1,8 @@
import { defineStore } from "pinia";
import { ref } from "vue";
import { login as apiLogin, fetchMe } from "../api/auth";
import { getLoginKey, login as apiLogin, fetchMe } from "../api/auth";
import { setToken, clearToken, getToken } from "../utils/auth";
import { encryptLoginPayload } from "../utils/loginCrypto";
import type { UserInfo } from "../types/api";
import { useStudyStore } from "./study";
import { useSessionStore } from "./session";
@@ -16,7 +17,17 @@ export const useAuthStore = defineStore("auth", () => {
const login = async (email: string, password: string) => {
loading.value = true;
try {
const { data } = await apiLogin({ email, password });
const { data: loginKey } = await getLoginKey();
const ciphertext = await encryptLoginPayload(loginKey.public_key, {
email,
password,
challenge: loginKey.challenge,
});
const { data } = await apiLogin({
key_id: loginKey.key_id,
challenge: loginKey.challenge,
ciphertext,
});
token.value = data.access_token;
setToken(data.access_token);
// 避免锁屏态下 fetchMe 被请求拦截