File size: 6,837 Bytes
f0743f4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | import path from 'path';
import axios from 'axios';
import { readFileAsString } from './files';
import { loadServiceKey } from './key';
jest.mock('fs');
jest.mock('axios');
jest.mock('@librechat/data-schemas', () => ({
logger: {
error: jest.fn(),
},
}));
jest.mock('./files', () => ({
readFileAsString: jest.fn(),
}));
describe('loadServiceKey', () => {
const mockServiceKey = {
type: 'service_account',
project_id: 'test-project',
private_key_id: 'test-key-id',
private_key: '-----BEGIN PRIVATE KEY-----\ntest-key\n-----END PRIVATE KEY-----',
client_email: 'test@test-project.iam.gserviceaccount.com',
client_id: '123456789',
auth_uri: 'https://accounts.google.com/o/oauth2/auth',
token_uri: 'https://oauth2.googleapis.com/token',
auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs',
client_x509_cert_url:
'https://www.googleapis.com/robot/v1/metadata/x509/test%40test-project.iam.gserviceaccount.com',
};
beforeEach(() => {
jest.clearAllMocks();
});
it('should return null if keyPath is empty', async () => {
const result = await loadServiceKey('');
expect(result).toBeNull();
});
it('should parse stringified JSON directly', async () => {
const jsonString = JSON.stringify(mockServiceKey);
const result = await loadServiceKey(jsonString);
expect(result).toEqual(mockServiceKey);
});
it('should parse stringified JSON with leading/trailing whitespace', async () => {
const jsonString = ` ${JSON.stringify(mockServiceKey)} `;
const result = await loadServiceKey(jsonString);
expect(result).toEqual(mockServiceKey);
});
it('should load from file path', async () => {
const filePath = '/path/to/service-key.json';
(readFileAsString as jest.Mock).mockResolvedValue({
content: JSON.stringify(mockServiceKey),
bytes: JSON.stringify(mockServiceKey).length,
});
const result = await loadServiceKey(filePath);
expect(readFileAsString).toHaveBeenCalledWith(path.resolve(filePath));
expect(result).toEqual(mockServiceKey);
});
it('should load from URL', async () => {
const url = 'https://example.com/service-key.json';
(axios.get as jest.Mock).mockResolvedValue({ data: mockServiceKey });
const result = await loadServiceKey(url);
expect(axios.get).toHaveBeenCalledWith(url);
expect(result).toEqual(mockServiceKey);
});
it('should handle invalid JSON string', async () => {
const invalidJson = '{ invalid json }';
const result = await loadServiceKey(invalidJson);
expect(result).toBeNull();
});
it('should handle file read errors', async () => {
const filePath = '/path/to/nonexistent.json';
(readFileAsString as jest.Mock).mockRejectedValue(new Error('File not found'));
const result = await loadServiceKey(filePath);
expect(result).toBeNull();
});
it('should handle URL fetch errors', async () => {
const url = 'https://example.com/service-key.json';
(axios.get as jest.Mock).mockRejectedValue(new Error('Network error'));
const result = await loadServiceKey(url);
expect(result).toBeNull();
});
it('should validate service key format', async () => {
const invalidServiceKey = { invalid: 'key' };
const result = await loadServiceKey(JSON.stringify(invalidServiceKey));
expect(result).toEqual(invalidServiceKey); // It returns the object as-is, validation is minimal
});
it('should handle escaped newlines in private key from AWS Secrets Manager', async () => {
const serviceKeyWithEscapedNewlines = {
...mockServiceKey,
private_key: '-----BEGIN PRIVATE KEY-----\\ntest-key\\n-----END PRIVATE KEY-----',
};
const jsonString = JSON.stringify(serviceKeyWithEscapedNewlines);
const result = await loadServiceKey(jsonString);
expect(result).not.toBeNull();
expect(result?.private_key).toBe(
'-----BEGIN PRIVATE KEY-----\ntest-key\n-----END PRIVATE KEY-----',
);
});
it('should handle double-escaped newlines in private key', async () => {
// When you have \\n in JavaScript, JSON.stringify converts it to \\\\n
// But we want to test the case where the JSON string contains \\n (single backslash + n)
const serviceKeyWithEscapedNewlines = {
...mockServiceKey,
private_key: '-----BEGIN PRIVATE KEY-----\\ntest-key\\n-----END PRIVATE KEY-----',
};
// This will create a JSON string where the private_key contains literal \n (backslash-n)
const jsonString = JSON.stringify(serviceKeyWithEscapedNewlines);
const result = await loadServiceKey(jsonString);
expect(result).not.toBeNull();
expect(result?.private_key).toBe(
'-----BEGIN PRIVATE KEY-----\ntest-key\n-----END PRIVATE KEY-----',
);
});
it('should handle private key without any newlines', async () => {
const serviceKeyWithoutNewlines = {
...mockServiceKey,
private_key: '-----BEGIN PRIVATE KEY-----test-key-----END PRIVATE KEY-----',
};
const jsonString = JSON.stringify(serviceKeyWithoutNewlines);
const result = await loadServiceKey(jsonString);
expect(result).not.toBeNull();
expect(result?.private_key).toBe(
'-----BEGIN PRIVATE KEY-----\ntest-key\n-----END PRIVATE KEY-----',
);
});
it('should not modify private key that already has proper formatting', async () => {
const jsonString = JSON.stringify(mockServiceKey);
const result = await loadServiceKey(jsonString);
expect(result).not.toBeNull();
expect(result?.private_key).toBe(mockServiceKey.private_key);
});
it('should handle base64 encoded service key', async () => {
const jsonString = JSON.stringify(mockServiceKey);
const base64Encoded = Buffer.from(jsonString).toString('base64');
const result = await loadServiceKey(base64Encoded);
expect(result).not.toBeNull();
expect(result).toEqual(mockServiceKey);
});
it('should handle base64 encoded service key with escaped newlines', async () => {
const serviceKeyWithEscapedNewlines = {
...mockServiceKey,
private_key: '-----BEGIN PRIVATE KEY-----\\ntest-key\\n-----END PRIVATE KEY-----',
};
const jsonString = JSON.stringify(serviceKeyWithEscapedNewlines);
const base64Encoded = Buffer.from(jsonString).toString('base64');
const result = await loadServiceKey(base64Encoded);
expect(result).not.toBeNull();
expect(result?.private_key).toBe(
'-----BEGIN PRIVATE KEY-----\ntest-key\n-----END PRIVATE KEY-----',
);
});
it('should handle invalid base64 strings gracefully', async () => {
// This looks like base64 but isn't valid
const invalidBase64 = 'SGVsbG8gV29ybGQ='; // "Hello World" in base64, not valid JSON
const result = await loadServiceKey(invalidBase64);
expect(result).toBeNull();
});
});
|