Просмотр исходного кода

:construction: Continued work on email valdiation and saving survey state

juan_spike
tomit4 3 лет назад
Родитель
Сommit
136266b559

+ 5
- 7
backend/lib/routes/user/generatejwt.js Просмотреть файл

13
 }
13
 }
14
 
14
 
15
 module.exports = {
15
 module.exports = {
16
-    method: 'GET',
17
-    path: '/generatejwt/{hash}',
16
+    method: 'POST',
17
+    path: '/generatejwt',
18
     options: {
18
     options: {
19
         ...pluginConfig.docs.get,
19
         ...pluginConfig.docs.get,
20
         tags: ['api'],
20
         tags: ['api'],
22
         cors: true,
22
         cors: true,
23
         handler: async function (request, h) {
23
         handler: async function (request, h) {
24
             const { userService } = request.server.services()
24
             const { userService } = request.server.services()
25
-            const hash = request.params.hash
26
-            const user = {
27
-                user_email: hash,
28
-            }
29
-            const token = await userService.createToken(user)
25
+            const res = request.payload
26
+
27
+            const token = await userService.createToken(res)
30
             try {
28
             try {
31
                 return {
29
                 return {
32
                     ok: true,
30
                     ok: true,

+ 4
- 1
backend/lib/routes/user/validatejwt.js Просмотреть файл

28
                 return {
28
                 return {
29
                     ok: true,
29
                     ok: true,
30
                     handler: pluginConfig.handlerType,
30
                     handler: pluginConfig.handlerType,
31
-                    data: { isValid: jwtIsValid.isValid },
31
+                    data: {
32
+                        isValid: jwtIsValid.isValid,
33
+                        payload: jwtIsValid.payload,
34
+                    },
32
                 }
35
                 }
33
             } catch (err) {
36
             } catch (err) {
34
                 return {
37
                 return {

+ 7
- 3
backend/lib/services/user.js Просмотреть файл

63
         super(...args)
63
         super(...args)
64
         const pwd = new SecurePassword()
64
         const pwd = new SecurePassword()
65
         this.hashedEmail = ''
65
         this.hashedEmail = ''
66
+        // this.hashedEmails = []
66
         this.pwd = {
67
         this.pwd = {
67
             hash: Util.promisify(pwd.hash.bind(pwd)),
68
             hash: Util.promisify(pwd.hash.bind(pwd)),
68
             verify: Util.promisify(pwd.verify.bind(pwd)),
69
             verify: Util.promisify(pwd.verify.bind(pwd)),
197
             {
198
             {
198
                 aud: 'urn:audience:test',
199
                 aud: 'urn:audience:test',
199
                 iss: 'urn:issuer:test',
200
                 iss: 'urn:issuer:test',
200
-                email: user.user_email,
201
+                email: user.email,
202
+                name: user.name,
203
+                seeking: user.seeking,
201
             },
204
             },
202
             {
205
             {
203
                 key: key,
206
                 key: key,
218
     validateToken(token) {
221
     validateToken(token) {
219
         const key = this.server.registrations['main-app-plugin'].options.jwtKey
222
         const key = this.server.registrations['main-app-plugin'].options.jwtKey
220
         const decodedToken = Jwt.token.decode(token)
223
         const decodedToken = Jwt.token.decode(token)
224
+        console.log('decodedToken :=>', decodedToken)
221
         // NOTE: reveals email...perhaps unhashed email belongs here instead...
225
         // NOTE: reveals email...perhaps unhashed email belongs here instead...
222
-        // console.log('decodedToken :=>', decodedToken)
223
         try {
226
         try {
224
             Jwt.token.verify(decodedToken, key)
227
             Jwt.token.verify(decodedToken, key)
225
-            return { isValid: true }
228
+            return { isValid: true, payload: decodedToken.decoded.payload }
226
         } catch (err) {
229
         } catch (err) {
227
             return { isValid: false, error: err.message }
230
             return { isValid: false, error: err.message }
228
         }
231
         }
295
             },
298
             },
296
         )
299
         )
297
         this.hashedEmail = hashEmail(userEmail)
300
         this.hashedEmail = hashEmail(userEmail)
301
+        // this.hashedEmails.push(hashEmail(userEmail))
298
     }
302
     }
299
 }
303
 }

+ 15
- 10
frontend/src/components/onboarding/Auth.vue Просмотреть файл

34
             default: () => {},
34
             default: () => {},
35
         },
35
         },
36
     },
36
     },
37
-    emits: ['update-answers'],
37
+    emits: ['update-answers', 'set-pid'],
38
     data: () => ({
38
     data: () => ({
39
         authenticator: {},
39
         authenticator: {},
40
     }),
40
     }),
41
     async created() {
41
     async created() {
42
+        // establishes new user and emits it up to onboarding for login purposes
42
         this.authenticator = new Authenticator()
43
         this.authenticator = new Authenticator()
43
         if (this.survey.hasMinResponsesToCreateProfile(this.answered)) {
44
         if (this.survey.hasMinResponsesToCreateProfile(this.answered)) {
44
             const newUser = await signupUser(this.answered)
45
             const newUser = await signupUser(this.answered)
45
             const newUserId = newUser.user_id
46
             const newUserId = newUser.user_id
46
-            try {
47
-                await createProfileForUserId(newUserId, this.responses)
48
-            } catch (err) {
49
-                console.error('ERROR :=>', err)
50
-            }
51
-        }
47
+            const newProfile = await createProfileForUserId(
48
+                newUserId,
49
+                this.responses,
50
+            )
52
 
51
 
53
-        this.authenticator.sendAuthEmail(this.answered)
54
-        // TODO: Consider waiting until email hash is verified...(i.e. not in created)
55
-        signupUser(this.answered)
52
+            // sets jwt authentication cookie to be used in VerifyView.vue
53
+            // TODO: Instead of having this.answered here, simply pass profile_id?
54
+            const jwt = await this.authenticator.generateJwt(this.answered)
55
+            document.cookie = `siimee_jwt=${jwt}; path=/verify`
56
+            // this.$emit('set-pid', newProfile.profile_id)
57
+
58
+            // sends authentication email
59
+            this.authenticator.sendAuthEmail(this.answered)
60
+        }
56
     },
61
     },
57
     methods: {
62
     methods: {
58
         // TODO: remove test button above and use a watcher instead to emit this
63
         // TODO: remove test button above and use a watcher instead to emit this

+ 4
- 3
frontend/src/services/auth.service.js Просмотреть файл

13
         const isVerified = await db.get(`/user/verify/${hash}`)
13
         const isVerified = await db.get(`/user/verify/${hash}`)
14
         return isVerified.hashesMatch
14
         return isVerified.hashesMatch
15
     }
15
     }
16
-    async generateJwt(hash) {
17
-        const token = await db.get(`/user/generatejwt/${hash}`)
16
+    // TODO: this needs to generate the JWT with the RAW email
17
+    async generateJwt(res) {
18
+        const token = await db.post('/user/generatejwt', res)
18
         return token.jwt
19
         return token.jwt
19
     }
20
     }
20
     async validateJwt(jwt) {
21
     async validateJwt(jwt) {
21
         const validateJwt = await db.get(`/user/validatejwt/${jwt}`)
22
         const validateJwt = await db.get(`/user/validatejwt/${jwt}`)
22
-        return validateJwt.isValid
23
+        return validateJwt
23
     }
24
     }
24
 }
25
 }
25
 
26
 

+ 48
- 6
frontend/src/views/OnboardingView.vue Просмотреть файл

15
                 :responses='responses'
15
                 :responses='responses'
16
                 :survey='survey'
16
                 :survey='survey'
17
                 :currentStep='currentStep'
17
                 :currentStep='currentStep'
18
+                :jwt='jwt'
18
                 :surveyStepsCount='survey.steps.length'
19
                 :surveyStepsCount='survey.steps.length'
19
                 @handle-submit='onSubmit'
20
                 @handle-submit='onSubmit'
20
                 @update-answers='updateAnswers'
21
                 @update-answers='updateAnswers'
22
+                @set-pid='setPid'
21
                 v-if='step && currentStep == i'
23
                 v-if='step && currentStep == i'
22
             ) 
24
             ) 
23
         .invalidResponseMessage(
25
         .invalidResponseMessage(
36
 <script>
38
 <script>
37
 import { Authenticator } from '../services/auth.service.js'
39
 import { Authenticator } from '../services/auth.service.js'
38
 import { surveyFactory } from '@/utils'
40
 import { surveyFactory } from '@/utils'
41
+import { currentProfile } from '../services/'
39
 import stepViews from '@/components/onboarding'
42
 import stepViews from '@/components/onboarding'
40
 import SurveyCompleteView from './SurveyCompleteView.vue'
43
 import SurveyCompleteView from './SurveyCompleteView.vue'
41
 
44
 
59
         authenticator: {},
62
         authenticator: {},
60
         jwt: '',
63
         jwt: '',
61
     }),
64
     }),
