You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AuthTokenSection.vue 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <!--
  2. - @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
  3. -
  4. - @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
  5. -
  6. - @license GNU AGPL version 3 or any later version
  7. -
  8. - This program is free software: you can redistribute it and/or modify
  9. - it under the terms of the GNU Affero General Public License as
  10. - published by the Free Software Foundation, either version 3 of the
  11. - License, or (at your option) any later version.
  12. -
  13. - This program is distributed in the hope that it will be useful,
  14. - but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. - GNU Affero General Public License for more details.
  17. -
  18. - You should have received a copy of the GNU Affero General Public License
  19. - along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. -->
  21. <template>
  22. <div id="security" class="section">
  23. <h2>{{ t('settings', 'Devices & sessions', {}, undefined, {sanitize: false}) }}</h2>
  24. <p class="settings-hint hidden-when-empty">
  25. {{ t('settings', 'Web, desktop and mobile clients currently logged in to your account.') }}
  26. </p>
  27. <AuthTokenList :tokens="tokens"
  28. @toggleScope="toggleTokenScope"
  29. @rename="rename"
  30. @delete="deleteToken"
  31. @wipe="wipeToken" />
  32. <AuthTokenSetupDialogue v-if="canCreateToken" :add="addNewToken" />
  33. </div>
  34. </template>
  35. <script>
  36. import axios from '@nextcloud/axios'
  37. import confirmPassword from '@nextcloud/password-confirmation'
  38. import { generateUrl } from '@nextcloud/router'
  39. import AuthTokenList from './AuthTokenList'
  40. import AuthTokenSetupDialogue from './AuthTokenSetupDialogue'
  41. const confirm = () => {
  42. return new Promise(resolve => {
  43. OC.dialogs.confirm(
  44. t('settings', 'Do you really want to wipe your data from this device?'),
  45. t('settings', 'Confirm wipe'),
  46. resolve,
  47. true
  48. )
  49. })
  50. }
  51. /**
  52. * Tap into a promise without losing the value
  53. * @param {Function} cb the callback
  54. * @returns {any} val the value
  55. */
  56. const tap = cb => val => {
  57. cb(val)
  58. return val
  59. }
  60. export default {
  61. name: 'AuthTokenSection',
  62. components: {
  63. AuthTokenSetupDialogue,
  64. AuthTokenList,
  65. },
  66. props: {
  67. tokens: {
  68. type: Array,
  69. required: true,
  70. },
  71. canCreateToken: {
  72. type: Boolean,
  73. required: true,
  74. },
  75. },
  76. data() {
  77. return {
  78. baseUrl: generateUrl('/settings/personal/authtokens'),
  79. }
  80. },
  81. methods: {
  82. addNewToken(name) {
  83. console.debug('creating a new app token', name)
  84. const data = {
  85. name,
  86. }
  87. return axios.post(this.baseUrl, data)
  88. .then(resp => resp.data)
  89. .then(tap(() => console.debug('app token created')))
  90. // eslint-disable-next-line vue/no-mutating-props
  91. .then(tap(data => this.tokens.push(data.deviceToken)))
  92. .catch(err => {
  93. console.error.bind('could not create app password', err)
  94. OC.Notification.showTemporary(t('core', 'Error while creating device token'))
  95. throw err
  96. })
  97. },
  98. toggleTokenScope(token, scope, value) {
  99. console.debug('updating app token scope', token.id, scope, value)
  100. const oldVal = token.scope[scope]
  101. token.scope[scope] = value
  102. return this.updateToken(token)
  103. .then(tap(() => console.debug('app token scope updated')))
  104. .catch(err => {
  105. console.error.bind('could not update app token scope', err)
  106. OC.Notification.showTemporary(t('core', 'Error while updating device token scope'))
  107. // Restore
  108. token.scope[scope] = oldVal
  109. throw err
  110. })
  111. },
  112. rename(token, newName) {
  113. console.debug('renaming app token', token.id, token.name, newName)
  114. const oldName = token.name
  115. token.name = newName
  116. return this.updateToken(token)
  117. .then(tap(() => console.debug('app token name updated')))
  118. .catch(err => {
  119. console.error.bind('could not update app token name', err)
  120. OC.Notification.showTemporary(t('core', 'Error while updating device token name'))
  121. // Restore
  122. token.name = oldName
  123. })
  124. },
  125. updateToken(token) {
  126. return axios.put(this.baseUrl + '/' + token.id, token)
  127. .then(resp => resp.data)
  128. },
  129. deleteToken(token) {
  130. console.debug('deleting app token', token)
  131. // eslint-disable-next-line vue/no-mutating-props
  132. this.tokens = this.tokens.filter(t => t !== token)
  133. return axios.delete(this.baseUrl + '/' + token.id)
  134. .then(resp => resp.data)
  135. .then(tap(() => console.debug('app token deleted')))
  136. .catch(err => {
  137. console.error.bind('could not delete app token', err)
  138. OC.Notification.showTemporary(t('core', 'Error while deleting the token'))
  139. // Restore
  140. // eslint-disable-next-line vue/no-mutating-props
  141. this.tokens.push(token)
  142. })
  143. },
  144. async wipeToken(token) {
  145. console.debug('wiping app token', token)
  146. try {
  147. await confirmPassword()
  148. if (!(await confirm())) {
  149. console.debug('wipe aborted by user')
  150. return
  151. }
  152. await axios.post(this.baseUrl + '/wipe/' + token.id)
  153. console.debug('app token marked for wipe')
  154. token.type = 2
  155. } catch (err) {
  156. console.error('could not wipe app token', err)
  157. OC.Notification.showTemporary(t('core', 'Error while wiping the device with the token'))
  158. }
  159. },
  160. },
  161. }
  162. </script>
  163. <style scoped>
  164. </style>