Skip to content
This repository has been archived by the owner on Aug 4, 2020. It is now read-only.

Commit

Permalink
Merge remote-tracking branch 'origin/bugfix/do_not_reload_on_secret_s…
Browse files Browse the repository at this point in the history
…ubmit' into v0.7.0-RC2
  • Loading branch information
fieldju committed Dec 14, 2016
2 parents 43786d9 + a776c68 commit 33e6686
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 29 deletions.
93 changes: 80 additions & 13 deletions app/actions/manageSafetyDepositBoxActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@ export function removeVaultSecretFromLocalStore(key) {
}
}

export function removeVaultNodePathKeyFromLocalStore(key) {
return {
type: actions.REMOVE_VAULT_KEY_FROM_LOCAL_STORE,
payload: key
}
}

export function showAddNewVaultSecret() {
return {
type: actions.SHOW_ADD_SECRET_FORM
Expand All @@ -154,26 +161,34 @@ export function hideAddNewVaultSecret() {
}
}

export function commitSecret(navigatedPath, data, token) {
export function commitSecret(navigatedPath, data, token, isNewVaultPath) {
let vaultData = {}
let key = data.path
let fullPath = `${navigatedPath}${key}`

data.kvMap.map((entry) => {
log.info("entry", entry)
vaultData[entry.key] = entry.value
})

log.info(vaultData)

return function (dispatch) {
let nestedFolder = key.split('/').length > 1;
// let the UI / state know that we are saving the secret, so that the user can't spam the save button
// but only if not a nested folder
if (! nestedFolder) {
dispatch(savingVaultSecret(fullPath))
}

// save the secret
axios({
method: 'post',
url: `/v1/secret/${navigatedPath}${data.path}`,
url: `/v1/secret/${fullPath}`,
data: vaultData,
headers: {'X-Vault-Token': token},
timeout: 60 * 1000 // 1 minute
})
.then((response) => {
log.info("SUCCESS", response)
location.reload(); // todo hack until I get back from vacation
// once saved we can use the data we have locally to update the state, without additional API calls
dispatch(updateLocalStateAfterSaveCommit(navigatedPath, key, vaultData, isNewVaultPath))
})
.catch((response) => {
log.error("Failed to save Vault Secret data", response)
Expand All @@ -182,10 +197,49 @@ export function commitSecret(navigatedPath, data, token) {
}
}

export function deleteVaultPathConfirm(path, token) {
/**
* After posting a secret to Vault we can update the local state to represent the new data
*
* @param prefix, the partial path to Vault Node / Secret (Sort of like a virtual folder)
* @param key, the key to the Vault Node / Secret
* @param data, the Vault secret data that was saved, we can store this and save an API call
* @param isNewVaultPath, boolean, if its a new secret we need to hide the add new form
*/
export function updateLocalStateAfterSaveCommit(prefix, key, data, isNewVaultPath) {
return (dispatch) => {
// we will only store the data, if its not in a nested virtual folder
let addSecretData = true;

// Update the piece of state that stores the keys that are available for the given navigated path.
// if a user added a nested secret that is in a folder
// ex: foo/bar/bam we would want to add foo/ to the state, so the folder foo shows up in the ui
let pieces = key.split('/')
if (pieces.length > 1) {
key = pieces[0] + '/'
addSecretData = false
}
dispatch(updateStoredKeys(key))

// Update the stored vault secret data for the given complete path, if the key is not a virtual folder
if (addSecretData) {
log.info('ADDING KEY DATA')
dispatch(storeVaultSecret(`${prefix}${key}`, data))
}

// if this is a new vault path remove the create new form
if (isNewVaultPath) {
dispatch(hideAddNewVaultSecret())
}

// finally lets let the user know we saved there data
dispatch(messengerActions.addNewMessageWithTimeout(`Successfully saved Vault secret at path: ${prefix}${key}`, 2500))
}
}

export function deleteVaultPathConfirm(navigatedPath, label, token) {
return (dispatch) => {
let yes = () => {
dispatch(deleteVaultPath(path, token))
dispatch(deleteVaultPath(navigatedPath, label, token))
dispatch(modalActions.popModal())
}

Expand All @@ -202,17 +256,17 @@ export function deleteVaultPathConfirm(path, token) {
}
}

export function deleteVaultPath(path, token) {
export function deleteVaultPath(navigatedPath, label, token) {
return function (dispatch) {
axios({
method: 'delete',
url: `/v1/secret/${path}`,
url: `/v1/secret/${navigatedPath}${label}`,
headers: {'X-Vault-Token': token},
timeout: 60 * 1000 // 1 minute
})
.then((response) => {
log.info("SUCCESS", response)
location.reload(); // todo hack until I get back from vacation
dispatch(removeVaultSecretFromLocalStore(`${navigatedPath}${label}`))
dispatch(removeVaultNodePathKeyFromLocalStore(label))
})
.catch((response) => {
log.error("Failed to delete Vault Secret", response)
Expand Down Expand Up @@ -300,3 +354,16 @@ export function resetSubmittingEditSDBRequest() {
}
}

export function savingVaultSecret(path) {
return {
type: actions.SAVING_VAULT_SECRET,
payload: path
}
}

export function updateStoredKeys(key) {
return {
type: actions.ADD_VAULT_KEY_IF_NOT_PRESET,
payload: key
}
}
32 changes: 28 additions & 4 deletions app/actions/messengerActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,47 @@ import * as constants from '../constants/actions'
* adds a message to the messenger
* @param message A string or JSX element to be rendered in the messenger component
*/
export function addNewMessage(message) {
export function addNewMessage(message, id) {
window.scrollTo(0, 0)
return {
type: constants.ADD_MESSAGE,
payload: message
payload: {
message: message,
id: id ? id : guid()
}
}
}

export function removeMessage(indexToRemove) {
export function addNewMessageWithTimeout(message, timeout) {
return (dispatch => {
let id = guid()

dispatch(addNewMessage(message, id))
setTimeout(() => {
dispatch(removeMessage(id))
}, timeout)
})
}

export function removeMessage(id) {
return {
type: constants.REMOVE_MESSAGE,
payload: indexToRemove
payload: id
}
}

export function clearAllMessages() {
return {
type: constants.CLEAR_ALL_MESSAGES
}
}

function guid() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
}
4 changes: 2 additions & 2 deletions app/components/Messenger/Messenger.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ export default class Messenger extends Component {
<div id='messenger-container'>
{messages.map((message, index) =>
<div className="messenger-message" key={index}>
<div className="messenger-message-content">{message}</div>
<div className="messenger-message-content">{message.message}</div>
<div className="messenger-message-buttons">
<div className="messenger-message-buttons-acknowledge" onClick={() => {
dispatch(messengerActions.removeMessage(index))}
dispatch(messengerActions.removeMessage(message.id))}
}></div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/components/VaultSecret/VaultSecret.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export default class VaultSecret extends Component {
pathReadOnly={true}
formKey={`${navigatedPath}${label}`} />
<div className="vault-secret-delete-btn" onClick={() => {
dispatch(mSDBActions.deleteVaultPathConfirm(`${navigatedPath}${label}`, vaultToken))
dispatch(mSDBActions.deleteVaultPathConfirm(`${navigatedPath}`,`${label}`, vaultToken))
}}>
<div className="vault-secret-delete-btn-icon"></div>
<div className="vault-secret-delete-btn-label">Delete this Vault Path</div>
Expand Down
12 changes: 8 additions & 4 deletions app/components/VaultSecretForm/VaultSecretForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ const validate = values => {
@connect((state) => {
return {
vaultToken: state.auth.vaultToken,
navigatedPath: state.manageSafetyDepositBox.navigatedPath
navigatedPath: state.manageSafetyDepositBox.navigatedPath,
vaultSecretsData: state.manageSafetyDepositBox.vaultSecretsData
}
})
@reduxForm(
Expand All @@ -60,19 +61,22 @@ export default class VaultSecretForm extends Component {
const {
fields: {
path,
kvMap,
kvMap
},
navigatedPath,
dispatch,
vaultToken,
handleSubmit,
pathReadOnly,
vaultSecretsData,
formKey
} = this.props

return(
<div id="vault-add-new-secret-container">
<form id='vault-add-new-secret-form' onSubmit={handleSubmit( data => {
dispatch(mSDBActions.commitSecret(navigatedPath, data, vaultToken))
let isNewVaultPath = formKey == 'add-new-secret'
dispatch(mSDBActions.commitSecret(navigatedPath, data, vaultToken, isNewVaultPath))
})}>
<div id='new-vault-secret-path'>
<div id='new-vault-secret-path-label'>Path:</div>
Expand Down Expand Up @@ -154,7 +158,7 @@ export default class VaultSecretForm extends Component {
<div className="btn-wrapper">
<button id='submit-btn'
className='ncss-btn-dark-grey ncss-brand pt3-sm pr5-sm pb3-sm pl5-sm pt2-lg pb2-lg u-uppercase'
disabled={false}>Save
disabled={vaultSecretsData[navigatedPath + path.value] ? vaultSecretsData[navigatedPath + path.value].isUpdating : false}>Save
</button>
</div>
</div>
Expand Down
3 changes: 3 additions & 0 deletions app/constants/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const SUBMITTED_NEW_SDB_REQUEST = 'SUBMITTED_NEW_SDB_REQUEST'
export const FETCHING_VAULT_SECRET = 'FETCHING_VAULT_SECRET'
export const FETCHED_VAULT_SECRET = 'FETCHED_VAULT_SECRET'
export const REMOVE_SECRET_FROM_LOCAL_STORE = 'REMOVE_SECRET_FROM_LOCAL_STORE'
export const REMOVE_VAULT_KEY_FROM_LOCAL_STORE = 'REMOVE_VAULT_KEY_FROM_LOCAL_STORE'
export const STORE_SDB_DATA = 'STORE_SDB_DATA'
export const TOGGLE_PERM_VIS = 'TOGGLE_PERM_VIS'
export const FETCHING_VAULT_KEYS = 'FETCHING_VAULT_KEYS'
Expand All @@ -40,6 +41,8 @@ export const HIDE_ADD_SECRET_FORM = 'HIDE_ADD_SECRET_FORM'
export const SUBMITTING_EDIT_SDB_REQUEST = 'SUBMITTING_EDIT_SDB_REQUEST'
export const RESET_SUBMITTING_EDIT_SDB_REQUEST = 'RESET_SUBMITTING_EDIT_SDB_REQUEST'
export const CLEAR_VAULT_DATA = 'CLEAR_VAULT_DATA'
export const SAVING_VAULT_SECRET = 'SAVING_VAULT_SECRET'
export const ADD_VAULT_KEY_IF_NOT_PRESET = 'ADD_VAULT_KEY_IF_NOT_PRESET'

// Messenger
export const ADD_MESSAGE = 'ADD_MESSAGE'
Expand Down
62 changes: 61 additions & 1 deletion app/reducers/manageSafetyDepositBoxReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,44 @@ export default createReducer(initialState, {
hasFetchedKeys: true
})
},
[action.ADD_VAULT_KEY_IF_NOT_PRESET]: (state, payload) => {
let existingList = state.vaultPathKeys
let keyToAddIfMissing = payload
let newList = []
let isKeyPreset = false

for (let key in existingList) {
let value = existingList[key]
if (value == keyToAddIfMissing) {
isKeyPreset = true
}
newList.push(value)
}

if (! isKeyPreset) {
newList.push(keyToAddIfMissing)
}

return Object.assign({}, state, {
vaultPathKeys: newList
})
},
[action.REMOVE_VAULT_KEY_FROM_LOCAL_STORE]: (state, payload) => {
let existingList = state.vaultPathKeys
let newList = []
let keyToRemove = payload

for (let key in existingList) {
let value = existingList[key]
if (keyToRemove != value) {
newList.push(value)
}
}

return Object.assign({}, state, {
vaultPathKeys: newList
})
},
[action.FETCHING_VAULT_KEYS]: (state) => {
return Object.assign({}, state, {
hasFetchedKeys: false
Expand All @@ -58,6 +96,7 @@ export default createReducer(initialState, {
}
newMap[fetchingKey] = {
isFetching: true,
isUpdating: false,
isActive: true,
data: {}
}
Expand All @@ -79,6 +118,7 @@ export default createReducer(initialState, {

newMap[fetchedKey] = {
isFetching: false,
isUpdating: false,
isActive: true,
data: payload.data
}
Expand Down Expand Up @@ -126,6 +166,26 @@ export default createReducer(initialState, {
vaultPathKeys: [],
vaultSecretsData: {}
})
},
[action.SAVING_VAULT_SECRET]: (state, payload) => {
let existingMap = state.vaultSecretsData
let newMap = {}
let fetchingKey = payload

for (let key in existingMap) {
if (existingMap.hasOwnProperty(key)) {
newMap[key] = existingMap[key]
}
}
newMap[fetchingKey] = {
isFetching: false,
isUpdating: true,
isActive: true,
data: existingMap[fetchingKey] ? existingMap[fetchingKey]['data'] : {}
}

return Object.assign({}, state, {
vaultSecretsData: newMap
})
}

})
11 changes: 7 additions & 4 deletions app/reducers/messengerReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ export default createReducer(initialState, {
newMessages.push(message)
})

newMessages.push(payload)
newMessages.push({
message: payload.message,
id: payload.id
})

log.info("New Messages", newMessages)

Expand All @@ -27,10 +30,10 @@ export default createReducer(initialState, {
let currentMessages = state.messages
let newMessages = []
//noinspection JSUnresolvedVariable
let indexToRemove = payload
let idToRemove = payload

currentMessages.forEach((message, index) => {
if (index != indexToRemove) {
currentMessages.forEach((message) => {
if (message.id != idToRemove) {
newMessages.push(message)
}
})
Expand Down

0 comments on commit 33e6686

Please sign in to comment.