login.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. <template lang="pug">
  2. .login(:class='{ "is-error": error }')
  3. .login-container(:class='{ "is-expanded": strategies.length > 1, "is-loading": isLoading }')
  4. .login-providers(v-show='strategies.length > 1')
  5. button(v-for='strategy in strategies', :class='{ "is-active": strategy.key === selectedStrategy }', @click='selectStrategy(strategy.key, strategy.useForm)', :title='strategy.title')
  6. em(v-html='strategy.icon')
  7. span {{ strategy.title }}
  8. .login-providers-fill
  9. .login-frame(v-show='screen === "login"')
  10. h1 {{ siteTitle }}
  11. h2 {{ $t('auth:loginRequired') }}
  12. input(type='text', ref='iptEmail', v-model='username', :placeholder='$t("auth:fields.emailUser")')
  13. input(type='password', ref='iptPassword', v-model='password', :placeholder='$t("auth:fields.password")', @keyup.enter='login')
  14. button.button.is-blue.is-fullwidth(@click='login')
  15. span {{ $t('auth:actions.login') }}
  16. .login-frame(v-show='screen === "tfa"')
  17. .login-frame-icon
  18. svg.icons.is-48(role='img')
  19. title {{ $t('auth:tfa.title') }}
  20. use(xlink:href='#nc-key')
  21. h2 {{ $t('auth:tfa.subtitle') }}
  22. input(type='text', ref='iptTFA', v-model='securityCode', :placeholder='$t("auth:tfa.placeholder")', @keyup.enter='verifySecurityCode')
  23. button.button.is-blue.is-fullwidth(@click='verifySecurityCode')
  24. span {{ $t('auth:tfa.verifyToken') }}
  25. .login-copyright
  26. span {{ $t('footer.poweredBy') }}
  27. a(href='https://wiki.js.org', rel='external', title='Wiki.js') Wiki.js
  28. </template>
  29. <script>
  30. /* global CONSTANTS, graphQL, siteConfig */
  31. export default {
  32. name: 'login',
  33. data () {
  34. return {
  35. error: false,
  36. strategies: [],
  37. selectedStrategy: 'local',
  38. screen: 'login',
  39. username: '',
  40. password: '',
  41. securityCode: '',
  42. loginToken: '',
  43. isLoading: false
  44. }
  45. },
  46. computed: {
  47. siteTitle () {
  48. return siteConfig.title
  49. }
  50. },
  51. methods: {
  52. selectStrategy (key, useForm) {
  53. this.selectedStrategy = key
  54. this.screen = 'login'
  55. if (!useForm) {
  56. window.location.assign(siteConfig.path + 'login/' + key)
  57. } else {
  58. this.$refs.iptEmail.focus()
  59. }
  60. },
  61. refreshStrategies () {
  62. this.isLoading = true
  63. graphQL.query({
  64. query: CONSTANTS.GRAPHQL.GQL_QUERY_AUTHENTICATION,
  65. variables: {
  66. mode: 'active'
  67. }
  68. }).then(resp => {
  69. if (resp.data.authentication) {
  70. this.strategies = resp.data.authentication
  71. } else {
  72. throw new Error('No authentication providers available!')
  73. }
  74. this.isLoading = false
  75. }).catch(err => {
  76. console.error(err)
  77. this.$store.dispatch('alert', {
  78. style: 'error',
  79. icon: 'gg-warning',
  80. msg: err.message
  81. })
  82. this.isLoading = false
  83. })
  84. },
  85. login () {
  86. if (this.username.length < 2) {
  87. this.$store.dispatch('alert', {
  88. style: 'error',
  89. icon: 'gg-warning',
  90. msg: 'Enter a valid email / username.'
  91. })
  92. this.$refs.iptEmail.focus()
  93. } else if (this.password.length < 2) {
  94. this.$store.dispatch('alert', {
  95. style: 'error',
  96. icon: 'gg-warning',
  97. msg: 'Enter a valid password.'
  98. })
  99. this.$refs.iptPassword.focus()
  100. } else {
  101. this.isLoading = true
  102. graphQL.mutate({
  103. mutation: CONSTANTS.GRAPHQL.GQL_MUTATION_LOGIN,
  104. variables: {
  105. username: this.username,
  106. password: this.password,
  107. provider: this.selectedStrategy
  108. }
  109. }).then(resp => {
  110. if (resp.data.login) {
  111. let respObj = resp.data.login
  112. if (respObj.succeeded === true) {
  113. if (respObj.tfaRequired === true) {
  114. this.screen = 'tfa'
  115. this.securityCode = ''
  116. this.loginToken = respObj.tfaLoginToken
  117. this.$nextTick(() => {
  118. this.$refs.iptTFA.focus()
  119. })
  120. } else {
  121. this.$store.dispatch('alert', {
  122. style: 'success',
  123. icon: 'gg-check',
  124. msg: 'Login successful!'
  125. })
  126. }
  127. this.isLoading = false
  128. } else {
  129. throw new Error(respObj.message)
  130. }
  131. } else {
  132. throw new Error('Authentication is unavailable.')
  133. }
  134. }).catch(err => {
  135. console.error(err)
  136. this.$store.dispatch('alert', {
  137. style: 'error',
  138. icon: 'gg-warning',
  139. msg: err.message
  140. })
  141. this.isLoading = false
  142. })
  143. }
  144. },
  145. verifySecurityCode () {
  146. if (this.securityCode.length !== 6) {
  147. this.$store.dispatch('alert', {
  148. style: 'error',
  149. icon: 'gg-warning',
  150. msg: 'Enter a valid security code.'
  151. })
  152. this.$refs.iptTFA.focus()
  153. } else {
  154. this.isLoading = true
  155. graphQL.mutate({
  156. mutation: CONSTANTS.GRAPHQL.GQL_MUTATION_LOGINTFA,
  157. variables: {
  158. loginToken: this.loginToken,
  159. securityCode: this.securityCode
  160. }
  161. }).then(resp => {
  162. if (resp.data.loginTFA) {
  163. let respObj = resp.data.loginTFA
  164. if (respObj.succeeded === true) {
  165. this.$store.dispatch('alert', {
  166. style: 'success',
  167. icon: 'gg-check',
  168. msg: 'Login successful!'
  169. })
  170. this.isLoading = false
  171. } else {
  172. throw new Error(respObj.message)
  173. }
  174. } else {
  175. throw new Error('Authentication is unavailable.')
  176. }
  177. }).catch(err => {
  178. console.error(err)
  179. this.$store.dispatch('alert', {
  180. style: 'error',
  181. icon: 'gg-warning',
  182. msg: err.message
  183. })
  184. this.isLoading = false
  185. })
  186. }
  187. }
  188. },
  189. mounted () {
  190. this.$store.commit('navigator/subtitleStatic', 'Login')
  191. this.refreshStrategies()
  192. this.$refs.iptEmail.focus()
  193. }
  194. }
  195. </script>