mirror of
https://github.com/ramvignesh-b/pi-ku.git
synced 2026-05-04 08:56:52 +00:00
feat: enhance zero-knowledge authentication by deriving and sending auth hashes to the server
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { act, renderHook } from "@testing-library/react";
|
||||
import { HttpResponse, http } from "msw";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { mockMasterKey } from "../../test/fixtures/auth.fixture";
|
||||
import { mockUser } from "../../test/fixtures/user.fixture";
|
||||
import { server } from "../../test/mocks/server";
|
||||
import { useAuthStore } from "../store/useAuthStore";
|
||||
@@ -13,26 +14,24 @@ import {
|
||||
} from "../utils/keystore";
|
||||
import { useAuth } from "./useAuth";
|
||||
|
||||
vi.mock("../utils/crypto");
|
||||
vi.mock("../utils/keystore");
|
||||
|
||||
const API_URL = "http://piku-server";
|
||||
|
||||
vi.mock("../utils/crypto", () => ({
|
||||
CryptoUtils: {
|
||||
deriveMasterKey: vi
|
||||
.fn()
|
||||
.mockResolvedValue({ type: "secret" } as unknown as CryptoKey),
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("../utils/keystore", () => ({
|
||||
saveMasterKey: vi.fn().mockResolvedValue(undefined),
|
||||
loadMasterKey: vi
|
||||
.fn()
|
||||
.mockResolvedValue({ type: "secret" } as unknown as CryptoKey),
|
||||
clearMasterKey: vi.fn().mockResolvedValue(undefined),
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
|
||||
// hack to set up mock implementations using fixtures
|
||||
vi.mocked(CryptoUtils.deriveKeyBundle).mockResolvedValue({
|
||||
masterKey: mockMasterKey,
|
||||
authHash: "mock-auth-hash",
|
||||
});
|
||||
|
||||
vi.mocked(loadMasterKey).mockResolvedValue(mockMasterKey);
|
||||
vi.mocked(saveMasterKey).mockResolvedValue(undefined);
|
||||
vi.mocked(clearMasterKey).mockResolvedValue(undefined);
|
||||
|
||||
useAuthStore.setState({
|
||||
accessToken: null,
|
||||
user: null,
|
||||
@@ -61,34 +60,21 @@ describe("isAuthenticated", () => {
|
||||
});
|
||||
|
||||
describe("login", () => {
|
||||
it("should derive the master key using the provided credentials", async () => {
|
||||
it("should persist the provided master key to IndexedDB", async () => {
|
||||
const { result } = renderHook(() => useAuth());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.login("access-token", mockUser, "test-password");
|
||||
await result.current.login("access-token", mockUser, mockMasterKey);
|
||||
});
|
||||
|
||||
expect(CryptoUtils.deriveMasterKey).toHaveBeenCalledWith(
|
||||
"test-password",
|
||||
mockUser.email,
|
||||
);
|
||||
});
|
||||
|
||||
it("should persist the derived master key to IndexedDB", async () => {
|
||||
const { result } = renderHook(() => useAuth());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.login("access-token", mockUser, "my-password");
|
||||
});
|
||||
|
||||
expect(saveMasterKey).toHaveBeenCalledTimes(1);
|
||||
expect(saveMasterKey).toHaveBeenCalledWith(mockMasterKey);
|
||||
});
|
||||
|
||||
it("should update the store with the access token and user profile", async () => {
|
||||
const { result } = renderHook(() => useAuth());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.login("my-access-token", mockUser, "my-password");
|
||||
await result.current.login("my-access-token", mockUser, mockMasterKey);
|
||||
});
|
||||
|
||||
expect(useAuthStore.getState().accessToken).toBe("my-access-token");
|
||||
@@ -99,7 +85,7 @@ describe("login", () => {
|
||||
const { result } = renderHook(() => useAuth());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.login("token", mockUser, "my-password");
|
||||
await result.current.login("token", mockUser, mockMasterKey);
|
||||
});
|
||||
|
||||
expect(useKeyStore.getState().masterKey).not.toBeNull();
|
||||
|
||||
@@ -4,7 +4,6 @@ import { endpoints } from "../config/endpoints";
|
||||
import type { UserProfile } from "../store/useAuthStore";
|
||||
import { useAuthStore } from "../store/useAuthStore";
|
||||
import { useKeyStore } from "../store/useKeyStore";
|
||||
import { CryptoUtils } from "../utils/crypto";
|
||||
import {
|
||||
clearMasterKey,
|
||||
loadMasterKey,
|
||||
@@ -18,16 +17,12 @@ export const useAuth = () => {
|
||||
|
||||
const isAuthenticated = !!accessToken;
|
||||
|
||||
// called after successful login — derive & save master key
|
||||
const login = async (
|
||||
// called after successful login — save master key
|
||||
const setAuthStore = async (
|
||||
access: string,
|
||||
profile: UserProfile,
|
||||
password: string,
|
||||
masterKey: CryptoKey,
|
||||
) => {
|
||||
const masterKey = await CryptoUtils.deriveMasterKey(
|
||||
password,
|
||||
profile.email,
|
||||
);
|
||||
await saveMasterKey(masterKey);
|
||||
setMasterKey(masterKey);
|
||||
setAuth(access, profile);
|
||||
@@ -76,7 +71,7 @@ export const useAuth = () => {
|
||||
isAuthenticated,
|
||||
user,
|
||||
isInitializing,
|
||||
login,
|
||||
setAuthStore,
|
||||
logout,
|
||||
initialize,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user