perf: update pam

This commit is contained in:
ibuler
2025-01-10 17:53:44 +08:00
parent 1f5cc25b86
commit 9cefe70061
13 changed files with 165 additions and 42 deletions

View File

@@ -132,7 +132,7 @@ export default {
columnsDefault: {
type: Array,
default: () => ([
'name', 'username', 'secret', 'asset', 'platform', 'date_updated', 'connect'
'name', 'username', 'secret', 'asset', 'platform', 'connect'
])
},
headerExtraActions: {
@@ -210,6 +210,7 @@ export default {
},
platform: {
label: this.$t('Platform'),
width: '120px',
formatter: PlatformFormatter,
formatterArgs: {
platformAttr: 'asset.platform'

View File

@@ -4,6 +4,7 @@
height="300"
title="Processing"
width="300"
class="processing-dialog"
>
<div id="load">
<div class="spinner" />
@@ -40,12 +41,18 @@ export default {
</script>
<style lang="scss" scoped>
.processing-dialog {
::v-deep .el-dialog__body {
overflow: hidden;
}
}
.spinner {
width: 100px;
height: 100px;
border: 5px solid rgba(0, 0, 0, 0.1);
border-radius: 50%;
border-top-color: #3498db;
border-top-color: var(--color-primary);
animation: spin 1s infinite linear;
}

View File

@@ -0,0 +1,69 @@
<template>
<Dialog
:visible="iVisible"
height="300"
title="Processing"
width="300"
class="processing-dialog"
>
<div id="load">
<div class="spinner" />
</div>
</Dialog>
</template>
<script>
import Dialog from './index.vue'
export default {
name: 'RemoteProcessingDialog',
components: { Dialog },
props: {
visible: {
type: Boolean,
default: false
}
},
data() {
return {}
},
computed: {
iVisible: {
get() {
return this.visible
},
set(val) {
this.$emit('update:visible', val)
}
}
}
}
</script>
<style lang="scss" scoped>
.processing-dialog {
::v-deep .el-dialog__body {
overflow: hidden;
}
}
.spinner {
width: 100px;
height: 100px;
border: 5px solid rgba(0, 0, 0, 0.1);
border-radius: 50%;
border-top-color: var(--color-primary);
animation: spin 1s infinite linear;
}
#load {
display: flex;
justify-content: center;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
</style>

View File

@@ -6,15 +6,15 @@
<el-input
v-show="isShow"
v-model.trim="curValue"
:disabled="disabled"
:placeholder="placeholder"
:type="type"
:disabled="disabled"
class="password-input"
show-password
@change="onChange"
/>
<el-button size="small" type="text" :disabled="disabled" @click="randomPassword">
<i class="fa fa-retweet" />
<el-button :disabled="disabled" size="small" type="text" @click="randomPassword">
<i class="fa fa-refresh" />
</el-button>
</div>
</template>

View File

@@ -7,6 +7,18 @@
"notAlphanumericUnderscore": "Only alphanumeric characters and underscores are allowed.",
"notParenthesis": "Parentheses are not allowed.",
"InvalidJson": "Invalid JSON format.",
"requiredHasUserNameMapped": "Username attr is required."
"requiredHasUserNameMapped": "Username attr is required.",
"NewFound": "New Found",
"LastLoginTime": "Last login time",
"Diff": "Difference",
"LastChangeTime": "Last change time",
"AccountDeleted": "Account deleted",
"WeakPassword": "Weak password",
"RepeatPassword": "Repeat password",
"LeakPassword": "Password leaked",
"Other": "Other",
"Details": "Details",
"Confirm": "Confirm",
"Ignore": "Ignore"
}

View File

@@ -1,11 +1,12 @@
{
"FieldRequiredError": "这个字段是必需的。",
"InputEmailAddress": "输入一个电子邮件地址。",
"ServerError": "服务错误,请联系管理员。",
"FormatError": "格式错误。",
"NotSpecialEmoji": "不支持表情字符。",
"notAlphanumericUnderscore": "仅支持字母、数字和下划线。",
"notParenthesis": "不能包含括号。",
"InvalidJson": "JSON 格式错误.",
"requiredHasUserNameMapped": "用户名属性是必需的。"
"FieldRequiredError": "这个字段是必需的。",
"InputEmailAddress": "输入一个电子邮件地址。",
"ServerError": "服务错误,请联系管理员。",
"FormatError": "格式错误。",
"NotSpecialEmoji": "不支持表情字符。",
"notAlphanumericUnderscore": "仅支持字母、数字和下划线。",
"notParenthesis": "不能包含括号。",
"InvalidJson": "JSON 格式错误.",
"requiredHasUserNameMapped": "用户名属性是必需的。",
"Diff": ""
}

View File

@@ -7,5 +7,17 @@
"notAlphanumericUnderscore": "仅支持字母、数字和下划线。",
"notParenthesis": "不能包含括号。",
"InvalidJson": "JSON 格式错误.",
"requiredHasUserNameMapped": "用户名属性是必需的。"
"requiredHasUserNameMapped": "用户名属性是必需的。",
"NewFound": "新发现",
"LastLoginTime": "最后登录时间",
"Diff": "差异",
"LastChangeTime": "最后修改时间",
"AccountDeleted": "账户已删除",
"WeakPassword": "弱密码",
"RepeatPassword": "重复密码",
"LeakPassword": "密码泄露",
"Other": "其他",
"Details": "详情",
"Confirm": "确认",
"Ignore": "忽略"
}

View File

@@ -102,8 +102,11 @@ const actions = {
const recentPlatformIds = state.recentPlatformIds
return new Promise(resolve => {
dispatch('getPlatforms').then(platforms => {
const recentPlatforms = platforms.filter(p => recentPlatformIds.includes(p.id))
.sort((a, b) => recentPlatformIds.indexOf(a.id) - recentPlatformIds.indexOf(b.id))
const platformsMap = {}
platforms.forEach(p => {
platformsMap[p.id] = p
})
const recentPlatforms = recentPlatformIds.map(id => platformsMap[id]).filter(p => p)
resolve(recentPlatforms)
})
})

View File

@@ -252,10 +252,9 @@ export default {
},
async setRecentPlatforms() {
const recentPlatforms = await this.$store.dispatch('assets/getRecentPlatforms')
const recentIds = recentPlatforms.map(item => item.id)
let allPlatforms = await this.$store.dispatch('assets/getPlatforms')
allPlatforms = allPlatforms.filter(item => !recentIds.includes(item.id))
let platforms = [...recentPlatforms, ...allPlatforms]
const allPlatforms = await this.$store.dispatch('assets/getPlatforms')
const otherPlatforms = allPlatforms.filter(item => !this.recentPlatformIds.includes(item.id))
let platforms = [...recentPlatforms, ...otherPlatforms]
if (this.category !== 'all') {
platforms = platforms.filter(item => item.category.value === this.category)
}

View File

@@ -72,8 +72,6 @@ export default {
<style lang="scss" scoped>
.dashboard-container {
padding: 1.25rem;
.top-summary,
.middle-section,
.bottom-section {
@@ -108,7 +106,7 @@ export default {
background: #fff;
padding: 1.25rem;
height: 100%;
box-shadow: 0 1px 4px rgba(0,21,41,.08);
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
transition: all .3s;
::v-deep .card-content {
@@ -124,14 +122,14 @@ export default {
.mission-summary {
background: #fff;
padding: 1.25rem;
box-shadow: 0 1px 4px rgba(0,21,41,.08);
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
}
.secret-summary {
background: #fff;
padding: 1.25rem;
margin-bottom: 1.25rem;
box-shadow: 0 1px 4px rgba(0,21,41,.08);
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
}
@media screen and (max-width: 1200px) {

View File

@@ -15,6 +15,7 @@ export default {
fields: [
[this.$t('Basic'), ['name', 'scope']],
[this.$t('Other'), ['comment']]
],
createSuccessNextRoute: {
name: 'Template'

View File

@@ -3,6 +3,7 @@
:title="$t('Details')"
:visible.sync="iVisible"
append-to-body
class="drawer"
destroy-on-close
direction="rtl"
style="z-index: 999"
@@ -10,7 +11,9 @@
>
<div class="drawer-body">
<div v-for="r in iRows" :key="r.id">
<div class="host-username">{{ r.asset ? r.asset.name : r }} - {{ r.username }}</div>
<div class="host-username">
{{ r.username }}@{{ r.asset ? r.asset.name : r }}
</div>
<el-timeline :reverse="true">
<el-timeline-item
v-for="detail in r.details"
@@ -54,13 +57,14 @@ export default {
default: true
},
rows: {
type: Array,
type: Array, // review
default: () => []
}
},
data() {
return {
riskActions
riskActions,
title: this.$t('Details of')
}
},
computed: {
@@ -128,23 +132,29 @@ export default {
handleInit(row, detail) {
switch (row.risk.value) {
case 'new_found':
return this.$tc('New found')
return this.$tc('NewFound')
case 'long_time_no_login':
return this.$tc('Last login time') + ': ' + this.formatTimestamp(detail.date)
return this.$tc('LastLoginTime') + ': ' + this.formatTimestamp(detail.date)
case 'group_changed':
case 'sudoers_changed':
case 'authorized_key_changed':
return `变更:
return this.$t('Diff') + `:
<pre>
${detail.diff}
</pre>
`
case 'long_time_password':
return this.$t('Last change time') + ': ' + this.formatTimestamp(detail.date)
return this.$t('LastChangeTime') + ': ' + this.formatTimestamp(detail.date)
case 'account_deleted':
return this.$t('Account deleted')
return this.$t('AccountDeleted')
case 'weak_password':
return this.$t('WeakPassword')
case 'repeat_password':
return this.$t('RepeatPassword')
case 'leak_password':
return this.$t('LeakPassword')
default:
return '其它'
return this.$t('Other')
}
}
}
@@ -152,12 +162,21 @@ ${detail.diff}
</script>
<style lang='scss' scoped>
.drawer {
::v-deep {
.el-drawer__header {
padding: 15px 20px 5px;
}
}
}
.drawer-body {
height: calc(100% - 40px - 40px);
height: calc(100% - 40px - 30px);
overflow: auto;
::v-deep .el-drawer__body {
overflow: auto;
padding: 0 10px;
}
::v-deep pre {
@@ -165,18 +184,19 @@ ${detail.diff}
}
.host-username {
font-size: 13px;
margin-left: 40px;
margin-bottom: 10px;
font-weight: 500;
}
}
.drawer-footer {
border-top: solid 1px var(--color-border);
height: 70px;
padding: 15px 30px;
height: 60px;
line-height: 60px;
padding: 0 30px;
.buttons {
}
}
</style>

View File

@@ -35,7 +35,7 @@
</template>
<script>
import BaseFormatter from '@/components/Table/TableFormatters/base.vue'
import ReviewDraw from '@/views/pam/RiskDetect/RiskHandlerFormatter/ReviewDraw.vue'
import ReviewDraw from '@/views/pam/RiskDetect/RiskHandlerFormatter/ReviewDrawer.vue'
import ProcessingDialog from '@/components/Dialog/ProcessingDialog.vue'
import { riskActions } from './const'
import { sleep } from '@/utils/time'