This is an automated email from the ASF dual-hosted git repository.

pearl11594 pushed a commit to branch 2fa-ui
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/2fa-ui by this push:
     new 936fe565c0c register 2fa for user
936fe565c0c is described below

commit 936fe565c0c25e3034ae3cd410ce8e21478d165e
Author: Pearl Dsilva <[email protected]>
AuthorDate: Tue Oct 18 16:25:46 2022 +0530

    register 2fa for user
---
 ui/package-lock.json                       | 20 +++++++
 ui/package.json                            |  4 +-
 ui/public/locales/en.json                  |  7 +++
 ui/src/config/section/user.js              |  9 +++
 ui/src/core/lazy_lib/icons_use.js          |  2 +
 ui/src/store/modules/user.js               |  3 +
 ui/src/views/dashboard/TwoFa.vue           |  3 +-
 ui/src/views/iam/RegisterTwoFactorAuth.vue | 94 ++++++++++++++++++++++++++++++
 8 files changed, 140 insertions(+), 2 deletions(-)

diff --git a/ui/package-lock.json b/ui/package-lock.json
index 8ae7034a544..6ae1e0367d5 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -18596,6 +18596,11 @@
       "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
       "dev": true
     },
+    "qrious": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/qrious/-/qrious-4.0.2.tgz";,
+      "integrity": 
"sha512-xWPJIrK1zu5Ypn898fBp8RHkT/9ibquV2Kv24S/JY9VYEhMBMKur1gHVsOiNUh7PHP9uCgejjpZUHUIXXKoU/g=="
+    },
     "qs": {
       "version": "6.5.3",
       "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz";,
@@ -22530,6 +22535,21 @@
         "loader-utils": "^2.0.0"
       }
     },
+    "vue-qrious": {
+      "version": "3.1.0",
+      "resolved": 
"https://registry.npmjs.org/vue-qrious/-/vue-qrious-3.1.0.tgz";,
+      "integrity": 
"sha512-qC5jw94b/VbUHFxYfumwqhSXKBJNEmaimhpwEmudqOiORMd5yPCFn/mPInnP5nWobvhvcV+S+U3Ger6w2dLyfQ==",
+      "requires": {
+        "tslib": "^2.4.0"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "2.4.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz";,
+          "integrity": 
"sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+        }
+      }
+    },
     "vue-router": {
       "version": "4.0.14",
       "resolved": 
"https://registry.npmjs.org/vue-router/-/vue-router-4.0.14.tgz";,
diff --git a/ui/package.json b/ui/package.json
index e27ec671fa1..31ad8bd9d3e 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -53,16 +53,18 @@
     "moment": "^2.26.0",
     "npm-check-updates": "^6.0.1",
     "nprogress": "^0.2.0",
+    "qrious": "^4.0.2",
     "vue": "^3.2.31",
     "vue-chartjs": "^4.0.7",
     "vue-clipboard2": "^0.3.1",
     "vue-cropper": "^1.0.2",
     "vue-i18n": "^9.1.6",
     "vue-loader": "^16.2.0",
+    "vue-qrious": "^3.1.0",
     "vue-router": "^4.0.14",
+    "vue-uuid": "^3.0.0",
     "vue-web-storage": "^6.1.0",
     "vue3-clipboard": "^1.0.0",
-    "vue-uuid": "^3.0.0",
     "vuedraggable": "^4.0.3",
     "vuex": "^4.0.0-0"
   },
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index 06ba0e602ae..4a23ce4adc0 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -136,6 +136,7 @@
 "label.action.reboot.systemvm": "Reboot system VM",
 "label.action.recover.volume": "Recover volume",
 "label.action.recurring.snapshot": "Recurring snapshots",
+"label.action.register.2FA.user.auth": "Register user for 2FA authentication",
 "label.action.register.iso": "Register ISO",
 "label.action.register.template": "Register template from URL",
 "label.action.release.ip": "Release IP",
@@ -409,6 +410,7 @@
 "label.compute.offerings": "Compute offerings",
 "label.configuration": "Configuration",
 "label.configure": "Configure",
+"label.configure.app": "Configure the App",
 "label.configure.ldap": "Configure LDAP",
 "label.configure.ovs": "Configure Ovs",
 "label.configure.sticky.policy": "Configure sticky policy",
@@ -678,6 +680,7 @@
 "label.endipv6": "IPv6 end IP",
 "label.endpoint": "Endpoint",
 "label.endport": "End port",
+"label.enter.code": "Enter 6-digit code",
 "label.enter.token": "Enter token",
 "label.error": "Error",
 "label.error.caught": "Error caught",
@@ -1749,6 +1752,7 @@
 "label.transportzoneuuid": "Transport zone UUID",
 "label.try.again": "Try again",
 "label.tuesday": "Tuesday",
+"label.two.factor.secret": "Your Two-factor secret",
 "label.type": "Type",
 "label.type.id": "Type ID",
 "label.ucs": "UCS",
@@ -2601,6 +2605,9 @@
 "message.tooltip.reserved.system.netmask": "The network prefix that defines 
the pod subnet. Uses CIDR notation.",
 "message.traffic.type.to.basic.zone": "traffic type to basic zone",
 "message.two.fa.auth": "Open the two-factor authentication app on your mobile 
device to view your authentication code",
+"message.two.fa.auth.register.account": "Open the two-factor authentication 
application and scan the QR code add the user account",
+"message.two.fa.static.pin.part1": "If you can't scan the QR code, ",
+"message.two.fa.static.pin.part2": "enter this text code",
 "message.update.ipaddress.processing": "Updating IP Address...",
 "message.update.resource.count": "Please confirm that you want to update 
