WebauthnKeys.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. <template>
  2. <div>
  3. <div class="mt-6">
  4. <h3 class="font-bold text-xl">Device Authentication (WebAuthn)</h3>
  5. <div class="my-4 w-24 border-b-2 border-grey-200"></div>
  6. <p class="my-6">
  7. Hardware security keys you have registered for 2nd factor authentication. To remove a key
  8. simply click the delete button next to it. Disabling all keys will turn off 2FA on your
  9. account.
  10. </p>
  11. <div>
  12. <p class="mb-0" v-if="keys.length === 0">You have not registered any hardware keys.</p>
  13. <div class="table w-full text-sm md:text-base" v-if="keys.length > 0">
  14. <div class="table-row">
  15. <div class="table-cell p-1 md:p-4 font-semibold">Name</div>
  16. <div class="table-cell p-1 md:p-4 font-semibold">Created</div>
  17. <div class="table-cell p-1 md:p-4 font-semibold">Enabled</div>
  18. <div class="table-cell p-1 md:p-4 text-right">
  19. <a href="/webauthn/keys/create" class="text-indigo-700">Add New Key</a>
  20. </div>
  21. </div>
  22. <div v-for="key in keys" :key="key.id" class="table-row even:bg-grey-50 odd:bg-white">
  23. <div class="table-cell p-1 md:p-4">{{ key.name }}</div>
  24. <div class="table-cell p-1 md:p-4">{{ $filters.timeAgo(key.created_at) }}</div>
  25. <div class="table-cell p-1 md:p-4">
  26. <Toggle v-model="key.enabled" @on="enableKey(key.id)" @off="disableKey(key.id)" />
  27. </div>
  28. <div class="table-cell p-1 md:p-4 text-right">
  29. <a
  30. class="text-red-500 font-bold cursor-pointer focus:outline-none"
  31. @click="showRemoveModal(key)"
  32. >
  33. Delete
  34. </a>
  35. </div>
  36. </div>
  37. </div>
  38. </div>
  39. </div>
  40. <Modal :open="deleteKeyModalOpen" @close="closeDeleteKeyModal">
  41. <template v-slot:title> Remove Hardware Key </template>
  42. <template v-slot:content>
  43. <p v-if="keys.length === 1" class="my-4 text-grey-700">
  44. Once this key is removed, <b>Two-Factor Authentication</b> will be disabled on your
  45. account.
  46. </p>
  47. <p v-else class="my-4 text-grey-700">
  48. Once this key is removed, <b>Two-Factor Authentication</b> will still be enabled as you
  49. have other hardware keys associated with your account.
  50. </p>
  51. <div class="mt-6">
  52. <button
  53. @click="remove"
  54. class="bg-red-500 hover:bg-red-600 text-white font-bold py-3 px-4 rounded focus:outline-none"
  55. :class="removeKeyLoading ? 'cursor-not-allowed' : ''"
  56. :disabled="removeKeyLoading"
  57. >
  58. Remove
  59. <loader v-if="removeKeyLoading" />
  60. </button>
  61. <button
  62. @click="closeDeleteKeyModal"
  63. class="ml-4 px-4 py-3 text-grey-800 font-semibold bg-white hover:bg-grey-50 border border-grey-100 rounded focus:outline-none"
  64. >
  65. Close
  66. </button>
  67. </div>
  68. </template>
  69. </Modal>
  70. </div>
  71. </template>
  72. <script>
  73. import Modal from './Modal.vue'
  74. import Toggle from './../components/Toggle.vue'
  75. export default {
  76. components: {
  77. Modal,
  78. Toggle,
  79. },
  80. data() {
  81. return {
  82. deleteKeyModalOpen: false,
  83. keys: [],
  84. keyToRemove: null,
  85. loading: false,
  86. removeKeyLoading: false,
  87. }
  88. },
  89. mounted() {
  90. this.getWebauthnKeys()
  91. },
  92. methods: {
  93. getWebauthnKeys() {
  94. axios.get('/webauthn/keys').then(response => {
  95. this.keys = response.data
  96. })
  97. },
  98. showRemoveModal(token) {
  99. this.keyToRemove = token
  100. this.deleteKeyModalOpen = true
  101. },
  102. remove() {
  103. this.removeKeyLoading = true
  104. axios.delete(`/webauthn/keys/${this.keyToRemove.id}`).then(response => {
  105. this.removeKeyLoading = false
  106. this.deleteKeyModalOpen = false
  107. this.keyToRemove = null
  108. if (this.keys.length === 1) {
  109. location.reload()
  110. } else {
  111. this.getWebauthnKeys()
  112. }
  113. })
  114. },
  115. enableKey(id) {
  116. axios
  117. .post(
  118. `/webauthn/enabled-keys`,
  119. JSON.stringify({
  120. id: id,
  121. }),
  122. {
  123. headers: { 'Content-Type': 'application/json' },
  124. }
  125. )
  126. .then(response => {
  127. //
  128. })
  129. .catch(error => {
  130. if (error.response !== undefined) {
  131. this.error(error.response.data)
  132. } else {
  133. this.error()
  134. }
  135. })
  136. },
  137. disableKey(id) {
  138. axios
  139. .delete(`/webauthn/enabled-keys/${id}`)
  140. .then(response => {
  141. //
  142. })
  143. .catch(error => {
  144. if (error.response !== undefined) {
  145. this.error(error.response.data)
  146. } else {
  147. this.error()
  148. }
  149. })
  150. },
  151. closeDeleteKeyModal() {
  152. this.deleteKeyModalOpen = false
  153. },
  154. },
  155. }
  156. </script>