mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-09 06:55:54 -06:00
1257ec9969
The new implementation will store the master password in the keyring instead of storing each and every server password separately. The master password will be used to encrypt/decrypt server password when storing in the pgAdmin config DB.
397 lines
13 KiB
JavaScript
397 lines
13 KiB
JavaScript
/////////////////////////////////////////////////////////////
|
|
//
|
|
// pgAdmin 4 - PostgreSQL Tools
|
|
//
|
|
// Copyright (C) 2013 - 2024, The pgAdmin Development Team
|
|
// This software is released under the PostgreSQL Licence
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
import React from 'react';
|
|
import pgAdmin from 'sources/pgadmin';
|
|
import ConnectServerContent from './ConnectServerContent';
|
|
import url_for from 'sources/url_for';
|
|
import gettext from 'sources/gettext';
|
|
|
|
import getApiInstance from '../api_instance';
|
|
import MasterPasswordContent from './MasterPasswordContent';
|
|
import ChangePasswordContent from './ChangePasswordContent';
|
|
import NamedRestoreContent from './NamedRestoreContent';
|
|
import ChangeOwnershipContent from './ChangeOwnershipContent';
|
|
import UrlDialogContent from './UrlDialogContent';
|
|
import RenameTabContent from './RenameTabContent';
|
|
import { BROWSER_PANELS } from '../../../browser/static/js/constants';
|
|
import ErrorBoundary from '../helpers/ErrorBoundary';
|
|
import QuickSearch from '../QuickSearch';
|
|
|
|
// This functions is used to show the connect server password dialog.
|
|
export function showServerPassword() {
|
|
let title = arguments[0],
|
|
formJson = arguments[1],
|
|
nodeObj = arguments[2],
|
|
nodeData = arguments[3],
|
|
treeNodeInfo = arguments[4],
|
|
itemNodeData = arguments[5],
|
|
status = arguments[6],
|
|
onSuccess = arguments[7],
|
|
onFailure = arguments[8];
|
|
|
|
pgAdmin.Browser.notifier.showModal(title, (onClose) => {
|
|
return (
|
|
<ConnectServerContent
|
|
closeModal={()=>{
|
|
onClose();
|
|
}}
|
|
data={formJson}
|
|
onOK={(formData)=>{
|
|
const api = getApiInstance();
|
|
let _url = nodeObj.generate_url(itemNodeData, 'connect', nodeData, true);
|
|
if (!status) {
|
|
treeNodeInfo.setLeaf(itemNodeData);
|
|
treeNodeInfo.removeIcon(itemNodeData);
|
|
treeNodeInfo.addIcon(itemNodeData, {icon: 'icon-server-connecting'});
|
|
}
|
|
|
|
api.post(_url, formData)
|
|
.then(res=>{
|
|
onClose();
|
|
return onSuccess(
|
|
res.data, nodeObj, nodeData, treeNodeInfo, itemNodeData, status
|
|
);
|
|
})
|
|
.catch((err)=>{
|
|
return onFailure(
|
|
err, null, nodeObj, nodeData, treeNodeInfo, itemNodeData, status
|
|
);
|
|
});
|
|
}}
|
|
/>
|
|
);
|
|
});
|
|
}
|
|
|
|
function masterPassCallbacks(masterpass_callback_queue) {
|
|
while(masterpass_callback_queue.length > 0) {
|
|
let callback = masterpass_callback_queue.shift();
|
|
callback();
|
|
}
|
|
}
|
|
|
|
export function checkMasterPassword(data, masterpass_callback_queue, cancel_callback) {
|
|
const api = getApiInstance();
|
|
api.post(url_for('browser.set_master_password'), data).then((res)=> {
|
|
let isKeyring = res.data.data.keyring_name.length > 0;
|
|
let error = res.data.data.errmsg;
|
|
|
|
if(!res.data.data.present) {
|
|
showMasterPassword(res.data.data.reset, res.data.data.errmsg, masterpass_callback_queue, cancel_callback, res.data.data.keyring_name, res.data.data.master_password_hook);
|
|
} else {
|
|
masterPassCallbacks(masterpass_callback_queue);
|
|
if(isKeyring) {
|
|
if(error){
|
|
pgAdmin.Browser.notifier.alert(gettext('Migration failed'),
|
|
gettext(`Passwords previously saved can not be re-encrypted using encryption key stored in the ${res.data.data.keyring_name}. due to ${error}`));
|
|
}else{
|
|
pgAdmin.Browser.notifier.alert(gettext('Migration successful'),
|
|
gettext(`Passwords previously saved are re-encrypted using encryption key stored in the ${res.data.data.keyring_name}.`));
|
|
}
|
|
}
|
|
}
|
|
}).catch(function(error) {
|
|
pgAdmin.Browser.notifier.pgRespErrorNotify(error);
|
|
});
|
|
}
|
|
|
|
// This functions is used to show the master password dialog.
|
|
export function showMasterPassword(isPWDPresent, errmsg, masterpass_callback_queue, cancel_callback, keyring_name='', master_password_hook='') {
|
|
const api = getApiInstance();
|
|
let title = gettext('Set Master Password');
|
|
if (keyring_name.length > 0)
|
|
title = gettext('Migrate Saved Passwords');
|
|
else if (isPWDPresent)
|
|
title = gettext('Unlock Saved Passwords');
|
|
|
|
if(master_password_hook){
|
|
if(errmsg){
|
|
pgAdmin.Browser.notifier.error(errmsg);
|
|
return true;
|
|
}else{
|
|
pgAdmin.Browser.notifier.confirm(gettext('Reset Master Password'),
|
|
gettext('The master password retrieved from the master password hook utility is different from what was previously retrieved.') + '<br>'
|
|
+ gettext('Do you want to reset your master password to match?') + '<br><br>'
|
|
+ gettext('Note that this will close all open database connections and remove all saved passwords.'),
|
|
function() {
|
|
let _url = url_for('browser.reset_master_password');
|
|
const api = getApiInstance();
|
|
api.delete(_url)
|
|
.then(() => {
|
|
pgAdmin.Browser.notifier.info('The master password has been reset.');
|
|
})
|
|
.catch((err) => {
|
|
pgAdmin.Browser.notifier.error(err.message);
|
|
});
|
|
return true;
|
|
},
|
|
function() {/* If user clicks No */ return true;}
|
|
);}
|
|
}else{
|
|
|
|
pgAdmin.Browser.notifier.showModal(title, (onClose)=> {
|
|
return (
|
|
<MasterPasswordContent
|
|
isPWDPresent= {isPWDPresent}
|
|
data={{'errmsg': errmsg}}
|
|
keyringName={keyring_name}
|
|
closeModal={() => {
|
|
onClose();
|
|
}}
|
|
onResetPassowrd={(isKeyRing=false)=>{
|
|
pgAdmin.Browser.notifier.confirm(gettext('Reset Master Password'),
|
|
gettext('This will remove all the saved passwords. This will also remove established connections to '
|
|
+ 'the server and you may need to reconnect again. Do you wish to continue?'),
|
|
function() {
|
|
let _url = url_for('browser.reset_master_password');
|
|
|
|
api.delete(_url)
|
|
.then(() => {
|
|
onClose();
|
|
if(!isKeyRing) {
|
|
showMasterPassword(false, null, masterpass_callback_queue, cancel_callback);
|
|
}
|
|
})
|
|
.catch((err) => {
|
|
pgAdmin.Browser.notifier.error(err.message);
|
|
});
|
|
return true;
|
|
},
|
|
function() {/* If user clicks No */ return true;}
|
|
);
|
|
}}
|
|
onCancel={()=>{
|
|
cancel_callback?.();
|
|
}}
|
|
onOK={(formData) => {
|
|
onClose();
|
|
checkMasterPassword(formData, masterpass_callback_queue, cancel_callback);
|
|
}}
|
|
/>
|
|
);
|
|
});
|
|
}
|
|
}
|
|
|
|
export function showChangeServerPassword() {
|
|
let title = arguments[0],
|
|
nodeData = arguments[1],
|
|
nodeObj = arguments[2],
|
|
itemNodeData = arguments[3],
|
|
isPgPassFileUsed = arguments[4];
|
|
|
|
const panelId = BROWSER_PANELS.SEARCH_OBJECTS;
|
|
const onClose = ()=>{pgAdmin.Browser.docker.close(panelId);};
|
|
pgAdmin.Browser.docker.openDialog({
|
|
id: panelId,
|
|
title: title,
|
|
content: (
|
|
<ChangePasswordContent
|
|
onClose={onClose}
|
|
onSave={(isNew, data)=>{
|
|
return new Promise((resolve, reject)=>{
|
|
const api = getApiInstance();
|
|
let _url = nodeObj.generate_url(itemNodeData, 'change_password', nodeData, true);
|
|
|
|
api.post(_url, data)
|
|
.then(({data: respData})=>{
|
|
pgAdmin.Browser.notifier.success(respData.info);
|
|
// Notify user to update pgpass file
|
|
if(isPgPassFileUsed) {
|
|
pgAdmin.Browser.notifier.alert(
|
|
gettext('Change Password'),
|
|
gettext('Please make sure to disconnect the server'
|
|
+ ' and update the new password in the pgpass file'
|
|
+ ' before performing any other operation')
|
|
);
|
|
}
|
|
|
|
resolve(respData.data);
|
|
onClose();
|
|
})
|
|
.catch((error)=>{
|
|
reject(error instanceof Error ? error : Error(gettext('Something went wrong')));
|
|
});
|
|
});
|
|
}}
|
|
userName={nodeData.user.name}
|
|
isPgpassFileUsed={isPgPassFileUsed}
|
|
/>
|
|
)
|
|
}, pgAdmin.Browser.stdW.md, pgAdmin.Browser.stdH.md);
|
|
}
|
|
|
|
export function showChangeUserPassword(url) {
|
|
const panelId = BROWSER_PANELS.SEARCH_OBJECTS;
|
|
const onClose = ()=>{pgAdmin.Browser.docker.close(panelId);};
|
|
pgAdmin.Browser.docker.openDialog({
|
|
id: panelId,
|
|
title: gettext('Change pgAdmin User Password'),
|
|
content: (
|
|
<ChangePasswordContent
|
|
getInitData={()=>{
|
|
const api = getApiInstance();
|
|
return new Promise((resolve, reject)=>{
|
|
api.get(url)
|
|
.then((res)=>{
|
|
resolve(res.data);
|
|
})
|
|
.catch((err)=>{
|
|
reject(err instanceof Error ? err : Error(gettext('Something went wrong')));
|
|
});
|
|
});
|
|
}}
|
|
onClose={()=>{
|
|
onClose();
|
|
}}
|
|
onSave={(_isNew, data)=>{
|
|
const api = getApiInstance();
|
|
return new Promise((resolve, reject)=>{
|
|
const formData = {
|
|
'password': data.password,
|
|
'new_password': data.newPassword,
|
|
'new_password_confirm': data.confirmPassword,
|
|
'csrf_token': data.csrf_token
|
|
};
|
|
|
|
api({
|
|
method: 'POST',
|
|
url: url,
|
|
data: formData,
|
|
}).then((res)=>{
|
|
resolve(res.data.info);
|
|
onClose();
|
|
pgAdmin.Browser.notifier.success(res.data.info);
|
|
}).catch((err)=>{
|
|
reject(err instanceof Error ? err : Error(gettext('Something went wrong')));
|
|
});
|
|
});
|
|
}}
|
|
hasCsrfToken={true}
|
|
showUser={false}
|
|
/>
|
|
)
|
|
}, pgAdmin.Browser.stdW.md, pgAdmin.Browser.stdH.md);
|
|
}
|
|
|
|
export function showNamedRestorePoint() {
|
|
let title = arguments[0],
|
|
nodeData = arguments[1],
|
|
nodeObj = arguments[2],
|
|
itemNodeData = arguments[3];
|
|
|
|
const panelId = BROWSER_PANELS.SEARCH_OBJECTS;
|
|
const onClose = ()=>{pgAdmin.Browser.docker.close(panelId);};
|
|
pgAdmin.Browser.docker.openDialog({
|
|
id: panelId,
|
|
title: title,
|
|
content: (
|
|
<NamedRestoreContent
|
|
closeModal={onClose}
|
|
onOK={(formData)=>{
|
|
const api = getApiInstance();
|
|
let _url = nodeObj.generate_url(itemNodeData, 'restore_point', nodeData, true);
|
|
|
|
api.post(_url, formData)
|
|
.then(res=>{
|
|
onClose();
|
|
pgAdmin.Browser.notifier.success(res.data.data.result);
|
|
})
|
|
.catch(function(error) {
|
|
pgAdmin.Browser.notifier.pgRespErrorNotify(error);
|
|
});
|
|
}}
|
|
/>
|
|
)
|
|
}, pgAdmin.Browser.stdW.md, 180);
|
|
}
|
|
|
|
export function showChangeOwnership() {
|
|
let title = arguments[0],
|
|
userList = arguments[1],
|
|
noOfSharedServers = arguments[2],
|
|
deletedUser = arguments[3],
|
|
deleteUserRow = arguments[4];
|
|
|
|
// Render Preferences component
|
|
pgAdmin.Browser.notifier.showModal(title, (onClose) => {
|
|
return <ChangeOwnershipContent
|
|
onClose={()=>{
|
|
onClose();
|
|
}}
|
|
onSave={(isNew, data)=>{
|
|
const api = getApiInstance();
|
|
|
|
return new Promise((resolve, reject)=>{
|
|
if (data.newUser == '') {
|
|
deleteUserRow();
|
|
onClose();
|
|
} else {
|
|
let newData = {'new_owner': `${data.newUser}`, 'old_owner': `${deletedUser['id']}`};
|
|
api.post(url_for('user_management.change_owner'), newData)
|
|
.then(({data: respData})=>{
|
|
pgAdmin.Browser.notifier.success(gettext(respData.info));
|
|
onClose();
|
|
deleteUserRow();
|
|
resolve(respData.data);
|
|
})
|
|
.catch((err)=>{
|
|
reject(err instanceof Error ? err : Error(gettext('Something went wrong')));
|
|
});
|
|
}
|
|
});
|
|
}}
|
|
userList = {userList}
|
|
noOfSharedServers = {noOfSharedServers}
|
|
deletedUser = {deletedUser['name']}
|
|
/>;
|
|
},
|
|
{ isFullScreen: false, isResizeable: true, showFullScreen: true, isFullWidth: true,
|
|
dialogWidth: pgAdmin.Browser.stdW.md, dialogHeight: pgAdmin.Browser.stdH.md});
|
|
}
|
|
|
|
export function showUrlDialog() {
|
|
let title = arguments[0],
|
|
url = arguments[1],
|
|
helpFile = arguments[2],
|
|
width = arguments[3],
|
|
height = arguments[4];
|
|
|
|
pgAdmin.Browser.notifier.showModal(title, (onClose) => {
|
|
return <UrlDialogContent url={url} helpFile={helpFile} onClose={onClose} />;
|
|
},
|
|
{ isFullScreen: false, isResizeable: true, showFullScreen: true, isFullWidth: true,
|
|
dialogWidth: width || pgAdmin.Browser.stdW.md, dialogHeight: height || pgAdmin.Browser.stdH.md});
|
|
}
|
|
|
|
export function showRenameTab(panelId, panelDocker) {
|
|
pgAdmin.Browser.notifier.showModal(gettext('Rename Tab'), (onClose) => {
|
|
return (
|
|
<ErrorBoundary>
|
|
<RenameTabContent
|
|
closeModal={()=>{
|
|
onClose();
|
|
}}
|
|
panelId={panelId}
|
|
panelDocker={panelDocker}
|
|
/>
|
|
</ErrorBoundary>
|
|
);
|
|
});
|
|
}
|
|
|
|
export function showQuickSearch() {
|
|
pgAdmin.Browser.notifier.showModal(gettext('Quick Search'), (closeModal) => {
|
|
return <QuickSearch closeModal={closeModal}/>;
|
|
},
|
|
{ isFullScreen: false, isResizeable: false, showFullScreen: false, isFullWidth: false, showTitle: false}
|
|
);
|
|
}
|