diff options
author | Josh Morel <morel.josh@hotmail.com> | 2018-08-31 03:18:19 -0400 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2018-08-31 09:18:19 +0200 |
commit | d9eaee3939bf2e93e5d775d32bce77842201faba (patch) | |
tree | c115acb3611986b98f51b3addf29ebe66f63ee7f /server/controllers/api | |
parent | 04291e1ba44032165388758e993d385a10c1c5a1 (diff) | |
download | PeerTube-d9eaee3939bf2e93e5d775d32bce77842201faba.tar.gz PeerTube-d9eaee3939bf2e93e5d775d32bce77842201faba.tar.zst PeerTube-d9eaee3939bf2e93e5d775d32bce77842201faba.zip |
add user account email verificiation (#977)
* add user account email verificiation
includes server and client code to:
* enable verificationRequired via custom config
* send verification email with registration
* ask for verification email
* verify via email
* prevent login if not verified and required
* conditional client links to ask for new verification email
* allow login for verified=null
these are users created when verification not required
should still be able to login when verification is enabled
* refactor email verifcation pr
* change naming from verified to emailVerified
* change naming from askVerifyEmail to askSendVerifyEmail
* undo unrelated automatic prettier formatting on api/config
* use redirectService for home
* remove redundant success notification on email verified
* revert test.yaml smpt host
Diffstat (limited to 'server/controllers/api')
-rw-r--r-- | server/controllers/api/config.ts | 16 | ||||
-rw-r--r-- | server/controllers/api/users/index.ts | 47 |
2 files changed, 58 insertions, 5 deletions
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index 25ddd1fa6..6edbe4820 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts | |||
@@ -60,7 +60,8 @@ async function getConfig (req: express.Request, res: express.Response, next: exp | |||
60 | serverVersion: packageJSON.version, | 60 | serverVersion: packageJSON.version, |
61 | signup: { | 61 | signup: { |
62 | allowed, | 62 | allowed, |
63 | allowedForCurrentIP | 63 | allowedForCurrentIP, |
64 | requiresEmailVerification: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION | ||
64 | }, | 65 | }, |
65 | transcoding: { | 66 | transcoding: { |
66 | enabledResolutions | 67 | enabledResolutions |
@@ -159,12 +160,20 @@ async function updateCustomConfig (req: express.Request, res: express.Response, | |||
159 | toUpdate.transcoding.threads = parseInt('' + toUpdate.transcoding.threads, 10) | 160 | toUpdate.transcoding.threads = parseInt('' + toUpdate.transcoding.threads, 10) |
160 | 161 | ||
161 | // camelCase to snake_case key | 162 | // camelCase to snake_case key |
162 | const toUpdateJSON = omit(toUpdate, 'user.videoQuota', 'instance.defaultClientRoute', 'instance.shortDescription', 'cache.videoCaptions') | 163 | const toUpdateJSON = omit( |
164 | toUpdate, | ||
165 | 'user.videoQuota', | ||
166 | 'instance.defaultClientRoute', | ||
167 | 'instance.shortDescription', | ||
168 | 'cache.videoCaptions', | ||
169 | 'signup.requiresEmailVerification' | ||
170 | ) | ||
163 | toUpdateJSON.user['video_quota'] = toUpdate.user.videoQuota | 171 | toUpdateJSON.user['video_quota'] = toUpdate.user.videoQuota |
164 | toUpdateJSON.user['video_quota_daily'] = toUpdate.user.videoQuotaDaily | 172 | toUpdateJSON.user['video_quota_daily'] = toUpdate.user.videoQuotaDaily |
165 | toUpdateJSON.instance['default_client_route'] = toUpdate.instance.defaultClientRoute | 173 | toUpdateJSON.instance['default_client_route'] = toUpdate.instance.defaultClientRoute |
166 | toUpdateJSON.instance['short_description'] = toUpdate.instance.shortDescription | 174 | toUpdateJSON.instance['short_description'] = toUpdate.instance.shortDescription |
167 | toUpdateJSON.instance['default_nsfw_policy'] = toUpdate.instance.defaultNSFWPolicy | 175 | toUpdateJSON.instance['default_nsfw_policy'] = toUpdate.instance.defaultNSFWPolicy |
176 | toUpdateJSON.signup['requires_email_verification'] = toUpdate.signup.requiresEmailVerification | ||
168 | 177 | ||
169 | await writeJSON(CONFIG.CUSTOM_FILE, toUpdateJSON, { spaces: 2 }) | 178 | await writeJSON(CONFIG.CUSTOM_FILE, toUpdateJSON, { spaces: 2 }) |
170 | 179 | ||
@@ -220,7 +229,8 @@ function customConfig (): CustomConfig { | |||
220 | }, | 229 | }, |
221 | signup: { | 230 | signup: { |
222 | enabled: CONFIG.SIGNUP.ENABLED, | 231 | enabled: CONFIG.SIGNUP.ENABLED, |
223 | limit: CONFIG.SIGNUP.LIMIT | 232 | limit: CONFIG.SIGNUP.LIMIT, |
233 | requiresEmailVerification: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION | ||
224 | }, | 234 | }, |
225 | admin: { | 235 | admin: { |
226 | email: CONFIG.ADMIN.EMAIL | 236 | email: CONFIG.ADMIN.EMAIL |
diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts index 25d51ae5e..008c34ca4 100644 --- a/server/controllers/api/users/index.ts +++ b/server/controllers/api/users/index.ts | |||
@@ -25,7 +25,10 @@ import { | |||
25 | usersSortValidator, | 25 | usersSortValidator, |
26 | usersUpdateValidator | 26 | usersUpdateValidator |
27 | } from '../../../middlewares' | 27 | } from '../../../middlewares' |
28 | import { usersAskResetPasswordValidator, usersBlockingValidator, usersResetPasswordValidator } from '../../../middlewares/validators' | 28 | import { |
29 | usersAskResetPasswordValidator, usersBlockingValidator, usersResetPasswordValidator, | ||
30 | usersAskSendVerifyEmailValidator, usersVerifyEmailValidator | ||
31 | } from '../../../middlewares/validators' | ||
29 | import { UserModel } from '../../../models/account/user' | 32 | import { UserModel } from '../../../models/account/user' |
30 | import { OAuthTokenModel } from '../../../models/oauth/oauth-token' | 33 | import { OAuthTokenModel } from '../../../models/oauth/oauth-token' |
31 | import { auditLoggerFactory, UserAuditView } from '../../../helpers/audit-logger' | 34 | import { auditLoggerFactory, UserAuditView } from '../../../helpers/audit-logger' |
@@ -110,6 +113,17 @@ usersRouter.post('/:id/reset-password', | |||
110 | asyncMiddleware(resetUserPassword) | 113 | asyncMiddleware(resetUserPassword) |
111 | ) | 114 | ) |
112 | 115 | ||
116 | usersRouter.post('/ask-send-verify-email', | ||
117 | loginRateLimiter, | ||
118 | asyncMiddleware(usersAskSendVerifyEmailValidator), | ||
119 | asyncMiddleware(askSendVerifyUserEmail) | ||
120 | ) | ||
121 | |||
122 | usersRouter.post('/:id/verify-email', | ||
123 | asyncMiddleware(usersVerifyEmailValidator), | ||
124 | asyncMiddleware(verifyUserEmail) | ||
125 | ) | ||
126 | |||
113 | usersRouter.post('/token', | 127 | usersRouter.post('/token', |
114 | loginRateLimiter, | 128 | loginRateLimiter, |
115 | token, | 129 | token, |
@@ -165,7 +179,8 @@ async function registerUser (req: express.Request, res: express.Response) { | |||
165 | autoPlayVideo: true, | 179 | autoPlayVideo: true, |
166 | role: UserRole.USER, | 180 | role: UserRole.USER, |
167 | videoQuota: CONFIG.USER.VIDEO_QUOTA, | 181 | videoQuota: CONFIG.USER.VIDEO_QUOTA, |
168 | videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY | 182 | videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY, |
183 | emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null | ||
169 | }) | 184 | }) |
170 | 185 | ||
171 | const { user } = await createUserAccountAndChannel(userToCreate) | 186 | const { user } = await createUserAccountAndChannel(userToCreate) |
@@ -173,6 +188,10 @@ async function registerUser (req: express.Request, res: express.Response) { | |||
173 | auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON())) | 188 | auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON())) |
174 | logger.info('User %s with its channel and account registered.', body.username) | 189 | logger.info('User %s with its channel and account registered.', body.username) |
175 | 190 | ||
191 | if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) { | ||
192 | await sendVerifyUserEmail(user) | ||
193 | } | ||
194 | |||
176 | return res.type('json').status(204).end() | 195 | return res.type('json').status(204).end() |
177 | } | 196 | } |
178 | 197 | ||
@@ -261,6 +280,30 @@ async function resetUserPassword (req: express.Request, res: express.Response, n | |||
261 | return res.status(204).end() | 280 | return res.status(204).end() |
262 | } | 281 | } |
263 | 282 | ||
283 | async function sendVerifyUserEmail (user: UserModel) { | ||
284 | const verificationString = await Redis.Instance.setVerifyEmailVerificationString(user.id) | ||
285 | const url = CONFIG.WEBSERVER.URL + '/verify-account/email?userId=' + user.id + '&verificationString=' + verificationString | ||
286 | await Emailer.Instance.addVerifyEmailJob(user.email, url) | ||
287 | return | ||
288 | } | ||
289 | |||
290 | async function askSendVerifyUserEmail (req: express.Request, res: express.Response, next: express.NextFunction) { | ||
291 | const user = res.locals.user as UserModel | ||
292 | |||
293 | await sendVerifyUserEmail(user) | ||
294 | |||
295 | return res.status(204).end() | ||
296 | } | ||
297 | |||
298 | async function verifyUserEmail (req: express.Request, res: express.Response, next: express.NextFunction) { | ||
299 | const user = res.locals.user as UserModel | ||
300 | user.emailVerified = true | ||
301 | |||
302 | await user.save() | ||
303 | |||
304 | return res.status(204).end() | ||
305 | } | ||
306 | |||
264 | function success (req: express.Request, res: express.Response, next: express.NextFunction) { | 307 | function success (req: express.Request, res: express.Response, next: express.NextFunction) { |
265 | res.end() | 308 | res.end() |
266 | } | 309 | } |