Explorar el Código

:construction: Continuing work on integrating email transac

tags/0.0.3^2
tomit4 hace 3 años
padre
commit
b522bb49bc

+ 2
- 0
backend/lib/plugins/user.js Ver fichero

@@ -13,6 +13,7 @@ const UserProfilesListRoute = require('../routes/user/list-profiles')
13 13
 const UserLoginRoute = require('../routes/user/login')
14 14
 const UserSignupRoute = require('../routes/user/signup')
15 15
 const UserEmailRoute = require('../routes/user/email.js')
16
+const UserVerifyEmailRoute = require('../routes/user/verifyemail.js')
16 17
 const UserPassword = require('../routes/user/authentication')
17 18
 
18 19
 const UserService = require('../services/user')
@@ -51,6 +52,7 @@ module.exports = {
51 52
         await server.route(UserProfileCreateRoute)
52 53
         await server.route(UserProfilesListRoute)
53 54
         await server.route(UserEmailRoute)
55
+        await server.route(UserVerifyEmailRoute)
54 56
         await server.route(UserPassword)
55 57
     },
56 58
 }

+ 0
- 2
backend/lib/routes/user/email.js Ver fichero

@@ -23,8 +23,6 @@ module.exports = {
23 23
         handler: async function (request, h) {
24 24
             const { userService } = request.server.services()
25 25
             const userEmail = request.payload.email
26
-            const userPw = request.payload.password
27
-            console.log('this.answered :=>', request.payload)
28 26
             try {
29 27
                 const emailSent = userService.emailSent(userEmail)
30 28
                 return {

+ 58
- 0
backend/lib/routes/user/verifyemail.js Ver fichero

@@ -0,0 +1,58 @@
1
+'use strict'
2
+
3
+const Joi = require('joi')
4
+
5
+const pluginConfig = {
6
+    handlerType: 'email',
7
+    docs: {
8
+        get: {
9
+            description: 'verifies confirmation email',
10
+            notes: 'Verifies the email from the stored hash',
11
+        },
12
+    },
13
+}
14
+
15
+module.exports = {
16
+    method: 'GET',
17
+    path: '/verify/{hash}',
18
+    options: {
19
+        ...pluginConfig.docs.get,
20
+        tags: ['api'],
21
+        auth: false,
22
+        cors: true,
23
+        handler: async function (request, h) {
24
+            const { userService } = request.server.services()
25
+            const hashToMatch = await userService.hashedEmail
26
+            const hash = request.params.hash
27
+            const hashesMatch = hashToMatch === hash ? true : false
28
+            try {
29
+                if (hashesMatch) {
30
+                    return {
31
+                        ok: true,
32
+                        handler: pluginConfig.handlerType,
33
+                        data: { hashesMatch: hashesMatch },
34
+                    }
35
+                }
36
+            } catch (err) {
37
+                return {
38
+                    ok: false,
39
+                    handler: pluginConfig.handlerType,
40
+                    data: {
41
+                        error: err,
42
+                    },
43
+                }
44
+            }
45
+        },
46
+        validate: {
47
+            failAction: 'log',
48
+        },
49
+        response: {
50
+            schema: Joi.object({
51
+                ok: Joi.bool(),
52
+                handler: Joi.string(),
53
+                data: Joi.object(),
54
+            }).label('verify_email_res'),
55
+            failAction: 'log',
56
+        },
57
+    },
58
+}

+ 14
- 4
backend/lib/services/user.js Ver fichero

@@ -1,5 +1,6 @@
1 1
 'use strict'
2 2
 require('dotenv').config()
3
+const crypto = require('crypto')
3 4
 const Util = require('util')
4 5
 const Jwt = require('@hapi/jwt')
5 6
 const Schmervice = require('@hapipal/schmervice')
@@ -13,6 +14,15 @@ apiKey.apiKey = process.env.BREVO_KEY
13 14
 
14 15
 const apiInstance = new SibApiV3Sdk.TransactionalEmailsApi()
15 16
 
17
+const hashEmail = async email => {
18
+    try {
19
+        return crypto.createHmac('sha256', '').update(email).digest('hex')
20
+    } catch (err) {
21
+        console.error('ERROR :=>', err)
22
+        return undefined
23
+    }
24
+}
25
+
16 26
 const hasher = async (pwd, steak) => {
17 27
     const hash = await pwd.hash(steak)
18 28
     const result = await pwd.verify(steak, hash)
@@ -52,6 +62,7 @@ module.exports = class UserService extends Schmervice.Service {
52 62
     constructor(...args) {
53 63
         super(...args)
54 64
         const pwd = new SecurePassword()
65
+        this.hashedEmail = ''
55 66
         this.pwd = {
56 67
             hash: Util.promisify(pwd.hash.bind(pwd)),
57 68
             verify: Util.promisify(pwd.verify.bind(pwd)),
@@ -245,26 +256,25 @@ module.exports = class UserService extends Schmervice.Service {
245 256
             ],
246 257
             templateId: 1,
247 258
             params: {
248
-                // TODO: create basic hashing email above and cache hash...
249
-                email: 'tobehashedemail',
259
+                // TODO: Change this in production...
260
+                link: `localhost:3000/verify/${await hashEmail(userEmail)}`,
250 261
             },
251 262
         }
252 263
 
253 264
         await apiInstance.sendTransacEmail(sendSmtpEmail).then(
254 265
             data => {
255
-                console.log('data from sendTransacEmail :=>', data)
256 266
                 return {
257 267
                     wasSuccessfull: true,
258 268
                     data: data,
259 269
                 }
260 270
             },
261 271
             error => {
262
-                console.error('ERROR :=>', error)
263 272
                 return {
264 273
                     wasSuccessfull: false,
265 274
                     error: error,
266 275
                 }
267 276
             },
268 277
         )
278
+        this.hashedEmail = hashEmail(userEmail)
269 279
     }
270 280
 }

+ 4
- 1
frontend/src/components/onboarding/Auth.vue Ver fichero

@@ -9,6 +9,7 @@
9 9
 
10 10
 <script>
11 11
 import { Authenticator } from '../../services/auth.service.js'
12
+import { signupUser } from '../../services/user.service.js'
12 13
 
13 14
 export default {
14 15
     name: 'Auth',
@@ -25,12 +26,14 @@ export default {
25 26
     },
26 27
     emits: ['update-answers'],
27 28
     data: () => ({
28
-        authenticator: false,
29
+        authenticator: {},
29 30
     }),
30 31
     created() {
31 32
         this.authenticator = new Authenticator()
32 33
         console.log('this.answered :=>', this.answered)
33 34
         this.authenticator.sendAuthEmail(this.answered)
35
+        // TODO: Consider waiting until email hash is verified...(i.e. not in created)
36
+        signupUser(this.answered)
34 37
     },
35 38
     methods: {
36 39
         // TODO: remove test button above and use a watcher instead to emit this

+ 10
- 1
frontend/src/router/index.js Ver fichero

@@ -7,6 +7,7 @@ import PairsView from '../views/PairsView.vue'
7 7
 import LoginView from '../views/LoginView.vue'
8 8
 import SurveyView from '../views/SurveyView.vue'
9 9
 import OnboardingView from '../views/OnboardingView.vue'
10
+import VerifyView from '../views/VerifyView.vue'
10 11
 import MessagesView from '../views/MessagesView.vue'
11 12
 
12 13
 const routes = [
@@ -57,12 +58,20 @@ const routes = [
57 58
         name: `SurveyView`,
58 59
         meta: { requiresAuth: true, requiresCompleteProfile: false },
59 60
     },
61
+    // TODO: remove after better implementation is found for verifying email
62
+    // hash
60 63
     {
61
-        path: `/onboarding`,
64
+        path: `/onboarding/:hash?`,
62 65
         component: OnboardingView,
63 66
         name: `OnboardingView`,
64 67
         meta: { requiresAuth: true, requiresCompleteProfile: false },
65 68
     },
69
+    {
70
+        path: `/verify/:email?`,
71
+        component: VerifyView,
72
+        name: `VerifyView`,
73
+        meta: { requiresAuth: true, requiresCompleteProfile: false },
74
+    },
66 75
     {
67 76
         path: `/login`,
68 77
         component: LoginView,

+ 4
- 1
frontend/src/services/auth.service.js Ver fichero

@@ -3,12 +3,15 @@ import { db } from '../utils/db.js'
3 3
 class Authenticator {
4 4
     constructor() {
5 5
         this.curentUser = null
6
-        this.authenticated = false
7 6
     }
8 7
     async sendAuthEmail(answered) {
9 8
         const emailWasSent = await db.post(`/user/sendemail/`, answered)
10 9
         console.log('emailwasSent :=>', emailWasSent)
11 10
     }
11
+    async verifyAuthEmail(hash) {
12
+        const isVerified = await db.get(`/user/verify/${hash}`)
13
+        return isVerified.hashesMatch
14
+    }
12 15
 }
13 16
 
14 17
 export { Authenticator }

+ 1
- 1
frontend/src/utils/lang.js Ver fichero

@@ -33,8 +33,8 @@ const auth = {
33 33
 const allSteps = {
34 34
     usa: {
35 35
         email: 'email',
36
-        password: 'password',
37 36
         name: 'name',
37
+        password: 'password',
38 38
         seeking: 'seeking',
39 39
         aspect01: 'aspect-1',
40 40
         aspect02: 'aspect-2',

+ 22
- 5
frontend/src/views/OnboardingView.vue Ver fichero

@@ -6,16 +6,17 @@ main.view--onboarding
6 6
     )
7 7
         .answers(v-for='(value, key) in answered')
8 8
             span(v-if='key == "name" && value && currentStep == 2') Hi {{ value }}!
9
-        //- h3(v-if='currentStep == 1') Welcome to Siimee Onboarding! Let's get started!
10 9
         br
11 10
         .step(v-for='(step, i) in survey.steps')
12 11
             component(
13 12
                 :is='step.component'
14 13
                 :question='step'
14
+                :answered='answered'
15 15
                 :currentStep='currentStep'
16 16
                 :surveyStepsCount='survey.steps.length'
17 17
                 @handle-submit='onSubmit'
18 18
                 @update-answers='updateAnswers'
19
+                @resume-survey='resumeSurvey'
19 20
                 v-if='step && currentStep == i'
20 21
             ) 
21 22
         .invalidResponseMessage(
@@ -32,8 +33,10 @@ main.view--onboarding
32 33
 </template>
33 34
 
34 35
 <script>
36
+import { Authenticator } from '../services/auth.service.js'
35 37
 import { surveyFactory } from '@/utils'
36 38
 import stepViews from '@/components/onboarding'
39
+import VerifyView from './VerifyView.vue'
37 40
 import SurveyCompleteView from './SurveyCompleteView.vue'
38 41
 
39 42
 // import savesurveybyprofileid - call it on submit
@@ -52,10 +55,23 @@ export default {
52 55
         survey: null,
53 56
         currentProfileId: null,
54 57
         invalidResponse: false,
58
+        // TODO: CURRENTLY WORKING ON**
59
+        isAuthenticated: false,
60
+        authenticator: {},
55 61
     }),
56 62
     async created() {
57 63
         this.survey = await surveyFactory.createSurvey()
58
-        console.log('this.survey :=>', this.survey)
64
+        this.authenticator = new Authenticator()
65
+        // TODO: Replace with better implementation, hacky workaround for now...
66
+        if (this.$route.params.hash) {
67
+            const hashEmail = this.$route.params.hash
68
+            const hashesMatch = this.authenticator.verifyAuthEmail(hashEmail)
69
+            if (hashesMatch) {
70
+                this.currentStep = 4
71
+            } else {
72
+                console.log('nope, not at all :=>')
73
+            }
74
+        }
59 75
     },
60 76
     methods: {
61 77
         onSubmit() {
@@ -64,12 +80,13 @@ export default {
64 80
         goToStep(num) {
65 81
             this.currentStep = num
66 82
         },
83
+        resumeSurvey() {
84
+            this.goToStep(4)
85
+        },
67 86
         async updateAnswers(payload) {
68 87
             // null payload is passed on splash page
69 88
             if (payload) {
70
-                // authentication achieved if payload.resume = true
71
-                if (payload.resume) this.currentStep = 3
72
-                this.invalidResponse = false
89
+                // this.invalidResponse = false
73 90
                 const k = payload.question.survey_stage
74 91
                 this.answered[k] = payload.input
75 92
 

+ 39
- 0
frontend/src/views/VerifyView.vue Ver fichero

@@ -0,0 +1,39 @@
1
+<template lang="pug">
2
+.wait-message
3
+    p.verify-message Thanks for authenticating your email {{ name }}!
4
+    p.verify-message Please give us a moment to redirect you back to the survey
5
+</template>
6
+
7
+<script>
8
+import { Authenticator } from '../services/auth.service.js'
9
+export default {
10
+    name: 'VerifyView',
11
+    emits: ['resume-survey'],
12
+    data: () => ({
13
+        authenticator: {},
14
+    }),
15
+    created() {
16
+        this.authenticator = new Authenticator()
17
+        const hashEmail = this.$route.params.email
18
+        const hashesMatch = this.authenticator.verifyAuthEmail(hashEmail)
19
+        if (hashesMatch) {
20
+            // this.$router.push(`/onboarding/${hashEmail}`)
21
+            this.$emit('resume-survey')
22
+        }
23
+        // else {
24
+        // render ERROR message above or redirect to 404 (or both?)
25
+        // }
26
+    },
27
+}
28
+</script>
29
+
30
+<style>
31
+.wait-message {
32
+    margin: 5rem auto;
33
+    text-align: center;
34
+    width: 90%;
35
+    max-width: 35rem;
36
+    font-size: 150%;
37
+    font-weight: bold;
38
+}
39
+</style>

Loading…
Cancelar
Guardar