diff --git a/src/services/keyManagement/__tests__/apiSercice.test.ts b/src/services/keyManagement/__tests__/apiSercice.test.ts new file mode 100644 index 0000000..99bfd6b --- /dev/null +++ b/src/services/keyManagement/__tests__/apiSercice.test.ts @@ -0,0 +1,65 @@ +import axios from "axios"; +import MockAdapter from "axios-mock-adapter"; +import { sendOTP } from "../apiService"; + +describe("sendOTP", () => { + let mock: MockAdapter; // Explicitly declare the type + + beforeEach(() => { + mock = new MockAdapter(axios); + }); + + afterEach(() => { + mock.restore(); + }); + + it("should send OTP successfully with valid inputs", async () => { + const fullPhoneNumber = "1234567890"; + const jwtToken = "valid-token"; + + mock + .onPost("http://localhost:8080/api/registration") + .reply(200, { message: "OTP sent" }); + + const response = await sendOTP(fullPhoneNumber, jwtToken); + + expect(response).toEqual({ message: "OTP sent" }); + }); + + it("should throw an error when API responds with an error", async () => { + const fullPhoneNumber = "1234567890"; + const jwtToken = "valid-token"; + + mock.onPost("http://localhost:8080/api/registration").reply(500); + + await expect(sendOTP(fullPhoneNumber, jwtToken)).rejects.toThrow( + "Failed to send OTP", + ); + }); + + it("should throw an error when an invalid JWT token is provided", async () => { + const fullPhoneNumber = "1234567890"; + const jwtToken = "invalid-token"; + + mock.onPost("http://localhost:8080/api/registration").reply(401); + + await expect(sendOTP(fullPhoneNumber, jwtToken)).rejects.toThrow( + "Failed to send OTP", + ); + }); + + it("should handle empty phone number and JWT token", async () => { + await expect(sendOTP("", "")).rejects.toThrow("Failed to send OTP"); + }); + + it("should handle network error", async () => { + const fullPhoneNumber = "1234567890"; + const jwtToken = "valid-token"; + + mock.onPost("http://localhost:8080/api/registration").networkError(); + + await expect(sendOTP(fullPhoneNumber, jwtToken)).rejects.toThrow( + "Failed to send OTP", + ); + }); +}); diff --git a/src/services/keyManagement/__tests__/jwtservice.test.ts b/src/services/keyManagement/__tests__/jwtservice.test.ts index 13c056c..46155fe 100644 --- a/src/services/keyManagement/__tests__/jwtservice.test.ts +++ b/src/services/keyManagement/__tests__/jwtservice.test.ts @@ -17,11 +17,13 @@ describe("JWT Generation", () => { // Convert privateKey to JWK for use with generateJWT const privateKeyJWK = await jose.exportJWK(privateKey); + // Convert publicKey to JWK for verification + const publicKeyJWK = await jose.exportJWK(publicKey); + // Step 3: Call the generateJWT function - const jwt = await generateJWT(data, privateKeyJWK); + const jwt = await generateJWT(data, privateKeyJWK, publicKeyJWK); // Step 4: Verify the JWT signature and payload - const publicKeyJWK = await jose.exportJWK(publicKey); // Convert publicKey to JWK for verification const { payload } = await jose.jwtVerify( jwt, await jose.importJWK(publicKeyJWK, "ES256"), diff --git a/src/services/keyManagement/apiService.ts b/src/services/keyManagement/apiService.ts new file mode 100644 index 0000000..3f129b1 --- /dev/null +++ b/src/services/keyManagement/apiService.ts @@ -0,0 +1,27 @@ +import axios from "axios"; +export const sendOTP = async (fullPhoneNumber: string, jwtToken: string) => { + // Create the request object with both phone number and public key + const requestBody = { + phoneNumber: fullPhoneNumber, + }; + const headers = { + "Content-Type": "application/json", + Authorization: `Bearer ${jwtToken}`, + }; + + try { + const response = await axios.post( + "http://localhost:8080/api/registration", + requestBody, + { headers }, + ); + + // Log the response from the backend + console.log("Response from backend:", response.data); + + return response.data; + } catch (error) { + console.error("Error sending OTP:", error); + throw new Error("Failed to send OTP"); + } +}; diff --git a/src/services/keyManagement/jwtService.ts b/src/services/keyManagement/jwtService.ts index ca763a9..875e56e 100644 --- a/src/services/keyManagement/jwtService.ts +++ b/src/services/keyManagement/jwtService.ts @@ -8,6 +8,7 @@ function hashPayload(payload: string): string { export async function generateJWT( data: string, privateKeyJWK: jose.JWK, + publicKeyJWK: jose.JWK, ): Promise { // Hash the payload const hashedPayload = hashPayload(data); @@ -23,7 +24,11 @@ export async function generateJWT( // Sign the JWT with the private key const jwt = await new jose.SignJWT(jwtPayload) - .setProtectedHeader({ alg: "ES256" }) + .setProtectedHeader({ + typ: "JWT", + alg: "ES256", + jwk: publicKeyJWK, + }) .sign(privateKey); return jwt; diff --git a/src/services/keyManagement/registerService.ts b/src/services/keyManagement/registerService.ts index ff19eb2..f75203d 100644 --- a/src/services/keyManagement/registerService.ts +++ b/src/services/keyManagement/registerService.ts @@ -1,6 +1,7 @@ import { generateJWT } from "./jwtService"; import storeKeyPair, { retrieveKeyPair } from "./storeKey"; import checkKeyPairExists from "./checkKeyPairExists"; +import { sendOTP } from "./apiService"; export async function sendOtpWithKeyManagement( phoneNumber: string, @@ -20,8 +21,10 @@ export async function sendOtpWithKeyManagement( } // Generate JWT with the full phone number - jwtToken = await generateJWT(phoneNumber, privateKey); - console.log("Generated JWT:", jwtToken); + jwtToken = await generateJWT(phoneNumber, privateKey, publicKey); + + // Send the JWT and phone number + await sendOTP(phoneNumber, jwtToken); } else { console.log("Key pair already exists. Skipping generation."); } diff --git a/src/services/keyManagement/storeKey.ts b/src/services/keyManagement/storeKey.ts index 846d088..8182cfe 100644 --- a/src/services/keyManagement/storeKey.ts +++ b/src/services/keyManagement/storeKey.ts @@ -1,14 +1,13 @@ -import storage from "./storageSetup"; -import generateKeyPair from "./generateKey"; +import storage from "./storageSetup"; // Import the initialized storage +import generateKeyPair from "./generateKey"; // Import your existing key generation function // Function to store a key pair in IndexedDB export async function storeKeyPair() { - const { publicKey, privateKey, kid } = await generateKeyPair(); + const { publicKey, privateKey } = await generateKeyPair(); // Store both keys in a single record in IndexedDB await storage.insert("keys", { value: { - id: kid, pub: { ...publicKey }, priv: { ...privateKey }, },