Merge pull request #2510 from LenAnderson/proxy-confirm ask user to confirm proxy connections
Signed| @@ -53,6 +53,7 @@ import { | |||
| 53 | getFileText, | 53 | getFileText, |
| 54 | getImageSizeFromDataURL, | 54 | getImageSizeFromDataURL, |
| 55 | getSortableDelay, | 55 | getSortableDelay, |
| 56 | getStringHash, | ||
| 56 | isDataURL, | 57 | isDataURL, |
| 57 | parseJsonFile, | 58 | parseJsonFile, |
| 58 | resetScrollHeight, | 59 | resetScrollHeight, |
| @@ -72,6 +73,7 @@ import { SlashCommand } from './slash-commands/SlashCommand.js'; | |||
| 72 | import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js'; | 73 | import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js'; |
| 73 | import { renderTemplateAsync } from './templates.js'; | 74 | import { renderTemplateAsync } from './templates.js'; |
| 74 | import { SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js'; | 75 | import { SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js'; |
| 76 | import { Popup, POPUP_RESULT } from './popup.js'; | ||
| 75 | 77 | ||
| 76 | export { | 78 | export { |
| 77 | openai_messages_count, | 79 | openai_messages_count, |
| @@ -202,6 +204,15 @@ const custom_prompt_post_processing_types = { | |||
| 202 | CLAUDE: 'claude', | 204 | CLAUDE: 'claude', |
| 203 | }; | 205 | }; |
| 204 | 206 | ||
| 207 | const sensitiveFields = [ | ||
| 208 | 'reverse_proxy', | ||
| 209 | 'proxy_password', | ||
| 210 | 'custom_url', | ||
| 211 | 'custom_include_body', | ||
| 212 | 'custom_exclude_body', | ||
| 213 | 'custom_include_headers', | ||
| 214 | ]; | ||
| 215 | |||
| 205 | function getPrefixMap() { | 216 | function getPrefixMap() { |
| 206 | return selected_group ? { | 217 | return selected_group ? { |
| 207 | assistant: '', | 218 | assistant: '', |
| @@ -388,7 +399,7 @@ let openai_settings; | |||
| 388 | 399 | ||
| 389 | let promptManager = null; | 400 | let promptManager = null; |
| 390 | 401 | ||
| 391 | function validateReverseProxy() { | 402 | async function validateReverseProxy() { |
| 392 | if (!oai_settings.reverse_proxy) { | 403 | if (!oai_settings.reverse_proxy) { |
| 393 | return; | 404 | return; |
| 394 | } | 405 | } |
| @@ -402,6 +413,19 @@ function validateReverseProxy() { | |||
| 402 | resultCheckStatus(); | 413 | resultCheckStatus(); |
| 403 | throw err; | 414 | throw err; |
| 404 | } | 415 | } |
| 416 | const rememberKey = `Proxy_SkipConfirm_${getStringHash(oai_settings.reverse_proxy)}`; | ||
| 417 | const skipConfirm = localStorage.getItem(rememberKey) === 'true'; | ||
| 418 | |||
| 419 | const confirmation = skipConfirm || await Popup.show.confirm('Connecting To Proxy', `<span>Are you sure you want to connect to the following proxy URL?</span><var>${DOMPurify.sanitize(oai_settings.reverse_proxy)}</var>`); | ||
| 420 | |||
| 421 | if (!confirmation) { | ||
| 422 | toastr.error('Update or remove your reverse proxy settings.'); | ||
| 423 | setOnlineStatus('no_connection'); | ||
| 424 | resultCheckStatus(); | ||
| 425 | throw new Error('Proxy connection denied.'); | ||
| 426 | } | ||
| 427 | |||
| 428 | localStorage.setItem(rememberKey, String(true)); | ||
| 405 | } | 429 | } |
| 406 | 430 | ||
| 407 | /** | 431 | /** |
| @@ -1787,7 +1811,7 @@ async function sendOpenAIRequest(type, messages, signal) { | |||
| 1787 | 1811 | ||
| 1788 | // Proxy is only supported for Claude, OpenAI, Mistral, and Google MakerSuite | 1812 | // Proxy is only supported for Claude, OpenAI, Mistral, and Google MakerSuite |
| 1789 | if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI, chat_completion_sources.MISTRALAI, chat_completion_sources.MAKERSUITE].includes(oai_settings.chat_completion_source)) { | 1813 | if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI, chat_completion_sources.MISTRALAI, chat_completion_sources.MAKERSUITE].includes(oai_settings.chat_completion_source)) { |
| 1790 | validateReverseProxy(); | 1814 | await validateReverseProxy(); |
| 1791 | generate_data['reverse_proxy'] = oai_settings.reverse_proxy; | 1815 | generate_data['reverse_proxy'] = oai_settings.reverse_proxy; |
| 1792 | generate_data['proxy_password'] = oai_settings.proxy_password; | 1816 | generate_data['proxy_password'] = oai_settings.proxy_password; |
| 1793 | } | 1817 | } |
| @@ -3200,7 +3224,7 @@ async function getStatusOpen() { | |||
| 3200 | }; | 3224 | }; |
| 3201 | 3225 | ||
| 3202 | if (oai_settings.reverse_proxy && (oai_settings.chat_completion_source === chat_completion_sources.OPENAI || oai_settings.chat_completion_source === chat_completion_sources.CLAUDE)) { | 3226 | if (oai_settings.reverse_proxy && (oai_settings.chat_completion_source === chat_completion_sources.OPENAI || oai_settings.chat_completion_source === chat_completion_sources.CLAUDE)) { |
| 3203 | validateReverseProxy(); | 3227 | await validateReverseProxy(); |
| 3204 | } | 3228 | } |
| 3205 | 3229 | ||
| 3206 | if (oai_settings.chat_completion_source === chat_completion_sources.CUSTOM) { | 3230 | if (oai_settings.chat_completion_source === chat_completion_sources.CUSTOM) { |
| @@ -3495,6 +3519,26 @@ async function onPresetImportFileChange(e) { | |||
| 3495 | return; | 3519 | return; |
| 3496 | } | 3520 | } |
| 3497 | 3521 | ||
| 3522 | const fields = sensitiveFields.filter(field => presetBody[field]).map(field => `<b>${field}</b>`); | ||
| 3523 | const shouldConfirm = fields.length > 0; | ||
| 3524 | |||
| 3525 | if (shouldConfirm) { | ||
| 3526 | const textHeader = 'The imported preset contains proxy and/or custom endpoint settings.'; | ||
| 3527 | const textMessage = fields.join('<br>'); | ||
| 3528 | const cancelButton = { text: 'Cancel import', result: POPUP_RESULT.CANCELLED, appendAtEnd: true }; | ||
| 3529 | const popupOptions = { customButtons: [cancelButton], okButton: 'Remove them', cancelButton: 'Import as-is' }; | ||
| 3530 | const popupResult = await Popup.show.confirm(textHeader, textMessage, popupOptions); | ||
| 3531 | |||
| 3532 | if (popupResult === POPUP_RESULT.CANCELLED) { | ||
| 3533 | console.log('Import cancelled by user'); | ||
| 3534 | return; | ||
| 3535 | } | ||
| 3536 | |||
| 3537 | if (popupResult === POPUP_RESULT.AFFIRMATIVE) { | ||
| 3538 | sensitiveFields.forEach(field => delete presetBody[field]); | ||
| 3539 | } | ||
| 3540 | } | ||
| 3541 | |||
| 3498 | if (name in openai_setting_names) { | 3542 | if (name in openai_setting_names) { |
| 3499 | const confirm = await callPopup('Preset name already exists. Overwrite?', 'confirm'); | 3543 | const confirm = await callPopup('Preset name already exists. Overwrite?', 'confirm'); |
| 3500 | 3544 | ||
| @@ -3541,8 +3585,22 @@ async function onExportPresetClick() { | |||
| 3541 | 3585 | ||
| 3542 | const preset = structuredClone(openai_settings[openai_setting_names[oai_settings.preset_settings_openai]]); | 3586 | const preset = structuredClone(openai_settings[openai_setting_names[oai_settings.preset_settings_openai]]); |
| 3543 | 3587 | ||
| 3544 | delete preset.reverse_proxy; | 3588 | const fieldValues = sensitiveFields.filter(field => preset[field]).map(field => `<b>${field}</b>: <code>${preset[field]}</code>`); |
| 3545 | delete preset.proxy_password; | 3589 | const shouldConfirm = fieldValues.length > 0; |
| 3590 | const textHeader = 'Your preset contains proxy and/or custom endpoint settings.'; | ||
| 3591 | const textMessage = `<div>Do you want to remove these fields before exporting?</div><br>${DOMPurify.sanitize(fieldValues.join('<br>'))}`; | ||
| 3592 | const cancelButton = { text: 'Cancel', result: POPUP_RESULT.CANCELLED, appendAtEnd: true }; | ||
| 3593 | const popupOptions = { customButtons: [cancelButton] }; | ||
| 3594 | const popupResult = await Popup.show.confirm(textHeader, textMessage, popupOptions); | ||
| 3595 | |||
| 3596 | if (popupResult === POPUP_RESULT.CANCELLED) { | ||
| 3597 | console.log('Export cancelled by user'); | ||
| 3598 | return; | ||
| 3599 | } | ||
| 3600 | |||
| 3601 | if (!shouldConfirm || popupResult === POPUP_RESULT.AFFIRMATIVE) { | ||
| 3602 | sensitiveFields.forEach(field => delete preset[field]); | ||
| 3603 | } | ||
| 3546 | 3604 | ||
| 3547 | const presetJsonString = JSON.stringify(preset, null, 4); | 3605 | const presetJsonString = JSON.stringify(preset, null, 4); |
| 3548 | const presetFileName = `${oai_settings.preset_settings_openai}.json`; | 3606 | const presetFileName = `${oai_settings.preset_settings_openai}.json`; |