Skip to content

Commit 18c6450

Browse files
Refactor: Move crypto utilities to utils.ts
- Extract encryptData and decryptData functions to lib/utils.ts - Clean up auth.ts by removing duplicate crypto code - Maintain same functionality with better code organization
1 parent 876c952 commit 18c6450

File tree

2 files changed

+67
-66
lines changed

2 files changed

+67
-66
lines changed

client/src/lib/auth.ts

Lines changed: 1 addition & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -9,72 +9,7 @@ import {
99
} from "@modelcontextprotocol/sdk/shared/auth.js";
1010
import { SESSION_KEYS, getServerSpecificKey } from "./constants";
1111
import { generateOAuthState } from "@/utils/oauthUtils";
12-
13-
// Simple obfuscation using Web Crypto API
14-
const ENCRYPTION_KEY = 'mcp-inspector-oauth-storage-key-v1';
15-
16-
async function deriveKey(salt: Uint8Array): Promise<CryptoKey> {
17-
const encoder = new TextEncoder();
18-
const keyMaterial = await crypto.subtle.importKey(
19-
'raw',
20-
encoder.encode(ENCRYPTION_KEY),
21-
'PBKDF2',
22-
false,
23-
['deriveKey']
24-
);
25-
26-
return crypto.subtle.deriveKey(
27-
{
28-
name: 'PBKDF2',
29-
salt: salt.buffer as ArrayBuffer,
30-
iterations: 100000,
31-
hash: 'SHA-256',
32-
},
33-
keyMaterial,
34-
{ name: 'AES-GCM', length: 256 },
35-
false,
36-
['encrypt', 'decrypt']
37-
);
38-
}
39-
40-
async function encryptData(data: string): Promise<string> {
41-
const encoder = new TextEncoder();
42-
const salt = crypto.getRandomValues(new Uint8Array(16));
43-
const iv = crypto.getRandomValues(new Uint8Array(12));
44-
const key = await deriveKey(salt);
45-
46-
const encrypted = await crypto.subtle.encrypt(
47-
{ name: 'AES-GCM', iv },
48-
key,
49-
encoder.encode(data)
50-
);
51-
52-
// Combine salt + iv + encrypted data
53-
const combined = new Uint8Array(salt.length + iv.length + encrypted.byteLength);
54-
combined.set(salt);
55-
combined.set(iv, salt.length);
56-
combined.set(new Uint8Array(encrypted), salt.length + iv.length);
57-
58-
return btoa(String.fromCharCode(...combined));
59-
}
60-
61-
async function decryptData(encryptedData: string): Promise<string> {
62-
const combined = new Uint8Array(atob(encryptedData).split('').map(c => c.charCodeAt(0)));
63-
64-
const salt = combined.slice(0, 16);
65-
const iv = combined.slice(16, 28);
66-
const data = combined.slice(28);
67-
68-
const key = await deriveKey(salt);
69-
70-
const decrypted = await crypto.subtle.decrypt(
71-
{ name: 'AES-GCM', iv },
72-
key,
73-
data
74-
);
75-
76-
return new TextDecoder().decode(decrypted);
77-
}
12+
import { encryptData, decryptData } from "./utils";
7813

7914
export const getClientInformationFromSessionStorage = async ({
8015
serverUrl,

client/src/lib/utils.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,69 @@ import { twMerge } from "tailwind-merge";
44
export function cn(...inputs: ClassValue[]) {
55
return twMerge(clsx(inputs));
66
}
7+
8+
// Simple obfuscation using Web Crypto API for sessionStorage
9+
const ENCRYPTION_KEY = 'mcp-inspector-oauth-storage-key-v1';
10+
11+
async function deriveKey(salt: Uint8Array): Promise<CryptoKey> {
12+
const encoder = new TextEncoder();
13+
const keyMaterial = await crypto.subtle.importKey(
14+
'raw',
15+
encoder.encode(ENCRYPTION_KEY),
16+
'PBKDF2',
17+
false,
18+
['deriveKey']
19+
);
20+
21+
return crypto.subtle.deriveKey(
22+
{
23+
name: 'PBKDF2',
24+
salt: salt.buffer as ArrayBuffer,
25+
iterations: 100000,
26+
hash: 'SHA-256',
27+
},
28+
keyMaterial,
29+
{ name: 'AES-GCM', length: 256 },
30+
false,
31+
['encrypt', 'decrypt']
32+
);
33+
}
34+
35+
export async function encryptData(data: string): Promise<string> {
36+
const encoder = new TextEncoder();
37+
const salt = crypto.getRandomValues(new Uint8Array(16));
38+
const iv = crypto.getRandomValues(new Uint8Array(12));
39+
const key = await deriveKey(salt);
40+
41+
const encrypted = await crypto.subtle.encrypt(
42+
{ name: 'AES-GCM', iv },
43+
key,
44+
encoder.encode(data)
45+
);
46+
47+
// Combine salt + iv + encrypted data
48+
const combined = new Uint8Array(salt.length + iv.length + encrypted.byteLength);
49+
combined.set(salt);
50+
combined.set(iv, salt.length);
51+
combined.set(new Uint8Array(encrypted), salt.length + iv.length);
52+
53+
return btoa(String.fromCharCode(...combined));
54+
}
55+
56+
export async function decryptData(encryptedData: string): Promise<string> {
57+
const combined = new Uint8Array(atob(encryptedData).split('').map(c => c.charCodeAt(0)));
58+
59+
const salt = combined.slice(0, 16);
60+
const iv = combined.slice(16, 28);
61+
const data = combined.slice(28);
62+
63+
const key = await deriveKey(salt);
64+
65+
const decrypted = await crypto.subtle.decrypt(
66+
{ name: 'AES-GCM', iv },
67+
key,
68+
data
69+
);
70+
71+
return new TextDecoder().decode(decrypted);
72+
}

0 commit comments

Comments
 (0)