65
+    computed: {
66
+        // NOTE: perhaps start this off as returning nothing
67
+        // and then add currentProfile in created()?
68
+        profile: () => currentProfile,
69
+    },
62
     async created() {
70
     async created() {
71
+        // console.log('this.profile.id :=>', this.profile.id)
63
         if (document.cookie.length) {
72
         if (document.cookie.length) {
64
-            const siimeeToken = this.grabToken(document.cookie)
73
+            // TODO: Remove this this.answered section when:
74
+            // SurveyCompleteView calls all responses from db
75
+            const siimeeAnswers = JSON.parse(
76
+                this.grabCookie(document.cookie, 'siimee_answered'),
77
+            )
78
+            this.answered = {
79
+                name: siimeeAnswers.name,
80
+                email: siimeeAnswers.email,
81
+                seeking: siimeeAnswers.seeking,
82
+            }
83
+            // TODO: Instead, login using siimee_profile_id from cookie
84
+            const siimeeToken = this.grabCookie(document.cookie, 'siimee_jwt')
65
             this.jwt = siimeeToken ? siimeeToken : ''
85
             this.jwt = siimeeToken ? siimeeToken : ''
66
         }
86
         }
87
+
67
         this.survey = await surveyFactory.createSurvey()
88
         this.survey = await surveyFactory.createSurvey()
68
         this.authenticator = new Authenticator()
89
         this.authenticator = new Authenticator()
69
         if (this.jwt.length) {
90
         if (this.jwt.length) {
70
-            const jwtStillValid = await this.authenticator.validateJwt(this.jwt)
71
-            if (jwtStillValid) {
91
+            // TODO: remove once currentProfile is established and user is logged in...
92
+            const jwt = await this.authenticator.validateJwt(this.jwt)
93
+            if (jwt.isValid) {
94
+                // grab profileId from jwt payload and login here
95
+                // use this profile to grab all responses in
96
+                // SurveyCompleteView.vue
72
                 this.goToStep(6)
97
                 this.goToStep(6)
73
             } else {
98
             } else {
74
                 this.goToStep(0)
99
                 this.goToStep(0)
83
         goToStep(num) {
108
         goToStep(num) {
84
             this.currentStep = num
109
             this.currentStep = num
85
         },
110
         },
86
-        grabToken(cookieString) {
111
+        grabCookie(cookieString, cookieKey) {
87
             const cookies = cookieString.split('; ').reduce((prev, current) => {
112
             const cookies = cookieString.split('; ').reduce((prev, current) => {
88
                 const [name, ...value] = current.split('=')
113
                 const [name, ...value] = current.split('=')
89
                 prev[name] = value.join('=')
114
                 prev[name] = value.join('=')
90
                 return prev
115
                 return prev
91
             }, {})
116
             }, {})
92
-            return 'siimee_jwt' in cookies ? cookies['siimee_jwt'] : undefined
117
+            return cookieKey in cookies ? cookies[`${cookieKey}`] : undefined
93
         },
118
         },
94
         async updateAnswers(payload) {
119
         async updateAnswers(payload) {
95
             // null payload is passed on splash page
120
             // null payload is passed on splash page
102
                     this.invalidResponse = true
127
                     this.invalidResponse = true
103
                     return
128
                     return
104
                 }
129
                 }
105
-                //
130
+
106
                 // once validated, don't log password in answered object
131
                 // once validated, don't log password in answered object
107
                 // this.answered[k] = k === 'password' ? undefined : payload.input
132
                 // this.answered[k] = k === 'password' ? undefined : payload.input
108
 
133
 
128
                 this.goToStep(this.currentStep + 1)
153
                 this.goToStep(this.currentStep + 1)
129
             }
154
             }
130
         },
155
         },
156
+        // NOTE: Brought in from App.vue, might not be necessary...
157
+        // Allows for login after initial email sign up is set
158
+        async setPid(profileId) {
159
+            if (currentProfile.isLoggedIn) {
160
+                currentProfile.logout()
161
+            }
162
+            // ERROR: this._profile is undefinedin login service
163
+            this.profile.id = await currentProfile.login(
164
+                profileId,
165
+                this.$waveui.notify,
166
+            )
167
+            console.log('---')
168
+
169
+            // Change if survey isn't complete...
170
+            // const toRoute = { name: 'HomeView' }
171
+            // this.$router.push(toRoute)
172
+        },
131
     },
173
     },
