AuthSettings.vue 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. <script setup lang="tsx">
  2. import { message } from 'ant-design-vue'
  3. import type { Ref } from 'vue'
  4. import dayjs from 'dayjs'
  5. import type { BannedIP } from '@/api/settings'
  6. import setting from '@/api/settings'
  7. import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
  8. import type { Settings } from '@/views/preference/typedef'
  9. import TOTP from '@/views/preference/components/TOTP.vue'
  10. import PasskeyRegistration from '@/components/Passkey/PasskeyRegistration.vue'
  11. import { $gettext } from '@/gettext'
  12. const data: Settings = inject('data') as Settings
  13. const bannedIPColumns = [{
  14. title: $gettext('IP'),
  15. dataIndex: 'ip',
  16. }, {
  17. title: $gettext('Attempts'),
  18. dataIndex: 'attempts',
  19. }, {
  20. title: $gettext('Banned Until'),
  21. dataIndex: 'expired_at',
  22. customRender: (args: customRender) => {
  23. return dayjs.unix(args.text).format('YYYY-MM-DD HH:mm:ss')
  24. },
  25. }, {
  26. title: $gettext('Action'),
  27. dataIndex: 'action',
  28. }]
  29. const bannedIPs: Ref<BannedIP[]> = ref([])
  30. function getBannedIPs() {
  31. setting.get_banned_ips().then(r => {
  32. bannedIPs.value = r
  33. })
  34. }
  35. getBannedIPs()
  36. defineExpose({
  37. getBannedIPs,
  38. })
  39. function removeBannedIP(ip: string) {
  40. setting.remove_banned_ip(ip).then(() => {
  41. bannedIPs.value = bannedIPs.value.filter(v => v.ip !== ip)
  42. message.success($gettext('Remove successfully'))
  43. }).catch((e: { message?: string }) => {
  44. message.error(e?.message ?? $gettext('Server error'))
  45. })
  46. }
  47. </script>
  48. <template>
  49. <div class="flex justify-center">
  50. <div>
  51. <h2>{{ $gettext('2FA Settings') }}</h2>
  52. <PasskeyRegistration class="mb-4" />
  53. <TOTP class="mb-4" />
  54. <h2>
  55. {{ $gettext('Authentication Settings') }}
  56. </h2>
  57. <AAlert
  58. class="mb-4"
  59. :message="$gettext('Tips')"
  60. :description="$gettext('If the number of login failed attempts from a ip reach the max attempts in ban threshold minutes,'
  61. + ' the ip will be banned for a period of time.')"
  62. type="info"
  63. />
  64. <AForm
  65. layout="horizontal"
  66. style="width:90%;max-width: 500px"
  67. >
  68. <AFormItem :label="$gettext('Ban Threshold Minutes')">
  69. <AInputNumber
  70. v-model:value="data.auth.ban_threshold_minutes"
  71. min="1"
  72. />
  73. </AFormItem>
  74. <AFormItem :label="$gettext('Max Attempts')">
  75. <AInputNumber
  76. v-model:value="data.auth.max_attempts"
  77. min="1"
  78. />
  79. </AFormItem>
  80. </AForm>
  81. <h3>
  82. {{ $gettext('Banned IPs') }}
  83. </h3>
  84. <div class="mb-6">
  85. <ATable
  86. :columns="bannedIPColumns"
  87. row-key="ip"
  88. :data-source="bannedIPs"
  89. size="small"
  90. >
  91. <template #bodyCell="{ column, record }">
  92. <template v-if="column.dataIndex === 'action'">
  93. <APopconfirm
  94. :title="$gettext('Are you sure to delete this banned IP immediately?')"
  95. :ok-text="$gettext('Yes')"
  96. :cancel-text="$gettext('No')"
  97. placement="bottom"
  98. @confirm="() => removeBannedIP(record.ip)"
  99. >
  100. <a>
  101. {{ $gettext('Remove') }}
  102. </a>
  103. </APopconfirm>
  104. </template>
  105. </template>
  106. </ATable>
  107. </div>
  108. </div>
  109. </div>
  110. </template>
  111. <style lang="less" scoped>
  112. </style>