resource counts for this account.",
 "message.update.resource.count.domain": "Please confirm that you want to 
update resource counts for this domain.",
diff --git a/ui/src/config/section/user.js b/ui/src/config/section/user.js
index e17e998179e..5a298134839 100644
--- a/ui/src/config/section/user.js
+++ b/ui/src/config/section/user.js
@@ -106,6 +106,15 @@ export default {
       },
       component: shallowRef(defineAsyncComponent(() => 
import('@/views/iam/ConfigureSamlSsoAuth.vue')))
     },
+    {
+      // update API name
+      api: 'updateUser',
+      icon: 'scan-outlined',
+      label: 'label.action.register.2FA.user.auth',
+      dataView: true,
+      popup: true,
+      component: shallowRef(defineAsyncComponent(() => 
import('@/views/iam/RegisterTwoFactorAuth.vue')))
+    },
     {
       api: 'deleteUser',
       icon: 'delete-outlined',
diff --git a/ui/src/core/lazy_lib/icons_use.js 
b/ui/src/core/lazy_lib/icons_use.js
index a5db66bf870..b1bcc86cdd0 100644
--- a/ui/src/core/lazy_lib/icons_use.js
+++ b/ui/src/core/lazy_lib/icons_use.js
@@ -138,6 +138,7 @@ import {
   SaveOutlined,
   ScheduleOutlined,
   ScissorOutlined,
+  ScanOutlined,
   SearchOutlined,
   SettingOutlined,
   ShareAltOutlined,
@@ -285,6 +286,7 @@ export default {
     app.component('SafetyOutlined', SafetyOutlined)
     app.component('SaveOutlined', SaveOutlined)
     app.component('ScheduleOutlined', ScheduleOutlined)
+    app.component('ScanOutlined', ScanOutlined)
     app.component('ScissorOutlined', ScissorOutlined)
     app.component('SearchOutlined', SearchOutlined)
     app.component('SettingOutlined', SettingOutlined)
diff --git a/ui/src/store/modules/user.js b/ui/src/store/modules/user.js
index 859f5e01d0a..262ac7676aa 100644
--- a/ui/src/store/modules/user.js
+++ b/ui/src/store/modules/user.js
@@ -393,6 +393,9 @@ const user = {
     },
     SetDarkMode ({ commit }, darkMode) {
       commit('SET_DARK_MODE', darkMode)
+    },
+    SetLoginFlag ({ commit }, loggedIn) {
+      commit('SET_LOGIN_FLAG', loggedIn)
     }
   }
 }
diff --git a/ui/src/views/dashboard/TwoFa.vue b/ui/src/views/dashboard/TwoFa.vue
index 19924c03747..31fd375fe4e 100644
--- a/ui/src/views/dashboard/TwoFa.vue
+++ b/ui/src/views/dashboard/TwoFa.vue
@@ -78,7 +78,8 @@ export default {
       })
     },
     handleSubmit () {
-    // Add logic to set loginFlag to true
+      // Add logic to set loginFlag to true
+      this.$store.dispatch('SetLoginFlag', true)
     }
   }
 }
diff --git a/ui/src/views/iam/RegisterTwoFactorAuth.vue 
b/ui/src/views/iam/RegisterTwoFactorAuth.vue
new file mode 100644
index 00000000000..c9378772fb4
--- /dev/null
+++ b/ui/src/views/iam/RegisterTwoFactorAuth.vue
@@ -0,0 +1,94 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+<template>
+  <h3> {{ $t('label.configure.app') }} </h3>
+  <div> {{ $t('message.two.fa.auth.register.account') }} </div>
+  <vue-qrious
+    class="center-align"
+    :value="resource.id"
+    @change="onDataUrlChange"
+  />
+  <br />
+  <div> {{ $t('message.two.fa.static.pin.part1') }} <a 
@click="generateStaticPin"> {{ $t('message.two.fa.static.pin.part2') 
}}</a></div>
+  <br />
+  <h3> {{ $t('label.enter.code') }} </h3>
+  <a-form @finish="submitPin" v-ctrl-enter="submitPin" class="container">
+    <a-input v-model:value="pin" />
+    <div :span="24">
+      <a-button ref="submit" type="primary" @click="submitPin">{{ 
$t('label.ok') }}</a-button>
+    </div>
+  </a-form>
+  <a-modal
+    v-if="showPin"
+    :visible="showPin"
+    :title="$t('label.two.factor.secret')"
+    :closable="true"
+    :footer="null"
+    @cancel="onCloseModal"
+    centered
+    width="450px">
+    <div> {{ pin }} </div>
+  </a-modal>
+</template>
+<script>
+import VueQrious from 'vue-qrious'
+export default {
+  name: 'RegisterTwoFactorAuth',
+  props: {
+    resource: {
+      type: Object,
+      required: true
+    }
+  },
+  components: {
+    VueQrious
+  },
+  data () {
+    return {
+      dataUrl: '',
+      pin: '',
+      showPin: false
+    }
+  },
+  methods: {
+    onDataUrlChange (dataUrl) {
+      this.dataUrl = dataUrl
+    },
+    submitPin () {
+      // call api
+    },
+    generateStaticPin () {
+      this.pin = Math.floor(100000 + Math.random() * 900000)
+      this.showPin = true
+    },
+    onCloseModal () {
+      this.showPin = false
+    }
+  }
+}
+</script>
+<style scoped>
+  .center-align {
+    display: block;
+    margin-left: auto;
+    margin-right: auto;
+  }
+  .container {
+    display: flex;
+  }
+</style>

Reply via email to