Merge pull request #2121 from jumpserver/pr@v3@feat_account_password_history

feat: 资产账号增加查看历史密码
This commit is contained in:
feng626 2022-10-25 14:00:13 +08:00 committed by GitHub
commit 4effc3c3b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 171 additions and 23 deletions

View File

@ -99,7 +99,7 @@ export default {
}, },
push_now: { push_now: {
hidden: () => { hidden: () => {
return !this.platform.automation['push_account_enabled'] return !this.platform.automation?.['push_account_enabled']
} }
} }
}, },
@ -112,7 +112,7 @@ export default {
afterGetRemoteMeta(meta) { afterGetRemoteMeta(meta) {
const choices = meta.secret_type.choices const choices = meta.secret_type.choices
const secretTypes = [] const secretTypes = []
this.platform.protocols.forEach(p => { this.platform.protocols?.forEach(p => {
secretTypes.push(...p['secret_types']) secretTypes.push(...p['secret_types'])
}) })
if (!this.form.secret_type) { if (!this.form.secret_type) {

View File

@ -72,8 +72,7 @@ export default {
}, },
methods: { methods: {
async getPlatform() { async getPlatform() {
this.platform = await this.$axios.get(`/api/v1/assets/platforms/${this.asset.platform.id}/`) this.platform = await this.$axios.get(`/api/v1/assets/platforms/${this.asset?.platform?.id}/`)
console.log('Platform: ', this.platform)
}, },
addAccount(form) { addAccount(form) {
const data = { asset: this.asset.id, ...form } const data = { asset: this.asset.id, ...form }

View File

@ -0,0 +1,75 @@
<template>
<GenericListTableDialog :visible.sync="iVisible" v-bind="config" />
</template>
<script>
import { GenericListTableDialog } from '@/layout/components'
export default {
components: {
GenericListTableDialog
},
props: {
account: {
type: Object,
default: () => ({})
},
visible: {
type: Boolean,
default: false
}
},
data() {
return {
config: {
title: this.$t('accounts.HistoryPassword'),
visible: false,
width: '60%',
tableConfig: {
url: `/api/v1/assets/accounts-historys?id=${this.account.id}`,
columns: [
'name', 'version', 'password', 'date_created'
],
columnsShow: {
min: ['name'],
default: [
'name', 'version', 'password', 'date_created'
]
},
columnsMeta: {
name: {
showOverflowTooltip: true
}
}
},
headerActions: {
hasImport: false,
hasExport: false,
hasLeftActions: false,
hasColumnSetting: false
}
}
}
},
computed: {
iVisible: {
get() {
return this.visible
},
set(val) {
this.$emit('update:visible', val)
}
}
},
created() {
},
methods: {
}
}
</script>
<style scoped>
</style>

View File

@ -17,17 +17,26 @@
> >
<div> <div>
<el-form label-position="right" label-width="80px" :model="authInfo"> <el-form label-position="right" label-width="80px" :model="authInfo">
<el-form-item :label="this.$tc('assets.Name')"> <el-form-item :label="this.$t('assets.Name')">
<el-input v-model="account['name']" readonly /> <el-input v-model="account.asset.name" readonly />
</el-form-item> </el-form-item>
<el-form-item :label="this.$tc('assets.Username')"> <el-form-item :label="this.$tc('assets.Username')">
<el-input v-model="account['username']" readonly /> <el-input v-model="account['username']" readonly />
</el-form-item> </el-form-item>
<el-form-item v-if="account['secret_type'] === 'password'" :label="this.$tc('assets.Password')"> <el-form-item v-if="secretTypePassword" :label="this.$t('assets.Password')">
<el-input v-model="authInfo.secret" type="password" show-password /> <ShowKeyCopyFormatter v-model="authInfo.secret" />
</el-form-item> </el-form-item>
<el-form-item v-else :label="this.$tc('assets.Key')"> <el-form-item v-else :label="this.$t('users.SSHKey')">
<el-input v-model="authInfo.secret" type="textarea" :rows="10" /> <el-input v-model="authInfo['private_key']" class="item-textarea" type="textarea" show-password readonly />
</el-form-item>
<el-form-item :label="this.$t('common.DateCreated')">
<span>{{ $moment(authInfo.date_created, 'YYYY-MM-DD HH:mm:ss').format('YYYY-MM-DD HH:mm:ss') }}</span>
</el-form-item>
<el-form-item :label="this.$t('common.DateUpdated')">
<span>{{ $moment(authInfo.date_updated, 'YYYY-MM-DD HH:mm:ss').format('YYYY-MM-DD HH:mm:ss') }}</span>
</el-form-item>
<el-form-item :label="this.$t('accounts.PasswordRecord')">
<span>{{ authInfo.version }}</span>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
@ -38,11 +47,14 @@
<script> <script>
import Dialog from '@/components/Dialog' import Dialog from '@/components/Dialog'
import UserConfirmDialog from '@/components/UserConfirmDialog' import UserConfirmDialog from '@/components/UserConfirmDialog'
import { ShowKeyCopyFormatter } from '@/components/TableFormatters'
export default { export default {
name: 'ShowSecretInfo', name: 'ShowSecretInfo',
components: { components: {
Dialog, Dialog,
UserConfirmDialog UserConfirmDialog,
ShowKeyCopyFormatter
}, },
props: { props: {
account: { account: {
@ -62,6 +74,11 @@ export default {
url: `/api/v1/assets/account-secrets/${this.account.id}/` url: `/api/v1/assets/account-secrets/${this.account.id}/`
} }
}, },
computed: {
secretTypePassword() {
return this.authInfo.secret_type === 'password'
}
},
methods: { methods: {
getAuthInfo() { getAuthInfo() {
this.$axios.get(this.url, { disableFlashErrorMsg: true }).then(resp => { this.$axios.get(this.url, { disableFlashErrorMsg: true }).then(resp => {
@ -76,8 +93,23 @@ export default {
} }
</script> </script>
<style scoped> <style lang="scss" scoped>
.item-textarea >>> .el-textarea__inner { .item-textarea >>> .el-textarea__inner {
height: 110px; height: 110px;
} }
ul {
margin: 0;
}
li {
display: block;
font-size: 13px;
margin-bottom: 8px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.title {
color: #303133;
font-weight: 500;
}
}
</style> </style>

View File

@ -15,6 +15,11 @@
:account="account" :account="account"
@add="addAccountSuccess" @add="addAccountSuccess"
/> />
<PasswordHistoryDialog
v-if="showPasswordHistoryDialog"
:account="account"
:visible.sync="showPasswordHistoryDialog"
/>
</div> </div>
</template> </template>
@ -27,12 +32,14 @@ import AddAccount from './AddAccount'
import { connectivityMeta } from './const' import { connectivityMeta } from './const'
import { openTaskPage } from '@/utils/jms' import { openTaskPage } from '@/utils/jms'
import { hasUUID } from '@/utils/common' import { hasUUID } from '@/utils/common'
import PasswordHistoryDialog from './PasswordHistoryDialog'
export default { export default {
name: 'AccountListTable', name: 'AccountListTable',
components: { components: {
ListTable, ListTable,
UpdateSecretInfo, UpdateSecretInfo,
PasswordHistoryDialog,
ViewSecret, ViewSecret,
AddAccount AddAccount
}, },
@ -71,6 +78,7 @@ export default {
data() { data() {
const vm = this const vm = this
return { return {
showPasswordHistoryDialog: false,
showViewSecretDialog: false, showViewSecretDialog: false,
showUpdateSecretDialog: false, showUpdateSecretDialog: false,
showAddDialog: false, showAddDialog: false,
@ -176,6 +184,17 @@ export default {
vm.showAddDialog = true vm.showAddDialog = true
}) })
} }
},
{
title: this.$t('accounts.HistoryPassword'),
can: this.$hasPerm('assets.change_assetaccountsecret') && !this.$store.getters.currentOrgIsRoot,
callback: ({ row }) => {
vm.account = row
vm.showPasswordHistoryDialog = false
setTimeout(() => {
vm.showPasswordHistoryDialog = true
})
}
} }
] ]
} }

View File

@ -3,6 +3,7 @@
<span>{{ currentValue }}</span> <span>{{ currentValue }}</span>
<span class="right"> <span class="right">
<el-tooltip <el-tooltip
v-if="hasShow"
effect="dark" effect="dark"
placement="top" placement="top"
:content="this.$t('common.View')" :content="this.$t('common.View')"
@ -10,6 +11,7 @@
<i class="el-icon-view" @click="onShow()" /> <i class="el-icon-view" @click="onShow()" />
</el-tooltip> </el-tooltip>
<el-tooltip <el-tooltip
v-if="hasCopy"
effect="dark" effect="dark"
placement="top" placement="top"
:content="this.$t('common.Copy')" :content="this.$t('common.Copy')"
@ -21,15 +23,24 @@
</template> </template>
<script> <script>
import BaseFormatter from './base'
export default { export default {
name: 'ShowKeyCopyFormatter', name: 'ShowKeyCopyFormatter',
extends: BaseFormatter, props: {
proops: { value: {
cellValue: {
type: String, type: String,
default: () => '' default: () => ''
},
cellValue: {
type: [String, Number],
default: null
},
hasShow: {
type: Boolean,
default: true
},
hasCopy: {
type: Boolean,
default: true
} }
}, },
data() { data() {
@ -37,18 +48,24 @@ export default {
currentValue: this.switchShowValue() currentValue: this.switchShowValue()
} }
}, },
computed: {
iValue() {
return this.value || this.cellValue
}
},
methods: { methods: {
switchShowValue() { switchShowValue() {
return '******' + this.cellValue.replace(/[\w-]/g, '') const value = this.value || this.cellValue
return '******' + value.replace(/[\s\S]/g, '')
}, },
onShow() { onShow() {
const { currentValue, cellValue, switchShowValue } = this const { currentValue, switchShowValue } = this
this.currentValue = currentValue === cellValue ? switchShowValue() : cellValue this.currentValue = currentValue === this.iValue ? switchShowValue() : this.iValue
}, },
onCopy: _.throttle(function() { onCopy: _.throttle(function() {
const inputDom = document.createElement('input') const inputDom = document.createElement('input')
inputDom.id = 'creatInputDom' inputDom.id = 'createInputDom'
inputDom.value = this.cellValue inputDom.value = this.iValue
document.body.appendChild(inputDom) document.body.appendChild(inputDom)
inputDom.select() inputDom.select()
document?.execCommand('copy') document?.execCommand('copy')
@ -74,7 +91,7 @@ export default {
cursor: pointer; cursor: pointer;
.el-icon-view, .el-icon-copy-document { .el-icon-view, .el-icon-copy-document {
&:hover { &:hover {
color: #1c84c6; color: var(--color-primary);
} }
} }
} }

View File

@ -1,6 +1,8 @@
{ {
"": "", "": "",
"accounts": { "accounts": {
"HistoryPassword": "History password",
"PasswordRecord": "Password record",
"AccountHistableHelpMessage": "Record the historical version of the current account", "AccountHistableHelpMessage": "Record the historical version of the current account",
"PleaseClickLeftAssetToViewAssetAccount": "Asset account list, please click on the assets on the left to view", "PleaseClickLeftAssetToViewAssetAccount": "Asset account list, please click on the assets on the left to view",
"PleaseClickLeftApplicationToViewApplicationAccount": "Application account list, please click on the application on the left to view", "PleaseClickLeftApplicationToViewApplicationAccount": "Application account list, please click on the application on the left to view",

View File

@ -1,6 +1,8 @@
{ {
"": "", "": "",
"accounts": { "accounts": {
"HistoryPassword": "履歴パスワード",
"PasswordRecord": "パスワードレコード",
"AccountHistableHelpMessage": "現在のアカウントの履歴バージョンを記録する", "AccountHistableHelpMessage": "現在のアカウントの履歴バージョンを記録する",
"PleaseClickLeftAssetToViewAssetAccount": "資産のアカウントのリスト、左側の資産をクリックして表示します", "PleaseClickLeftAssetToViewAssetAccount": "資産のアカウントのリスト、左側の資産をクリックして表示します",
"PleaseClickLeftApplicationToViewApplicationAccount": "アカウントのリストを適用して、左側のアプリケーションをクリックして表示します", "PleaseClickLeftApplicationToViewApplicationAccount": "アカウントのリストを適用して、左側のアプリケーションをクリックして表示します",

View File

@ -1,6 +1,8 @@
{ {
"": "", "": "",
"accounts": { "accounts": {
"HistoryPassword": "历史密码",
"PasswordRecord": "密码记录",
"AccountHistableHelpMessage": "记录当前账号的历史版本", "AccountHistableHelpMessage": "记录当前账号的历史版本",
"PleaseClickLeftAssetToViewAssetAccount": "资产账号列表,点击左侧资产进行查看", "PleaseClickLeftAssetToViewAssetAccount": "资产账号列表,点击左侧资产进行查看",
"PleaseClickLeftApplicationToViewApplicationAccount": "应用账号列表,点击左侧应用进行查看", "PleaseClickLeftApplicationToViewApplicationAccount": "应用账号列表,点击左侧应用进行查看",