Przeglądaj źródła

:construction: Cleaned up logic from created into methods on Auth and Verification

juan_spike
tomit4 3 lat temu
rodzic
commit
adae7a42de

+ 1
- 0
backend/lib/routes/user/signup.js Wyświetl plik

69
                     })
69
                     })
70
                     .code(201)
70
                     .code(201)
71
             } catch (err) {
71
             } catch (err) {
72
+                console.error('ERROR :=>', err)
72
                 return h
73
                 return h
73
                     .response({
74
                     .response({
74
                         ok: false,
75
                         ok: false,

+ 1
- 1
backend/lib/routes/user/validatesession.js Wyświetl plik

37
                 return {
37
                 return {
38
                     ok: false,
38
                     ok: false,
39
                     handler: pluginConfig.handlerType,
39
                     handler: pluginConfig.handlerType,
40
-                    data: err.message,
40
+                    data: { error: err.message },
41
                 }
41
                 }
42
             }
42
             }
43
         },
43
         },

+ 16
- 13
backend/lib/services/profile/index.js Wyświetl plik

139
      */
139
      */
140
     async saveResponsesCreateProfileFor(userId, responses, txn) {
140
     async saveResponsesCreateProfileFor(userId, responses, txn) {
141
         const { Profile, Response } = this.server.models()
141
         const { Profile, Response } = this.server.models()
142
-
143
-        const profile = await Profile.query(txn).insert({
144
-            user_id: userId,
145
-        })
146
-        for (const responseToSave of responses) {
147
-            const convertedResponse = this._convertResponse(responseToSave)
148
-            const responseInfo = {
149
-                profile_id: profile.id,
150
-                response_key_id: convertedResponse.response_key_id,
151
-                val: convertedResponse.val,
142
+        try {
143
+            const profile = await Profile.query(txn).insert({
144
+                user_id: userId,
145
+            })
146
+            for (const responseToSave of responses) {
147
+                const convertedResponse = this._convertResponse(responseToSave)
148
+                const responseInfo = {
149
+                    profile_id: profile.id,
150
+                    response_key_id: convertedResponse.response_key_id,
151
+                    val: convertedResponse.val,
152
+                }
153
+                await Response.query(txn).insert(responseInfo)
152
             }
154
             }
153
-            await Response.query(txn).insert(responseInfo)
155
+            //** Work around for HAPI returning profile_id as id */
156
+            return { user_id: profile.user_id, profile_id: profile.id }
157
+        } catch (err) {
158
+            throw new Error(err)
154
         }
159
         }
155
-        //** Work around for HAPI returning profile_id as id */
156
-        return { user_id: profile.user_id, profile_id: profile.id }
157
     }
160
     }
158
 
161
 
159
     /** Update responses in place
162
     /** Update responses in place

+ 42
- 23
frontend/src/components/onboarding/Auth.vue Wyświetl plik

2
 .wait-message
2
 .wait-message
3
     p.verify-message Thanks for signing up!
3
     p.verify-message Thanks for signing up!
4
     p.verify-message We'll just need you to verify your email address to continue. Please check your email!
4
     p.verify-message We'll just need you to verify your email address to continue. Please check your email!
5
-    w-button.ma1.grow(
6
-        @click='handleSubmit'
7
-    ) TEST BUTTON
8
 </template>
5
 </template>
9
 
6
 
10
 <script>
7
 <script>
17
     props: {
14
     props: {
18
         question: {
15
         question: {
19
             required: true,
16
             required: true,
20
-            type: String,
21
-            default: 'authenticated question!!',
17
+            type: Object,
18
+            default: () => {},
22
         },
19
         },
23
         answered: {
20
         answered: {
24
-            type: String,
25
-            default: '',
21
+            type: Object,
22
+            default: () => {},
26
         },
23
         },
27
         responses: {
24
         responses: {
28
-            type: String,
29
-            default: '',
25
+            type: Object,
26
+            default: () => {},
30
         },
27
         },
31
         survey: {
28
         survey: {
32
             required: true,
29
             required: true,
41
     async created() {
38
     async created() {
42
         // Establishes New User And Sends Auth Email
39
         // Establishes New User And Sends Auth Email
43
         this.authenticator = new Authenticator()
40
         this.authenticator = new Authenticator()
44
-        if (this.survey.hasMinResponsesToCreateProfile(this.responses)) {
41
+        try {
42
+            this.doesUserHaveMinResponses(this.responses)
45
             const userPass = this.responses.find(
43
             const userPass = this.responses.find(
46
                 response => response.response_key_id === 9,
44
                 response => response.response_key_id === 9,
47
             )
45
             )
48
-            const newUser = await signupUser({
46
+            const newUserId = await this.signupNewUser({
49
                 ...this.answered,
47
                 ...this.answered,
50
                 password: userPass.val,
48
                 password: userPass.val,
51
             })
49
             })
52
-            const newUserId = newUser.user_id
53
-            await createProfileForUserId(newUserId, this.responses)
54
-            const jwt = await this.authenticator.getJwt({
50
+            await this.createProfileForNewUser(newUserId, this.responses)
51
+            const sessionToken = await this.getSessionToken({
55
                 ...this.answered,
52
                 ...this.answered,
56
-                expires: 60 * 3,
57
             })
53
             })
58
-            document.cookie = `siimee_session=${jwt}; max-age=600; path=/; secure`
54
+            document.cookie = `siimee_session=${sessionToken}; max-age=600; path=/; secure`
59
             await this.authenticator.sendAuthEmail(this.answered)
55
             await this.authenticator.sendAuthEmail(this.answered)
60
-        } else {
61
-            console.error('ERROR :=>')
56
+        } catch (err) {
57
+            // TODO: redirect to an error page displaying which
58
+            // error occurred and how to reach out to staff??
59
+            console.error('ERROR :=>', err)
62
         }
60
         }
63
     },
61
     },
64
     methods: {
62
     methods: {
65
-        // TODO: remove test button above and use a watcher instead to emit this
66
-        handleSubmit() {
67
-            const payload = {
68
-                question: this.question,
63
+        doesUserHaveMinResponses(responses) {
64
+            if (!this.survey.hasMinResponsesToCreateProfile(responses))
65
+                throw new Error(
66
+                    'User has not answered minimum amount of questions to create profile',
67
+                )
68
+        },
69
+        async getSessionToken(payload) {
70
+            return await this.authenticator.getJwt({
71
+                payload,
72
+                expires: 60 * 3,
73
+            })
74
+        },
75
+        async signupNewUser(userInfo) {
76
+            const newUser = await signupUser(userInfo)
77
+            if (!newUser || newUser.error) {
78
+                throw new Error(
79
+                    'Error occured when signing up new User :=>',
80
+                    newUser.error,
81
+                )
82
+            } else return newUser.user_id
83
+        },
84
+        async createProfileForNewUser(userId, responses) {
85
+            try {
86
+                await createProfileForUserId(userId, responses)
87
+            } catch (err) {
88
+                throw new Error(err)
69
             }
89
             }
70
-            this.$emit('update-answers', payload)
71
         },
90
         },
72
     },
91
     },
73
 }
92
 }

+ 1
- 1
frontend/src/components/onboarding/QuestionResponse.vue Wyświetl plik

24
             type: Object,
24
             type: Object,
25
             required: true,
25
             required: true,
26
         },
26
         },
27
-        currentSteps: {
27
+        currentStep: {
28
             type: Number,
28
             type: Number,
29
             required: true,
29
             required: true,
30
         },
30
         },

+ 2
- 32
frontend/src/services/auth.service.js Wyświetl plik

19
         const isVerified = await db.get(`/user/verify/${hashedEmail}`)
19
         const isVerified = await db.get(`/user/verify/${hashedEmail}`)
20
         return isVerified.hashesMatch
20
         return isVerified.hashesMatch
21
     }
21
     }
22
-
23
     async getJwt(req) {
22
     async getJwt(req) {
24
-        // TODO: Clean up, should be able to use TOJ's db.post function,
25
-        // may need custon db.postWithHeaders() func or something like that...
26
-        const response = await fetch('http://localhost:3001/api/user/getjwt', {
27
-            method: 'POST',
28
-            mode: 'cors',
29
-            cache: 'no-cache',
30
-            credentials: 'omit',
31
-            headers: {
32
-                'Content-Type': 'application/json',
33
-            },
34
-            redirect: 'manual',
35
-            referrerPolicy: 'no-referrer',
36
-            body: JSON.stringify({ payload: req, expires: 600 }),
37
-        }).then(response => {
38
-            return response
39
-        })
40
-        console.log('response.headers :=>', response.headers)
41
-        // TODO: consider cleaner way to convert headers into JS Object
42
-        const getHeaders = headers => {
43
-            const headerObj = {}
44
-            const keys = headers.keys()
45
-            let header = keys.next()
46
-            while (header.value) {
47
-                headerObj[header.value] = headers.get(header.value)
48
-                header = keys.next()
49
-            }
50
-            return headerObj
51
-        }
52
-        const headerObj = getHeaders(response.headers)
53
-        return headerObj['authorization']
23
+        const responseHeaders = await db.post('/user/getjwt', req, true)
24
+        return responseHeaders
54
     }
25
     }
55
-
56
     async validateSession(sessionToken) {
26
     async validateSession(sessionToken) {
57
         const validateSession = await db.get(
27
         const validateSession = await db.get(
58
             `/user/validatesession/${sessionToken}`,
28
             `/user/validatesession/${sessionToken}`,

+ 9
- 4
frontend/src/utils/db.js Wyświetl plik

35
         }
35
         }
36
         return header
36
         return header
37
     }
37
     }
38
-    async _tryFetch({ endpoint, header }) {
38
+    async _tryFetch({ endpoint, header }, returnHeaders = false) {
39
         try {
39
         try {
40
             const res = await fetch(`${remote}${endpoint}`, header)
40
             const res = await fetch(`${remote}${endpoint}`, header)
41
             if (!res.ok) {
41
             if (!res.ok) {
42
                 throw Error(res.statusText)
42
                 throw Error(res.statusText)
43
             }
43
             }
44
-            const jsonRes = await res.json()
45
-            return jsonRes.data
44
+            if (returnHeaders) {
45
+                return res.headers
46
+            } else {
47
+                const jsonRes = await res.json()
48
+                return jsonRes.data
49
+            }
46
         } catch (error) {
50
         } catch (error) {
47
             console.error(`[API Util]: ${error}\nroute:`, endpoint)
51
             console.error(`[API Util]: ${error}\nroute:`, endpoint)
48
         }
52
         }
53
             header: this._makeHeader({ method: this._verbs.get }),
57
             header: this._makeHeader({ method: this._verbs.get }),
54
         })
58
         })
55
     }
59
     }
56
-    async post(endpoint, payload = {}) {
60
+    async post(endpoint, payload = {}, returnHeaders = false) {
57
         return await this._tryFetch({
61
         return await this._tryFetch({
58
             endpoint,
62
             endpoint,
59
             header: this._makeHeader({ method: this._verbs.post, payload }),
63
             header: this._makeHeader({ method: this._verbs.post, payload }),
64
+            returnHeaders,
60
         })
65
         })
61
     }
66
     }
62
     async patch(endpoint, payload = {}) {
67
     async patch(endpoint, payload = {}) {

+ 1
- 1
frontend/src/views/OnboardingView.vue Wyświetl plik

87
         }
87
         }
88
         // if (sessionData && !accessToken) {
88
         // if (sessionData && !accessToken) {
89
         if (sessionData) {
89
         if (sessionData) {
90
-            this.userEmail = sessionData.email
90
+            this.userEmail = sessionData.payload.email
91
             this.emailIsRegistered =
91
             this.emailIsRegistered =
92
                 await this.authenticator.checkIfEmailIsRegistered(
92
                 await this.authenticator.checkIfEmailIsRegistered(
93
                     this.userEmail,
93
                     this.userEmail,

+ 43
- 39
frontend/src/views/VerifyView.vue Wyświetl plik

11
     data: () => ({
11
     data: () => ({
12
         authenticator: {},
12
         authenticator: {},
13
         answers: {},
13
         answers: {},
14
+        hash: undefined,
15
+        sessionToken: undefined,
16
+        accessToken: undefined,
14
     }),
17
     }),
15
     async created() {
18
     async created() {
16
         this.authenticator = new Authenticator()
19
         this.authenticator = new Authenticator()
17
-        const hashEmail = this.$route.params.email
18
-
19
-        const hashesMatch = await this.authenticator.verifyAuthEmail(hashEmail)
20
-        const sessionToken = this.grabCookie('siimee_session')
21
-        // TODO: Refactor, see methods below
22
-        // if (!hashesMatch) {
23
-        //     throw new Error('no record of hashed email in cache')
24
-        //     this.$router.push('/onboarding')
25
-        // }
26
-
27
-        // TODO: THIS NEEDS TO BE SENT OVER TO verifyAuthEmail(hashEmail) in the headers
28
-        // TODO: Refactor, see methods below
29
-        // if (!sessionToken) {
30
-        //     throw new Error('token doesn't exist)
31
-        //     this.$router.push('/onboarding')
32
-        // } else {}
33
-
34
-        // TODO: Refactor to not nest, use try/catch/throw
35
-        if (sessionToken) {
36
-            const validatedSessionToken =
37
-                await this.authenticator.validateSession(sessionToken)
38
-            if (validatedSessionToken && hashesMatch) {
39
-                // TODO: What payload does accessToken need in first param to getJwt?
40
-                const accessToken = await this.authenticator.getJwt({
41
-                    ...sessionToken,
42
-                    expires: 60 * 3,
43
-                })
44
-                document.cookie = `siimee_access=${accessToken}; max-age=600; path=/; secure`
45
-                this.$router.push('/onboarding')
46
-            }
47
-        } else {
48
-            console.error('ERROR :=>')
20
+        this.hash = this.$route.params.email
21
+        this.sessionToken = this.grabCookie('siimee_session')
22
+        try {
23
+            this.isHashInUrl(this.hash)
24
+            this.doesEmailMatch(this.hash)
25
+            this.doesSessionTokenExist(this.sessionToken)
26
+            const sessionTokenIsValid = this.isSessionTokenValid(
27
+                this.sessionToken,
28
+            )
29
+            if (sessionTokenIsValid)
30
+                document.cookie = `siimee_access=${this.accessToken}; max-age=600; path=/; secure`
31
+        } catch (err) {
32
+            console.error(err)
49
         }
33
         }
34
+        this.$router.push('/onboarding')
50
     },
35
     },
51
     methods: {
36
     methods: {
52
         grabCookie(cookieKey) {
37
         grabCookie(cookieKey) {
61
                 ? cookies[`${cookieKey}`]
46
                 ? cookies[`${cookieKey}`]
62
                 : undefined
47
                 : undefined
63
         },
48
         },
64
-        async generateAccessToken() {
65
-            const accessJwt = await this.authenticator.getJwt({
66
-                ...this.answers,
49
+        async getAccessToken(payload) {
50
+            return await this.authenticator.getJwt({
51
+                payload,
67
                 expires: 60 * 3,
52
                 expires: 60 * 3,
68
             })
53
             })
69
-            return accessJwt
70
         },
54
         },
71
-        // async doesEmailMatch() {},
72
-        // async doesTokenExist() {},
73
-        // async isTokenValid() {},
55
+        isHashInUrl(hash) {
56
+            if (!hash) throw new Error('URL contains no hash!')
57
+        },
58
+        async doesEmailMatch(hashEmail) {
59
+            const hashesMatch = await this.authenticator.verifyAuthEmail(
60
+                hashEmail,
61
+            )
62
+            if (!hashesMatch) throw new Error('Hash is not in registry!')
63
+        },
64
+        async doesSessionTokenExist(sessionToken) {
65
+            if (!sessionToken)
66
+                throw new Error('sessionToken not in cookie store!')
67
+        },
68
+        async isSessionTokenValid(sessionToken) {
69
+            const sessionTokenIsValid =
70
+                await this.authenticator.validateSession(sessionToken)
71
+            if (sessionTokenIsValid.error) {
72
+                throw new Error(sessionTokenIsValid.error)
73
+            } else {
74
+                // TODO: Does accessToken need sessionToken data?
75
+                this.accessToken = await this.getAccessToken(this.sessionToken)
76
+            }
77
+        },
74
     },
78
     },
75
 }
79
 }
76
 </script>
80
 </script>

Ładowanie…
Anuluj
Zapisz