132
 }
174
 }
133
 </script>
175
 </script>

+ 24
- 5
frontend/src/views/VerifyView.vue Просмотреть файл

1
 <template lang="pug">
1
 <template lang="pug">
2
 .wait-message
2
 .wait-message
3
-    p.verify-message Thanks for authenticating your email {{ name }}!
3
+    p.verify-message Thanks for authenticating your email!
4
     p.verify-message Please give us a moment to redirect you back to the survey
4
     p.verify-message Please give us a moment to redirect you back to the survey
5
 </template>
5
 </template>
6
 
6
 
15
         this.authenticator = new Authenticator()
15
         this.authenticator = new Authenticator()
16
         const hashEmail = this.$route.params.email
16
         const hashEmail = this.$route.params.email
17
         const hashesMatch = await this.authenticator.verifyAuthEmail(hashEmail)
17
         const hashesMatch = await this.authenticator.verifyAuthEmail(hashEmail)
18
-        if (hashesMatch) {
19
-            const jwt = await this.authenticator.generateJwt(hashEmail)
20
-            document.cookie = `siimee_jwt=${jwt}; path=/onboarding`
18
+        const siimeeToken = this.grabToken(document.cookie)
19
+
20
+        // TODO: remove once currentProfile is established and user is logged in...
21
+        // NOTE: another siimee_jwt cookie for onboarding path instead of verify
22
+        document.cookie = `siimee_jwt=${siimeeToken}; path=/onboarding`
23
+
24
+        const jwt = await this.authenticator.validateJwt(siimeeToken)
25
+
26
+        if (jwt.isValid && hashesMatch) {
27
+            // TODO: set jwt.payload.profile_id as siimee_profile_id
28
+            // remove answers, will query db at SurveyCompleteView.vue
29
+            const siimeeAnswers = JSON.stringify(jwt.payload)
30
+            document.cookie = `siimee_answered=${siimeeAnswers} ; path=/onboarding`
21
             this.$router.push('/onboarding')
31
             this.$router.push('/onboarding')
22
         }
32
         }
23
         // else {
33
         // else {
24
         // render ERROR message above or redirect to 404 (or both?)
34
         // render ERROR message above or redirect to 404 (or both?)
25
-        // }
35
+    },
36
+    methods: {
37
+        grabToken(cookieString) {
38
+            const cookies = cookieString.split('; ').reduce((prev, current) => {
39
+                const [name, ...value] = current.split('=')
40
+                prev[name] = value.join('=')
41
+                return prev
42
+            }, {})
43
+            return 'siimee_jwt' in cookies ? cookies['siimee_jwt'] : undefined
44
+        },
26
     },
45
     },
27
 }
46
 }
28
 </script>
47
 </script>

Загрузка…
Отмена
Сохранить