1
00:00:02,020 --> 00:00:03,840
So this product management part

2
00:00:03,840 --> 00:00:05,440
is pretty much finished.

3
00:00:05,440 --> 00:00:08,650
There are just some minor adjustments

4
00:00:08,650 --> 00:00:10,780
or notes that I want to make.

5
00:00:10,780 --> 00:00:13,150
Let's say we add a new product again,

6
00:00:13,150 --> 00:00:14,313
the keyboard again.

7
00:00:15,220 --> 00:00:16,910
If we do that,

8
00:00:16,910 --> 00:00:19,190
we could theoretically

9
00:00:19,190 --> 00:00:22,490
actually disable validation here in the browser,

10
00:00:22,490 --> 00:00:24,580
with the dev tools, for example,

11
00:00:24,580 --> 00:00:27,630
and actually submit an invalid product.

12
00:00:27,630 --> 00:00:28,810
I'm not going to do it here,

13
00:00:28,810 --> 00:00:30,330
but this would work

14
00:00:30,330 --> 00:00:32,479
because for the product management,

15
00:00:32,479 --> 00:00:35,340
if you have a look at our backend code

16
00:00:35,340 --> 00:00:36,890
in the admin controller,

17
00:00:36,890 --> 00:00:38,870
we added no validation.

18
00:00:38,870 --> 00:00:41,230
I'm not checking the user input.

19
00:00:41,230 --> 00:00:42,650
And I did mention earlier

20
00:00:42,650 --> 00:00:44,780
that you should always validate

21
00:00:44,780 --> 00:00:47,490
the user input on the server side.

22
00:00:47,490 --> 00:00:51,630
Now feel free to add this server side validation

23
00:00:51,630 --> 00:00:53,910
and maybe flashing error messages

24
00:00:53,910 --> 00:00:57,000
onto sessions as extra practice.

25
00:00:57,000 --> 00:00:59,350
I'm not doing it here because

26
00:00:59,350 --> 00:01:02,480
this admin area is in the end for myself.

27
00:01:02,480 --> 00:01:04,190
I'm building my own website here

28
00:01:04,190 --> 00:01:07,380
and I have no intention of hacking my own website.

29
00:01:07,380 --> 00:01:09,950
And since this is in the administration area,

30
00:01:09,950 --> 00:01:13,060
no other visitors will use that.

31
00:01:13,060 --> 00:01:16,480
And therefore, I can safely not have

32
00:01:16,480 --> 00:01:18,320
any server side validation

33
00:01:18,320 --> 00:01:21,470
since I won't hack myself.

34
00:01:21,470 --> 00:01:24,450
Now, you still might want to add it as extra practice,

35
00:01:24,450 --> 00:01:26,920
but that's why I didn't add it here.

36
00:01:26,920 --> 00:01:28,940
And instead I just well,

37
00:01:28,940 --> 00:01:31,023
rely on the front end validation.

38
00:01:32,740 --> 00:01:35,010
Now, another note that I want to make

39
00:01:35,010 --> 00:01:37,870
is related to 404 errors.

40
00:01:37,870 --> 00:01:41,750
If I do click view and edit, I load this product.

41
00:01:41,750 --> 00:01:44,740
If I enter a wrong ID here,

42
00:01:44,740 --> 00:01:46,810
I actually get this error though.

43
00:01:46,810 --> 00:01:49,610
The default error handling page.

44
00:01:49,610 --> 00:01:52,230
That's better than the server crashing,

45
00:01:52,230 --> 00:01:55,520
but still it's not what I want to do here.

46
00:01:55,520 --> 00:02:00,520
And you might recall that in my admin controller,

47
00:02:00,910 --> 00:02:03,170
no, in my product model,

48
00:02:03,170 --> 00:02:07,360
I actually did add this extra 404 code

49
00:02:07,360 --> 00:02:09,610
to some error objects

50
00:02:09,610 --> 00:02:12,313
for the case that loading an item failed.

51
00:02:13,740 --> 00:02:16,850
Now, I added this arbitrary code property

52
00:02:16,850 --> 00:02:18,280
to the error object

53
00:02:18,280 --> 00:02:20,460
because it's this error object,

54
00:02:20,460 --> 00:02:23,600
which I'm forwarding inside of my admin controller

55
00:02:23,600 --> 00:02:25,970
with help of the next function.

56
00:02:25,970 --> 00:02:28,130
And it's therefore this error object

57
00:02:28,130 --> 00:02:32,280
that reaches my default error handler in app.js.

58
00:02:32,280 --> 00:02:34,260
This error handler middleware,

59
00:02:34,260 --> 00:02:36,763
which we defined in the middlewares folder.

60
00:02:37,920 --> 00:02:41,670
There, we got this error-handler.js file.

61
00:02:41,670 --> 00:02:44,653
In there, I log the error and then I always send back

62
00:02:44,653 --> 00:02:47,610
this 500 error page.

63
00:02:47,610 --> 00:02:50,010
Now, since we know that for some errors,

64
00:02:50,010 --> 00:02:52,110
we'll have that code property

65
00:02:52,110 --> 00:02:54,140
and then that code property

66
00:02:54,140 --> 00:02:57,250
might hold a value of 404,

67
00:02:57,250 --> 00:02:59,310
we can actually add a if-check here

68
00:02:59,310 --> 00:03:03,477
and check if error.code is equal to 404.

69
00:03:05,230 --> 00:03:06,910
And if that's the case,

70
00:03:06,910 --> 00:03:10,130
we might want to return a response,

71
00:03:10,130 --> 00:03:13,170
where the status code is set to 404,

72
00:03:13,170 --> 00:03:16,920
and where we render shared 404.

73
00:03:16,920 --> 00:03:19,470
So a different error page.

74
00:03:19,470 --> 00:03:22,740
And I return here so that this code isn't executed

75
00:03:22,740 --> 00:03:24,743
if we made it into this if-block.

76
00:03:25,790 --> 00:03:28,580
For most errors, this will not be the case.

77
00:03:28,580 --> 00:03:29,413
And that's okay.

78
00:03:29,413 --> 00:03:32,790
We have the default error page for those cases.

79
00:03:32,790 --> 00:03:35,817
But for some errors, we do have a code of 404,

80
00:03:35,817 --> 00:03:37,713
and we can then handle it like this.

81
00:03:38,720 --> 00:03:41,250
So with that, back in our templates,

82
00:03:41,250 --> 00:03:43,000
in the shared templates,

83
00:03:43,000 --> 00:03:46,140
we can duplicate the 500.ejs file

84
00:03:46,140 --> 00:03:49,150
and add a 404.ejs file.

85
00:03:49,150 --> 00:03:50,580
And then change the text here

86
00:03:50,580 --> 00:03:53,900
to "Could not find the resource,"

87
00:03:53,900 --> 00:03:55,490
and you can of course change the content

88
00:03:55,490 --> 00:03:56,960
however you want.

89
00:03:56,960 --> 00:03:58,907
Here I'll say, "Unfortunately,

90
00:03:58,907 --> 00:04:03,100
"we could not find the requested resource,"

91
00:04:03,100 --> 00:04:03,933
like this.

92
00:04:06,930 --> 00:04:08,660
Now, with that done,

93
00:04:08,660 --> 00:04:12,540
if I reload this page with the incorrect ID,

94
00:04:12,540 --> 00:04:14,663
I get the 404 page instead.

95
00:04:15,650 --> 00:04:17,500
And that's simply a little improvement.

96
00:04:17,500 --> 00:04:19,339
Of course, we can still load products

97
00:04:19,339 --> 00:04:20,833
with a correct ID though.

98
00:04:21,779 --> 00:04:23,350
Now, as a last step,

99
00:04:23,350 --> 00:04:26,470
I want to work on a huge security

100
00:04:26,470 --> 00:04:30,580
or access issue that I have on this website.

101
00:04:30,580 --> 00:04:32,980
I'm currently logged in as an admin.

102
00:04:32,980 --> 00:04:35,290
Now let's see if I log out here

103
00:04:35,290 --> 00:04:39,430
and I then try to access admin/products.

104
00:04:39,430 --> 00:04:41,590
Oh, that works.

105
00:04:41,590 --> 00:04:44,043
Clicking delete also works.

106
00:04:44,930 --> 00:04:47,470
And that should not happen.

107
00:04:47,470 --> 00:04:49,690
Now, why does this all work?

108
00:04:49,690 --> 00:04:51,080
The reason for that is simple.

109
00:04:51,080 --> 00:04:55,030
I'm not protecting these admin routes at all.

110
00:04:55,030 --> 00:04:57,640
These are regular routes defined here

111
00:04:57,640 --> 00:04:59,840
in the admin.routes.js file,

112
00:04:59,840 --> 00:05:01,730
and I load them in app.js

113
00:05:01,730 --> 00:05:03,860
without any extra protection.

114
00:05:03,860 --> 00:05:06,593
If you know the path, you can send the request.

115
00:05:07,490 --> 00:05:11,400
Of course, we do have login built into our website,

116
00:05:11,400 --> 00:05:13,270
but we're not using the information

117
00:05:13,270 --> 00:05:15,640
whenever a user is logged in or not

118
00:05:15,640 --> 00:05:18,750
if we ignore the navigation bar.

119
00:05:18,750 --> 00:05:20,420
Now that's the first step.

120
00:05:20,420 --> 00:05:22,580
It ensures that you don't see options,

121
00:05:22,580 --> 00:05:24,550
which you shouldn't be able to access,

122
00:05:24,550 --> 00:05:28,000
but you can still enter paths and send requests manually

123
00:05:28,000 --> 00:05:31,000
if you play around with the site a bit.

124
00:05:31,000 --> 00:05:33,520
And that's of course a huge security issue

125
00:05:33,520 --> 00:05:35,260
for our website

126
00:05:35,260 --> 00:05:37,223
and for the data of our website.

127
00:05:38,100 --> 00:05:39,860
So, to protect against that,

128
00:05:39,860 --> 00:05:41,660
I want to make sure that requests

129
00:05:41,660 --> 00:05:45,570
to /admin routes, to all the routes in there,

130
00:05:45,570 --> 00:05:48,543
can only be sent if you are an admin.

131
00:05:49,690 --> 00:05:53,810
This means that I will add a new middleware,

132
00:05:53,810 --> 00:05:56,190
which I want to run before requests

133
00:05:56,190 --> 00:05:58,200
reach these admin routes.

134
00:05:58,200 --> 00:05:59,033
Now for this,

135
00:05:59,033 --> 00:06:00,930
I'll go to the middlewares folder

136
00:06:00,930 --> 00:06:02,360
and add a new file in there,

137
00:06:02,360 --> 00:06:06,830
which I'll name protect-routes.js.

138
00:06:06,830 --> 00:06:08,810
And in this file, we can add a function

139
00:06:08,810 --> 00:06:12,010
which can also be named protectRoutes,

140
00:06:12,010 --> 00:06:13,660
which will be a middleware function,

141
00:06:13,660 --> 00:06:15,670
and which therefore gets a request, a response,

142
00:06:15,670 --> 00:06:17,733
and this next function.

143
00:06:18,570 --> 00:06:20,930
And which I want to make available outside of this file,

144
00:06:20,930 --> 00:06:23,470
so I will export it like this.

145
00:06:23,470 --> 00:06:25,300
And then in this function,

146
00:06:25,300 --> 00:06:28,020
I want to do two things.

147
00:06:28,020 --> 00:06:28,853
First of all,

148
00:06:28,853 --> 00:06:32,410
I want to check if you're maybe not authenticated

149
00:06:32,410 --> 00:06:33,790
and for this, I can check

150
00:06:33,790 --> 00:06:37,240
if res.locals has a specific value,

151
00:06:37,240 --> 00:06:39,790
which I do set in check-auth.

152
00:06:39,790 --> 00:06:42,820
Check-auth is also one of our middleware functions.

153
00:06:42,820 --> 00:06:45,450
And there I just look into the incoming request

154
00:06:45,450 --> 00:06:47,500
and see if this user has a session

155
00:06:47,500 --> 00:06:51,420
that identifies him or her as logged in.

156
00:06:51,420 --> 00:06:54,580
And if that's the case, I set isAuth to true.

157
00:06:54,580 --> 00:06:56,860
And I also check, or I set if the user

158
00:06:56,860 --> 00:06:58,150
is an admin.

159
00:06:58,150 --> 00:06:59,810
And that's based on data

160
00:06:59,810 --> 00:07:01,593
that's also stored in the session.

161
00:07:02,630 --> 00:07:05,070
Now we can use isAuth and isAdmin

162
00:07:05,070 --> 00:07:08,010
in protect routes to now deny access,

163
00:07:08,010 --> 00:07:11,610
because checkAuthStatus does not deny any access.

164
00:07:11,610 --> 00:07:13,510
Here we just extract data

165
00:07:13,510 --> 00:07:14,923
from the incoming request.

166
00:07:15,890 --> 00:07:17,400
But now in protect Routes,

167
00:07:17,400 --> 00:07:20,141
I can use res.locals isAuth and isAdmin

168
00:07:20,141 --> 00:07:22,903
to deny access to certain paths.

169
00:07:23,760 --> 00:07:27,010
So here I check if not res.locals.isAuth,

170
00:07:27,010 --> 00:07:29,090
which means you're not authenticated.

171
00:07:29,090 --> 00:07:30,490
And in that case,

172
00:07:30,490 --> 00:07:32,670
if that middleware becomes active,

173
00:07:32,670 --> 00:07:35,110
which it will only for certain routes,

174
00:07:35,110 --> 00:07:37,040
I want to deny access.

175
00:07:37,040 --> 00:07:40,190
So then I'll simply return

176
00:07:40,190 --> 00:07:43,550
an error or let's say a redirect

177
00:07:44,520 --> 00:07:46,840
to a 401 route,

178
00:07:46,840 --> 00:07:48,273
which we have yet to add.

179
00:07:49,497 --> 00:07:51,610
401 because that will be the status code,

180
00:07:51,610 --> 00:07:54,380
which is typically used for telling a user

181
00:07:54,380 --> 00:07:56,403
that he or she is not authenticated.

182
00:07:57,440 --> 00:07:59,370
Now, of course you might be authenticated

183
00:07:59,370 --> 00:08:01,300
and still not be an admin.

184
00:08:01,300 --> 00:08:03,410
For some routes, that's enough.

185
00:08:03,410 --> 00:08:05,380
A lot of routes will be accessible

186
00:08:05,380 --> 00:08:07,810
to regular authenticated users.

187
00:08:07,810 --> 00:08:09,280
But for the admin routes,

188
00:08:09,280 --> 00:08:10,943
you also need to be an admin.

189
00:08:11,790 --> 00:08:15,470
Therefore I'll check if the request path,

190
00:08:15,470 --> 00:08:18,830
so the path of the request you sent us,

191
00:08:18,830 --> 00:08:22,353
actually starts with /admin.

192
00:08:23,840 --> 00:08:25,680
And startsWith is a built-in method,

193
00:08:25,680 --> 00:08:28,940
which you can call on strings in JavaScript,

194
00:08:28,940 --> 00:08:31,830
and request path yields a string.

195
00:08:31,830 --> 00:08:34,740
And this will return true if the path,

196
00:08:34,740 --> 00:08:36,919
in this case, to which a request was sent,

197
00:08:36,919 --> 00:08:39,190
starts with /admin,

198
00:08:39,190 --> 00:08:40,620
which tells me that you're trying

199
00:08:40,620 --> 00:08:42,663
to access one of our admin routes.

200
00:08:43,750 --> 00:08:44,640
If that's the case,

201
00:08:44,640 --> 00:08:48,570
I also want to check if you maybe aren't an admin,

202
00:08:48,570 --> 00:08:50,910
so isAdmin is not true.

203
00:08:50,910 --> 00:08:52,750
Hence the exclamation mark.

204
00:08:52,750 --> 00:08:53,760
And in that case,

205
00:08:53,760 --> 00:08:56,230
I know that you're trying to an admin route,

206
00:08:56,230 --> 00:08:58,453
even though you aren't an admin.

207
00:09:00,030 --> 00:09:00,990
Now, that means that here,

208
00:09:00,990 --> 00:09:03,920
I also don't want to continue in this middleware.

209
00:09:03,920 --> 00:09:08,050
Instead I'll redirect to 403.

210
00:09:08,050 --> 00:09:10,740
And that's another route we have yet to add.

211
00:09:10,740 --> 00:09:13,370
403 because that will be the status code

212
00:09:13,370 --> 00:09:14,480
I'll then use later

213
00:09:14,480 --> 00:09:17,320
because that's the status code for telling a user

214
00:09:17,320 --> 00:09:20,840
or the browser that you're not authorized.

215
00:09:20,840 --> 00:09:22,460
So you might be authenticated,

216
00:09:22,460 --> 00:09:23,920
but you still don't have access

217
00:09:23,920 --> 00:09:25,710
to this specific resource

218
00:09:25,710 --> 00:09:27,123
you're trying to access.

219
00:09:28,310 --> 00:09:30,550
And if you make it past these if-checks,

220
00:09:30,550 --> 00:09:33,250
then you either didn't visit an admin route,

221
00:09:33,250 --> 00:09:34,980
but you are authenticated

222
00:09:34,980 --> 00:09:37,460
or you did try to access an admin route

223
00:09:37,460 --> 00:09:39,710
and you are an admin.

224
00:09:39,710 --> 00:09:42,670
And either way, I want to allow you to proceed.

225
00:09:42,670 --> 00:09:45,600
So then I call next so that the next middleware

226
00:09:45,600 --> 00:09:48,983
or route handling function in line can take over.

227
00:09:50,600 --> 00:09:53,280
And now protectRoutes should be applied

228
00:09:53,280 --> 00:09:56,440
to some routes in app.js.

229
00:09:56,440 --> 00:09:59,550
I want to run it in front of my admin routes.

230
00:09:59,550 --> 00:10:01,010
The baseRoutes, authRoutes, and productsRoutes

231
00:10:02,350 --> 00:10:04,740
are all accessible to everyone,

232
00:10:04,740 --> 00:10:06,870
also not logged in users.

233
00:10:06,870 --> 00:10:09,560
So we don't need to protect those.

234
00:10:09,560 --> 00:10:12,659
But before we try to handle a request

235
00:10:12,659 --> 00:10:14,649
with the adminRoutes,

236
00:10:14,649 --> 00:10:16,140
I want to run that request

237
00:10:16,140 --> 00:10:19,490
through that protectRoutes middleware we just worked on,

238
00:10:19,490 --> 00:10:22,060
which might redirect the response

239
00:10:22,060 --> 00:10:24,950
if the user tries to access a route

240
00:10:24,950 --> 00:10:27,760
or tries to send a request to a route

241
00:10:27,760 --> 00:10:29,380
where authentication

242
00:10:29,380 --> 00:10:31,943
or administration privileges are needed.

243
00:10:33,460 --> 00:10:36,090
So for this, let's import this middleware here

244
00:10:36,090 --> 00:10:37,790
in app.js.

245
00:10:37,790 --> 00:10:40,100
The protectRoutesMiddleware

246
00:10:41,240 --> 00:10:43,520
can be imported by requiring

247
00:10:44,464 --> 00:10:46,503
middlewares protect-routes.

248
00:10:47,970 --> 00:10:50,587
And now we use the protectRoutesMiddleware down here

249
00:10:50,587 --> 00:10:54,253
with app use just like this.

250
00:10:56,490 --> 00:10:58,570
So that will now protect all the routes

251
00:10:58,570 --> 00:11:01,610
that come thereafter, including this admin route,

252
00:11:01,610 --> 00:11:03,871
not the errorHandlerMiddleware.

253
00:11:03,871 --> 00:11:05,300
That will still work.

254
00:11:05,300 --> 00:11:07,610
But now we won't allow unauthenticated

255
00:11:07,610 --> 00:11:10,520
or unauthorized access to certain routes,

256
00:11:10,520 --> 00:11:12,203
in this case to the admin routes.

257
00:11:13,310 --> 00:11:16,880
Now since I'm redirecting to 401 and 403 in here,

258
00:11:16,880 --> 00:11:19,130
I want to make sure that we have those routes.

259
00:11:19,130 --> 00:11:22,670
And for that I'll start with the views for those routes.

260
00:11:22,670 --> 00:11:27,250
I'll copy the 404.ejs file like this

261
00:11:27,250 --> 00:11:30,810
and rename it to 401.ejs,

262
00:11:30,810 --> 00:11:33,680
and then here on 401.ejs,

263
00:11:33,680 --> 00:11:36,577
I'll say "Not authenticated."

264
00:11:37,610 --> 00:11:42,610
And in here say "You are not authenticated" maybe.

265
00:11:44,290 --> 00:11:48,700
And then I'll copy it again to have a 403.ejs file.

266
00:11:48,700 --> 00:11:51,350
And in that file, I'll say "Not authorized,"

267
00:11:51,350 --> 00:11:53,420
which is a different thing as you learned,

268
00:11:53,420 --> 00:11:55,630
and I'll say "You are not authorized."

269
00:11:55,630 --> 00:11:57,610
And of course you can fine-tune these pages

270
00:11:57,610 --> 00:11:58,870
to your likings.

271
00:12:00,010 --> 00:12:02,150
Now these are the views, not the routes.

272
00:12:02,150 --> 00:12:05,400
We also need the routes, and these will be some base routes,

273
00:12:05,400 --> 00:12:07,750
which I want to register here.

274
00:12:07,750 --> 00:12:10,140
So here in base.routes.js,

275
00:12:10,140 --> 00:12:12,490
I now want to define base routes

276
00:12:12,490 --> 00:12:16,350
for these 401 and so on views.

277
00:12:16,350 --> 00:12:19,420
And we actually don't have any controller

278
00:12:19,420 --> 00:12:20,550
for these routes.

279
00:12:20,550 --> 00:12:21,500
We could add one,

280
00:12:21,500 --> 00:12:24,380
but since this will all be very simple routes,

281
00:12:24,380 --> 00:12:27,460
I will just write them all with anonymous functions here,

282
00:12:27,460 --> 00:12:29,550
but adding a separate controller, of course,

283
00:12:29,550 --> 00:12:30,853
also would be fine.

284
00:12:31,810 --> 00:12:34,770
Here I want to handle /401,

285
00:12:34,770 --> 00:12:38,070
and in that case execute a function,

286
00:12:38,070 --> 00:12:40,950
which gets a request and a response,

287
00:12:40,950 --> 00:12:44,600
where I send back res.render.

288
00:12:44,600 --> 00:12:47,293
And then here I render shared 401.

289
00:12:48,660 --> 00:12:51,520
So this 401.ejs file we just added.

290
00:12:51,520 --> 00:12:54,230
That's the template I render here.

291
00:12:54,230 --> 00:12:57,063
And then I register another get route for 403,

292
00:12:58,760 --> 00:13:01,500
which is that other route we tried to redirect to

293
00:13:01,500 --> 00:13:04,400
in our protectRoutesMiddleware in some cases.

294
00:13:04,400 --> 00:13:07,143
And here we render the 403 view.

295
00:13:08,310 --> 00:13:10,890
And actually I'll also set status codes here

296
00:13:10,890 --> 00:13:14,167
to 401 and to 403,

297
00:13:16,110 --> 00:13:20,100
to have the appropriate status codes for these responses,

298
00:13:20,100 --> 00:13:23,790
to make it clear why this kind of response was sent.

299
00:13:23,790 --> 00:13:25,280
That's a technical detail,

300
00:13:25,280 --> 00:13:27,033
but still a good idea to set.

301
00:13:28,870 --> 00:13:31,210
With that, if I now try to reload,

302
00:13:31,210 --> 00:13:32,880
I get "Not authenticated"

303
00:13:32,880 --> 00:13:34,683
because I'm not logged in.

304
00:13:35,690 --> 00:13:40,000
And if I do log in with my administrator,

305
00:13:40,000 --> 00:13:43,130
so with the correct administration credentials,

306
00:13:43,130 --> 00:13:44,963
then of course I can visit this.

307
00:13:46,960 --> 00:13:50,440
If I log out and I log in with another user,

308
00:13:50,440 --> 00:13:52,240
who has an account,

309
00:13:52,240 --> 00:13:55,370
but who is not an administrator,

310
00:13:55,370 --> 00:13:57,700
then you will see that if I now try

311
00:13:57,700 --> 00:14:01,090
to access /admin/products,

312
00:14:01,090 --> 00:14:03,063
I get the "Not authorized" page.

313
00:14:04,230 --> 00:14:05,800
So now this protection works

314
00:14:05,800 --> 00:14:08,500
and it ensures that we can't visit pages

315
00:14:08,500 --> 00:14:10,050
or send requests,

316
00:14:10,050 --> 00:14:12,763
which we shouldn't be allowed to visit or send.

