mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-04 14:57:42 +00:00
🧱 fix: Validate Bedrock User Credentials (#13277)
This commit is contained in:
parent
7cd467a528
commit
af902118c9
2 changed files with 104 additions and 15 deletions
|
|
@ -483,6 +483,26 @@ describe('initializeBedrock', () => {
|
|||
expect(result.llmConfig).not.toHaveProperty('credentials');
|
||||
});
|
||||
|
||||
it('should reject a non-string user-provided Bedrock API key', async () => {
|
||||
process.env.BEDROCK_AWS_BEARER_TOKEN = AuthType.USER_PROVIDED;
|
||||
process.env.BEDROCK_AWS_ACCESS_KEY_ID = AuthType.USER_PROVIDED;
|
||||
process.env.BEDROCK_AWS_SECRET_ACCESS_KEY = AuthType.USER_PROVIDED;
|
||||
const params = createMockParams();
|
||||
(params.db.getUserKey as jest.Mock).mockResolvedValue(
|
||||
JSON.stringify({
|
||||
apiKey: JSON.stringify({
|
||||
bearerToken: {},
|
||||
accessKeyId: 'user-access-key',
|
||||
secretAccessKey: 'user-secret-key',
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(initializeBedrock(params)).rejects.toThrow(
|
||||
'Bedrock credentials not provided. Please provide them again.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should not use stored access keys when only bearer token mode is configured', async () => {
|
||||
process.env.BEDROCK_AWS_BEARER_TOKEN = AuthType.USER_PROVIDED;
|
||||
const params = createMockParams();
|
||||
|
|
@ -513,6 +533,24 @@ describe('initializeBedrock', () => {
|
|||
});
|
||||
expect(result.llmConfig).not.toHaveProperty('client');
|
||||
});
|
||||
|
||||
it('should reject non-string user-provided access key values', async () => {
|
||||
process.env.BEDROCK_AWS_ACCESS_KEY_ID = AuthType.USER_PROVIDED;
|
||||
process.env.BEDROCK_AWS_SECRET_ACCESS_KEY = AuthType.USER_PROVIDED;
|
||||
const params = createMockParams();
|
||||
(params.db.getUserKey as jest.Mock).mockResolvedValue(
|
||||
JSON.stringify({
|
||||
apiKey: JSON.stringify({
|
||||
accessKeyId: {},
|
||||
secretAccessKey: 'user-secret-key',
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(initializeBedrock(params)).rejects.toThrow(
|
||||
'Bedrock credentials not provided. Please provide them again.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Credentials Edge Cases', () => {
|
||||
|
|
|
|||
|
|
@ -15,12 +15,61 @@ import type {
|
|||
BaseInitializeParams,
|
||||
InitializeResultBase,
|
||||
BedrockCredentials,
|
||||
BedrockUserCredentials,
|
||||
GuardrailConfiguration,
|
||||
InferenceProfileConfig,
|
||||
} from '~/types';
|
||||
import { checkUserKeyExpiry } from '~/utils';
|
||||
|
||||
const BEDROCK_CREDENTIALS_ERROR = 'Bedrock credentials not provided. Please provide them again.';
|
||||
|
||||
type UserCredentialKey = 'accessKeyId' | 'secretAccessKey' | 'sessionToken' | 'bearerToken';
|
||||
type UserCredentialValue = string | number | boolean | object | null;
|
||||
type ParsedBedrockUserCredentials = Partial<Record<UserCredentialKey, UserCredentialValue>> & {
|
||||
apiKey?: string;
|
||||
};
|
||||
|
||||
function isParsedBedrockUserCredentials(value: unknown): value is ParsedBedrockUserCredentials {
|
||||
return value != null && typeof value === 'object' && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function parseBedrockUserCredentials(userKey: string): ParsedBedrockUserCredentials {
|
||||
const storedCredentials = JSON.parse(userKey) as unknown;
|
||||
if (!isParsedBedrockUserCredentials(storedCredentials)) {
|
||||
throw new Error(BEDROCK_CREDENTIALS_ERROR);
|
||||
}
|
||||
|
||||
if (typeof storedCredentials.apiKey !== 'string') {
|
||||
return storedCredentials;
|
||||
}
|
||||
|
||||
const nestedCredentials = JSON.parse(storedCredentials.apiKey) as unknown;
|
||||
if (!isParsedBedrockUserCredentials(nestedCredentials)) {
|
||||
throw new Error(BEDROCK_CREDENTIALS_ERROR);
|
||||
}
|
||||
|
||||
return nestedCredentials;
|
||||
}
|
||||
|
||||
function getUserCredentialValue(
|
||||
credentials: ParsedBedrockUserCredentials,
|
||||
key: UserCredentialKey,
|
||||
): string | undefined {
|
||||
if (!Object.prototype.hasOwnProperty.call(credentials, key)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const value = credentials[key];
|
||||
if (value === '') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (typeof value !== 'string') {
|
||||
throw new Error(BEDROCK_CREDENTIALS_ERROR);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes Bedrock endpoint configuration.
|
||||
*
|
||||
|
|
@ -101,35 +150,37 @@ export async function initializeBedrock({
|
|||
});
|
||||
|
||||
if (!userKey) {
|
||||
throw new Error('Bedrock credentials not provided. Please provide them again.');
|
||||
throw new Error(BEDROCK_CREDENTIALS_ERROR);
|
||||
}
|
||||
|
||||
let userCredentials: BedrockUserCredentials;
|
||||
let userCredentials: ParsedBedrockUserCredentials;
|
||||
try {
|
||||
const storedCredentials = JSON.parse(userKey) as BedrockUserCredentials & { apiKey?: string };
|
||||
userCredentials =
|
||||
typeof storedCredentials.apiKey === 'string'
|
||||
? (JSON.parse(storedCredentials.apiKey) as BedrockUserCredentials)
|
||||
: storedCredentials;
|
||||
userCredentials = parseBedrockUserCredentials(userKey);
|
||||
} catch {
|
||||
throw new Error('Bedrock credentials not provided. Please provide them again.');
|
||||
throw new Error(BEDROCK_CREDENTIALS_ERROR);
|
||||
}
|
||||
|
||||
if (userProvidesBearerToken && userCredentials.bearerToken) {
|
||||
bearerToken = userCredentials.bearerToken;
|
||||
const userBearerToken = userProvidesBearerToken
|
||||
? getUserCredentialValue(userCredentials, 'bearerToken')
|
||||
: undefined;
|
||||
|
||||
if (userBearerToken) {
|
||||
bearerToken = userBearerToken;
|
||||
} else {
|
||||
const canUseAccessKeys =
|
||||
userProvidesAccessKeyId || userProvidesSecretAccessKey || userProvidesSessionToken;
|
||||
const accessKeyId = userProvidesAccessKeyId ? userCredentials.accessKeyId : staticAccessKeyId;
|
||||
const accessKeyId = userProvidesAccessKeyId
|
||||
? getUserCredentialValue(userCredentials, 'accessKeyId')
|
||||
: staticAccessKeyId;
|
||||
const secretAccessKey = userProvidesSecretAccessKey
|
||||
? userCredentials.secretAccessKey
|
||||
? getUserCredentialValue(userCredentials, 'secretAccessKey')
|
||||
: staticSecretAccessKey;
|
||||
const sessionToken = userProvidesSessionToken
|
||||
? userCredentials.sessionToken
|
||||
? getUserCredentialValue(userCredentials, 'sessionToken')
|
||||
: staticSessionToken;
|
||||
|
||||
if (!canUseAccessKeys || !accessKeyId || !secretAccessKey) {
|
||||
throw new Error('Bedrock credentials not provided. Please provide them again.');
|
||||
throw new Error(BEDROCK_CREDENTIALS_ERROR);
|
||||
}
|
||||
|
||||
credentials = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue