From 90bb9e932efd1e6a1fd4966bdd8691f9a5096e4e Mon Sep 17 00:00:00 2001 From: thondery Date: Fri, 8 Mar 2019 16:22:05 +0800 Subject: [PATCH] update page: account/security ... --- assets/scss/console/security.scss | 200 +++++++++++++++++ components/security/email.vue | 139 ++++++++++++ components/security/mobile.vue | 143 ++++++++++++ components/security/password.vue | 140 ++++++++++++ components/security/verify.vue | 95 ++++++++ mails/send_code.mjml | 27 +++ pages/account/security.vue | 359 +++++++++++++++++++----------- pages/register.vue | 2 +- server/api/v1/account.ts | 2 +- server/api/v1/index.ts | 3 +- server/api/v1/security.ts | 237 ++++++++++++++++++++ server/error/code.ts | 3 + server/error/message/zh-cn.ts | 3 + server/filters/api_v1/security.ts | 159 +++++++++++++ server/middlewares/auth.ts | 2 +- server/models/verify.ts | 7 + server/proxys/user.ts | 6 + server/proxys/verify.ts | 7 + server/types/account.d.ts | 23 ++ server/types/error/code.d.ts | 3 + server/types/error/message.d.ts | 3 + server/types/mailer.d.ts | 8 + server/types/proxys/verify.d.ts | 2 + store/modules/auth.ts | 17 +- types/index.d.ts | 21 ++ 25 files changed, 1477 insertions(+), 134 deletions(-) create mode 100644 assets/scss/console/security.scss create mode 100644 components/security/email.vue create mode 100644 components/security/mobile.vue create mode 100644 components/security/password.vue create mode 100644 components/security/verify.vue create mode 100644 mails/send_code.mjml create mode 100644 server/api/v1/security.ts create mode 100644 server/filters/api_v1/security.ts diff --git a/assets/scss/console/security.scss b/assets/scss/console/security.scss new file mode 100644 index 0000000..d157b1f --- /dev/null +++ b/assets/scss/console/security.scss @@ -0,0 +1,200 @@ +// ------------------------------------ +// Sass Style +// ------------------------------------ +.security-container { + padding: 0 30px; + font-family: Lantinghei; + color: #444242; + max-width: 960px; + margin: auto; + position: relative; + + .panel { + //min-height: 180px; + + .panel-body { + display: flex; + justify-content: space-between; + //align-items: center; + min-height: 100px; + padding: 44px 30px; + + .panel-content { + padding: 0 20px 0 0; + + h4 { + height: 26px; + margin: 0 0 20px; + line-height: 26px; + font-size: 18px; + font-weight: 400; + + i { + font-size: 20px; + + &.success { + color: #4CAF50; + } + + &.info { + color: #ffc107; + } + + &.warning { + color: #FF5722; + } + } + + &+p { + margin-top: 20px; + } + + &:not(:first-child) { + margin-top: 20px; + font-size: 1.2em; + } + } + + p { + color: #747474; + line-height: 1.8; + margin: 0 ; + } + + .row-inline { + list-style: none; + display: flex; + padding: 0; + + &>li { + margin: 0 30px 10px 0!important; + color: #747474; + + &:before { + width: 8px; + height: 8px; + background-color: #52acd9; + color: #52acd9; + display: inline-block; + border-radius: 50%; + margin-right: 5px; + content: ''; + } + } + } + } + + .panel-sidebar { + display: flex; + align-items: flex-end; + padding: 0 30px 30px 0; + + .el-button { + border-radius: 0; + } + } + } + + &:not(:last-child) { + border-bottom: 1px solid #ecedf1; + } + } + + .el-steps { + margin-top: 80px; + } + + .main-content { + margin: auto; + margin-top: 80px; + + p { + margin: auto; + width: 600px; + border-bottom: 1px solid rgb(153, 153, 153); + + span { + margin-left: 20px; + } + } + + .el-form { + margin: 40px auto auto; + width: 600px; + + .el-form-item { + margin-bottom: 28px; + } + + .el-form-item__label { + //font-size: 13px; + padding-right: 20px; + color: #777; + } + + .el-input__inner { + border-radius: 0; + } + + .el-button--primary { + border-radius: 0; + width: 150px; + } + } + + .footer { + margin: auto; + border-top: 1px dashed #e8e8e8; + width: 600px; + margin-top: 50px; + padding: 15px 60px 0; + + h2 { + font-size: 15px; + margin-bottom: 16px; + } + + p { + line-height: 1.8; + margin-left: 20px; + border-bottom: 0; + width: auto; + } + } + + .result { + margin: 0 auto; + text-align: center; + + i { + color: #52c41a; + font-size: 72px; + line-height: 72px; + margin-bottom: 24px; + } + + h2 { + font-size: 24px; + } + + p { + border-bottom: 0; + } + } + } + + .close_content { + position: absolute; + top: -40px; + right: 0; + font-size: 24px; + + i { + cursor: pointer; + + &:hover { + color: #52acd9; + } + } + } +} \ No newline at end of file diff --git a/components/security/email.vue b/components/security/email.vue new file mode 100644 index 0000000..de97004 --- /dev/null +++ b/components/security/email.vue @@ -0,0 +1,139 @@ + + + \ No newline at end of file diff --git a/components/security/mobile.vue b/components/security/mobile.vue new file mode 100644 index 0000000..c9abfa5 --- /dev/null +++ b/components/security/mobile.vue @@ -0,0 +1,143 @@ + + + \ No newline at end of file diff --git a/components/security/password.vue b/components/security/password.vue new file mode 100644 index 0000000..9953df4 --- /dev/null +++ b/components/security/password.vue @@ -0,0 +1,140 @@ + + + \ No newline at end of file diff --git a/components/security/verify.vue b/components/security/verify.vue new file mode 100644 index 0000000..bab52be --- /dev/null +++ b/components/security/verify.vue @@ -0,0 +1,95 @@ + + + \ No newline at end of file diff --git a/mails/send_code.mjml b/mails/send_code.mjml new file mode 100644 index 0000000..ded2c1d --- /dev/null +++ b/mails/send_code.mjml @@ -0,0 +1,27 @@ + + + {{ site_name }}{{ title }} + + + + + + + + + 亲爱的 {{ username }}: + 您选择了通过邮件进行{{ site_name }}{{ title }}。请在相关页面中输入以下 验证码 进行操作: + + + {{ code }} + + + (此验证码有效时间为 {{ timeout }} 分钟,若超时请重新获取邮件) + 如果您要放弃操作,或者未曾申请{{ title }},请忽略此邮件。 + 为了您的账户安全,请您注意对此邮件内容保密。 + + - {{ site_name }}
(这是一封自动产生的Email,请勿回复)
+
+
+
+
\ No newline at end of file diff --git a/pages/account/security.vue b/pages/account/security.vue index 2801830..4f7aade 100644 --- a/pages/account/security.vue +++ b/pages/account/security.vue @@ -1,35 +1,72 @@ - - + \ No newline at end of file diff --git a/pages/register.vue b/pages/register.vue index 1c8b2af..2a71fef 100644 --- a/pages/register.vue +++ b/pages/register.vue @@ -106,7 +106,7 @@ export default class extends Vue { async handleUnique (type: 'username' | 'email', value: string): Promise { try { - let result: resufulInfo = await http.post(`/account/check/${type}`, { name: value }) + let result: resufulInfo = await http.put(`/account/check/${type}`, { name: value }) return result.data } catch (error) { this.$message.warning(error.message) diff --git a/server/api/v1/account.ts b/server/api/v1/account.ts index 5b82b31..4e7bbb7 100644 --- a/server/api/v1/account.ts +++ b/server/api/v1/account.ts @@ -84,7 +84,7 @@ export default class Account extends RouterMethods { * 验证名称是否占用 * @param name 用户名 | 电子邮箱 | 手机号 */ - @Router({ method: 'post', path: '/account/check/:type(username|email|mobile)'}) + @Router({ method: 'put', path: '/account/check/:type(username|email|mobile)'}) public async check (req: Request, res: IResponse, next: NextFunction): Promise { let { type } = req.params let { name } = req.body diff --git a/server/api/v1/index.ts b/server/api/v1/index.ts index 87853d3..3a161c4 100644 --- a/server/api/v1/index.ts +++ b/server/api/v1/index.ts @@ -1,8 +1,9 @@ import { RouterController, ControllerMount } from 'kenote-express-helper' import Account from './account' +import Security from './security' -@ControllerMount(Account) +@ControllerMount(Account, Security) class API_V1 extends RouterController {} export default new API_V1() \ No newline at end of file diff --git a/server/api/v1/security.ts b/server/api/v1/security.ts new file mode 100644 index 0000000..a7390a0 --- /dev/null +++ b/server/api/v1/security.ts @@ -0,0 +1,237 @@ +import { Request, Response, NextFunction } from 'express' +import { Router, RouterMethods, Filter } from 'kenote-express-helper' +import { CustomError, __ErrorCode } from '../../error' +import * as passport from 'passport' +import userProxy from '../../proxys/user' +import verifyProxy from '../../proxys/verify' +import securityFilter from '../../filters/api_v1/security' +import mailer from '../../utils/mailer' +import config from '../../config' +import { uniq } from 'lodash' +import alicloud from '../../utils/alicloud' + +import { IRequest, IResponse } from '../../types/resuful' +import { responseDocument as responseUserDocument } from '../../types/proxys/user' +import { responseDocument as responseVerifyDocument, createDocument as createVerifyDocument } from '../../types/proxys/verify' +import * as Mail from 'nodemailer/lib/mailer' +import { MailerContext } from '../../types/mailer' +import account from '../../types/account' +import * as mongoose from 'mongoose' + +export default class Security extends RouterMethods { + + /** + * 发送验证码 + * @param name 电子邮箱 | 手机号 + */ + @Router( { method: 'put', path: '/security/sendcode/:type(email|mobile)'} ) + @Filter( passport.authenticate('jwt', { session: false }), securityFilter.sendCode ) + public async sendCode (document: any, req: IRequest, res: IResponse, next: NextFunction): Promise { + let { type } = req.params + let { name, verify_id } = document + let user: responseUserDocument = req.user + try { + let verify: responseVerifyDocument = await verifyProxy.Dao.findOne(verify_id ? { type: 'code', _id: verify_id } : { type: 'code', user: user._id }) + if (!verify && verify_id) { + return res.api(null, __ErrorCode.ERROR_VERIFY_ID_FAILED) + } + if (verify) { + let updateTime: Date = verify_id ? verify.update_at : verify.create_at + let difftime: number = Date.now() - updateTime.getTime() + let timeout: number = Number(req.__register.mailphone_step) * 1000 + if (difftime < timeout) { + return res.api(null, __ErrorCode.ERROR_SEND_MAILPHONE_STEP) + } + !verify_id && await verifyProxy.Dao.remove({ _id: verify._id }) + } + + if (verify_id) { + verify = await verifyProxy.update({ _id: verify_id }, { application: name }) + } + else { + verify = await verifyProxy.create({ type: 'code', user: user._id }) + } + + if (type === 'email') { + let title: string = verify_id ? '邮箱校验' : '帐号身份校验' + let mail: Mail.Options = { + from: `${config.site_name} <${mailer.__MailOptions.auth.user}>`, + to: `${user.username} <${verify_id ? name : user.email}>`, + subject: `${config.site_name}${title}` + } + let context: MailerContext.sendCode = { + title: title, + site_name: config.site_name, + username: user.username, + code: verify.token, + timeout: req.__register.lost_pass.timeout / 60 + } + mailer.sendMail('send_code.mjml', mail, context) + } + if (type === 'mobile') { + await alicloud.SendSms(verify_id ? name : user.mobile, verify_id ? 'setinfos' : 'verifyid', { code: verify.token }) + } + return res.api({ result: true }) + } catch (error) { + if (CustomError(error)) { + return res.api(null, error) + } + return next(error) + } + } + + /** + * 校验验证码 + * @param code 验证码 + */ + @Router({ method: 'post', path: '/security/verifycode' }) + @Filter( passport.authenticate('jwt', { session: false }) ) + public async verifyCode (req: IRequest, res: IResponse, next: NextFunction): Promise { + let { code } = req.body + let user: responseUserDocument = req.user + try { + let verify: responseVerifyDocument = await verifyProxy.Dao.findOne({ type: 'code', user: user._id, token: code }) + if (!verify) { + return res.api(null, __ErrorCode.ERROR_VERIFY_CODE_FAILED) + } + let difftime: number = Date.now() - verify.create_at.getTime() + let timeout: number = Number(req.__register.lost_pass.timeout) * 1000 + if (difftime > timeout) { + return res.api(null, __ErrorCode.ERROR_VERIFY_CODE_TIMEOUT) + } + return res.api({ _id: verify._id }) + } catch (error) { + if (CustomError(error)) { + return res.api(null, error) + } + return next(error) + } + } + + /** + * 修改密码 + * @param passport 新密码 + * @param verify_id 身份验证 ID + */ + @Router({ method: 'post', path: '/security/setpassword' }) + @Filter( passport.authenticate('jwt', { session: false }), securityFilter.setPassword ) + public async setPassword (document: account.setPassword, req: IRequest, res: IResponse, next: NextFunction): Promise { + let { verify_id } = document + let user: responseUserDocument = req.user + try { + let verify: responseVerifyDocument = await verifyProxy.Dao.findOne({ type: 'code', user: user._id, _id: verify_id }) + if (!verify) { + return res.api(null, __ErrorCode.ERROR_VERIFY_ID_FAILED) + } + let difftime: number = Date.now() - verify.create_at.getTime() + let timeout: number = Number(req.__register.lost_pass.timeout) * 1000 + if (difftime > timeout) { + return res.api(null, __ErrorCode.ERROR_VERIFY_ID_TIMEOUT) + } + let result: mongoose.Query = await userProxy.setPassword({ _id: user._id }, document) + await verifyProxy.Dao.remove({ _id: verify._id }) + return res.api(result) + } catch (error) { + if (CustomError(error)) { + return res.api(null, error) + } + return next(error) + } + } + + /** + * 验证名称是否占用 + * @param name 用户名 | 电子邮箱 | 手机号 + */ + @Router({ method: 'put', path: '/security/check/:type(username|email|mobile)'}) + @Filter( passport.authenticate('jwt', { session: false }) ) + public async check (req: Request, res: IResponse, next: NextFunction): Promise { + let { type } = req.params + let { name } = req.body + let auth: responseUserDocument = req.user + let warnings: account.CheckWarning = { + username: __ErrorCode.ERROR_VALID_USERNAME_UNIQUE, + email: __ErrorCode.ERROR_VALID_EMAIL_UNIQUE, + mobile: __ErrorCode.ERROR_VALID_MOBILE_UNIQUE + } + try { + let user: responseUserDocument = await userProxy.Dao.findOne({ [type]: { $eq: name, $ne: auth[type] } }) + return res.api(!user, user ? warnings[type] : null) + } catch (error) { + if (CustomError(error)) { + return res.api(null, error) + } + return next(error) + } + } + + /** + * 修改邮箱 + * @param email 新邮箱 + * @param code 邮箱验证码 + * @param verify_id 身份验证 ID + */ + @Router({ method: 'post', path: '/security/setemail' }) + @Filter( passport.authenticate('jwt', { session: false }), securityFilter.setEmail ) + public async setEmail (document: account.setEmail, req: IRequest, res: IResponse, next: NextFunction): Promise { + let { verify_id, code, email } = document + let user: responseUserDocument = req.user + try { + let verify: responseVerifyDocument = await verifyProxy.Dao.findOne({ type: 'code', user: user._id, _id: verify_id }) + if (!verify) { + return res.api(null, __ErrorCode.ERROR_VERIFY_ID_FAILED) + } + let difftime: number = Date.now() - verify.create_at.getTime() + let timeout: number = Number(req.__register.lost_pass.timeout) * 1000 + if (difftime > timeout) { + return res.api(null, __ErrorCode.ERROR_VERIFY_ID_TIMEOUT) + } + if (verify.token !== code) { + return res.api(null, __ErrorCode.ERROR_VERIFY_CODE_FAILED) + } + let result: mongoose.Query = await userProxy.Dao.updateOne({ _id: user._id }, { email, binds: uniq(user.binds.concat('email')) }) + await verifyProxy.Dao.remove({ _id: verify._id }) + return res.api(result) + } catch (error) { + if (CustomError(error)) { + return res.api(null, error) + } + return next(error) + } + } + + /** + * 修改手机 + * @param mobile 新手机 + * @param code 手机验证码 + * @param verify_id 身份验证 ID + */ + @Router({ method: 'post', path: '/security/setmobile' }) + @Filter( passport.authenticate('jwt', { session: false }), securityFilter.setMobile ) + public async setMobile (document: account.setMobile, req: IRequest, res: IResponse, next: NextFunction): Promise { + let { verify_id, code, mobile } = document + let user: responseUserDocument = req.user + try { + let verify: responseVerifyDocument = await verifyProxy.Dao.findOne({ type: 'code', user: user._id, _id: verify_id }) + if (!verify) { + return res.api(null, __ErrorCode.ERROR_VERIFY_ID_FAILED) + } + let difftime: number = Date.now() - verify.create_at.getTime() + let timeout: number = Number(req.__register.lost_pass.timeout) * 1000 + if (difftime > timeout) { + return res.api(null, __ErrorCode.ERROR_VERIFY_ID_TIMEOUT) + } + if (verify.token !== code) { + return res.api(null, __ErrorCode.ERROR_VERIFY_CODE_FAILED) + } + let result: mongoose.Query = await userProxy.Dao.updateOne({ _id: user._id }, { mobile, binds: uniq(user.binds.concat('mobile')) }) + await verifyProxy.Dao.remove({ _id: verify._id }) + return res.api(result) + } catch (error) { + if (CustomError(error)) { + return res.api(null, error) + } + return next(error) + } + } +} \ No newline at end of file diff --git a/server/error/code.ts b/server/error/code.ts index e8e02d6..f9487d0 100644 --- a/server/error/code.ts +++ b/server/error/code.ts @@ -46,5 +46,8 @@ export default { ERROR_VERIFY_CODE_REQUIRED : 1424, ERROR_VERIFY_CODE_TIMEOUT : 1425, ERROR_VERIFY_CODE_FAILED : 1426, + ERROR_VERIFY_ID_REQUIRED : 1427, + ERROR_VERIFY_ID_TIMEOUT : 1428, + ERROR_VERIFY_ID_FAILED : 1429, } diff --git a/server/error/message/zh-cn.ts b/server/error/message/zh-cn.ts index 48b2be4..f8d9d2b 100644 --- a/server/error/message/zh-cn.ts +++ b/server/error/message/zh-cn.ts @@ -46,5 +46,8 @@ export default { ERROR_VERIFY_CODE_REQUIRED : '验证码不能为空', ERROR_VERIFY_CODE_TIMEOUT : '验证码超时', ERROR_VERIFY_CODE_FAILED : '验证码错误', + ERROR_VERIFY_ID_REQUIRED : '缺少身份验证', + ERROR_VERIFY_ID_TIMEOUT : '身份验证超时', + ERROR_VERIFY_ID_FAILED : '身份验证错误', } \ No newline at end of file diff --git a/server/filters/api_v1/security.ts b/server/filters/api_v1/security.ts new file mode 100644 index 0000000..8004106 --- /dev/null +++ b/server/filters/api_v1/security.ts @@ -0,0 +1,159 @@ + +import { Request, Response, NextFunction } from 'express' +import { Rule, Filter, asyncFilterData, errorInfo, Options } from 'kenote-validate-helper' + +import { IRequest, IResponse } from '../../types/resuful' +import account from '../../types/account' +import { __ErrorCode, __ErrorMessage } from '../../error' +import * as rules from '../../config/rules' + +const accountRules: account.Rules = { + username: [ + { + required : true, + message : __ErrorMessage.ERROR_VALID_USERNAME_REQUIRED, + code : __ErrorCode.ERROR_VALID_USERNAME_REQUIRED + } + ], + email: [ + { + required : true, + message : __ErrorMessage.ERROR_VALID_EMAIL_REQUIRED, + code : __ErrorCode.ERROR_VALID_EMAIL_REQUIRED + } + ], + mobile: [ + { + required : true, + message : __ErrorMessage.ERROR_VALID_MOBILE_REQUIRED, + code : __ErrorCode.ERROR_VALID_MOBILE_REQUIRED + } + ], + password: [ + { + required : true, + message : __ErrorMessage.ERROR_VALID_PASSWORD_REQUIRED, + code : __ErrorCode.ERROR_VALID_PASSWORD_REQUIRED + } + ], + verify_id: [ + { + required : true, + message : __ErrorMessage.ERROR_VERIFY_ID_REQUIRED, + code : __ErrorCode.ERROR_VERIFY_ID_REQUIRED + } + ], + code: [ + { + required : true, + message : __ErrorMessage.ERROR_VERIFY_CODE_REQUIRED, + code : __ErrorCode.ERROR_VERIFY_CODE_REQUIRED + } + ] +} + +class Security { + + public async sendCode (req: IRequest, res: IResponse, next: NextFunction): Promise { + let { type } = req.params + let { name, verify_id } = req.body + let document: account.sendCode = {} + if (!verify_id) return next(document) + let filters: Array = [ + { + key : 'name', + rules : (> accountRules[type]).concat(rules[type]), + value : name + }, + { + key : 'verify_id', + rules : > accountRules.verify_id, + value : verify_id + } + ] + try { + document = await asyncFilterData(filters) + return next(document) + } catch (error) { + return res.api(null, error) + } + } + + public async setPassword (req: IRequest, res: IResponse, next: NextFunction): Promise { + let { password, verify_id } = req.body + let filters: Array = [ + { + key : 'password', + rules : (> accountRules.password).concat(rules.password), + value : password + }, + { + key : 'verify_id', + rules : > accountRules.verify_id, + value : verify_id + } + ] + try { + let document: account.setPassword = await asyncFilterData(filters) + return next(document) + } catch (error) { + return res.api(null, error) + } + } + + public async setEmail (req: IRequest, res: IResponse, next: NextFunction): Promise { + let { email, verify_id, code } = req.body + let filters: Array = [ + { + key : 'email', + rules : (> accountRules.email).concat(rules.email), + value : email + }, + { + key : 'verify_id', + rules : > accountRules.verify_id, + value : verify_id + }, + { + key : 'code', + rules : > accountRules.code, + value : code + } + ] + try { + let document: account.setEmail = await asyncFilterData(filters) + return next(document) + } catch (error) { + return res.api(null, error) + } + } + + public async setMobile (req: IRequest, res: IResponse, next: NextFunction): Promise { + let { mobile, verify_id, code } = req.body + let filters: Array = [ + { + key : 'mobile', + rules : (> accountRules.mobile).concat(rules.mobile), + value : mobile + }, + { + key : 'verify_id', + rules : > accountRules.verify_id, + value : verify_id + }, + { + key : 'code', + rules : > accountRules.code, + value : code + } + ] + try { + let document: account.setMobile = await asyncFilterData(filters) + return next(document) + } catch (error) { + return res.api(null, error) + } + } +} + +export default new Security() \ No newline at end of file diff --git a/server/middlewares/auth.ts b/server/middlewares/auth.ts index 65f2734..dd99069 100644 --- a/server/middlewares/auth.ts +++ b/server/middlewares/auth.ts @@ -17,7 +17,7 @@ const jwtOptions: passportJWT.StrategyOptions = { const startegyVerify: passportJWT.VerifyCallbackWithRequest = async (req: Request, payload: Payload, done: passportJWT.VerifiedCallback): Promise => { try { let user: responseDocument = await userProxy.Dao.findOne({ _id: payload._id }) - return done(null, pick(user, ['_id', 'id', 'username', 'email', 'mobile', 'nickname', 'avatar', 'sex', 'binds', 'group', 'teams', 'create_at', 'update_at'])) + return done(null, pick(user, ['_id', 'id', 'username', 'email', 'mobile', 'nickname', 'avatar', 'sex', 'binds', 'group', 'teams', 'create_at', 'update_at', 'jw_token'])) } catch (error) { return done(error, false) } diff --git a/server/models/verify.ts b/server/models/verify.ts index 977280b..12752ed 100644 --- a/server/models/verify.ts +++ b/server/models/verify.ts @@ -23,6 +23,13 @@ const schema: Schema = new Schema({ approved: { type: Boolean, default: false + }, + application: { + type: String + }, + update_at: { + type: Date, + default: Date.now } }) diff --git a/server/proxys/user.ts b/server/proxys/user.ts index 960a0b9..48513c1 100644 --- a/server/proxys/user.ts +++ b/server/proxys/user.ts @@ -77,6 +77,12 @@ class UserProxy { return result } + public async setPassword (conditions: any, doc: account.setPassword): Bluebird> { + let password: account.Password = bcrypt.hash(doc.password || '') + let result: mongoose.Query = await this.Dao.updateOne(conditions, { encrypt: password.hash, salt: password.salt }) + return result + } + } export default new UserProxy() \ No newline at end of file diff --git a/server/proxys/verify.ts b/server/proxys/verify.ts index 6ef6e12..27c3fdb 100644 --- a/server/proxys/verify.ts +++ b/server/proxys/verify.ts @@ -36,6 +36,13 @@ class VerifyProxy { return verify } + public async update (conditions: any, doc: any): Bluebird> { + let token: string = Math.random().toFixed(6).replace(/^(0\.)/i, '') + let updateTime: Date = new Date() + let result: mongoose.Query = await this.Dao.updateOne(conditions, { ...doc, token, updtae_at: updateTime }) + return { ...result, token } + } + } export default new VerifyProxy() \ No newline at end of file diff --git a/server/types/account.d.ts b/server/types/account.d.ts index a10982f..ff3cd48 100644 --- a/server/types/account.d.ts +++ b/server/types/account.d.ts @@ -25,6 +25,28 @@ declare namespace account { name ?: string } + interface sendCode { + name ?: string + verify_id ?: string + } + + interface setPassword { + password ?: string + verify_id ?: string + } + + interface setEmail { + email : string + verify_id : string + code : string + } + + interface setMobile { + mobile : string + verify_id : string + code : string + } + interface Rules { username ?: Array email ?: Array @@ -32,6 +54,7 @@ declare namespace account { password ?: Array invitation ?: Array code ?: Array + verify_id ?: Array } interface Password { diff --git a/server/types/error/code.d.ts b/server/types/error/code.d.ts index 27f7bdd..974ae47 100644 --- a/server/types/error/code.d.ts +++ b/server/types/error/code.d.ts @@ -41,4 +41,7 @@ export interface CodeTypes { ERROR_VERIFY_CODE_REQUIRED : number ERROR_VERIFY_CODE_TIMEOUT : number ERROR_VERIFY_CODE_FAILED : number + ERROR_VERIFY_ID_REQUIRED : number + ERROR_VERIFY_ID_TIMEOUT : number + ERROR_VERIFY_ID_FAILED : number } \ No newline at end of file diff --git a/server/types/error/message.d.ts b/server/types/error/message.d.ts index 62415b7..36247b1 100644 --- a/server/types/error/message.d.ts +++ b/server/types/error/message.d.ts @@ -41,4 +41,7 @@ export interface MessageTypes { ERROR_VERIFY_CODE_REQUIRED : string ERROR_VERIFY_CODE_TIMEOUT : string ERROR_VERIFY_CODE_FAILED : string + ERROR_VERIFY_ID_REQUIRED : string + ERROR_VERIFY_ID_TIMEOUT : string + ERROR_VERIFY_ID_FAILED : string } \ No newline at end of file diff --git a/server/types/mailer.d.ts b/server/types/mailer.d.ts index 601e212..aef00ec 100644 --- a/server/types/mailer.d.ts +++ b/server/types/mailer.d.ts @@ -14,4 +14,12 @@ export declare namespace MailerContext { code : string timeout : number } + + interface sendCode { + title : string + site_name : string + username : string + code : string + timeout : number + } } \ No newline at end of file diff --git a/server/types/proxys/verify.d.ts b/server/types/proxys/verify.d.ts index 458d064..1dca9ce 100644 --- a/server/types/proxys/verify.d.ts +++ b/server/types/proxys/verify.d.ts @@ -14,4 +14,6 @@ export interface responseDocument extends mongoose.Document { create_at : Date user : responseUserDocument approved : boolean + application : string + update_at : Date } \ No newline at end of file diff --git a/store/modules/auth.ts b/store/modules/auth.ts index 79c2f24..7269f81 100644 --- a/store/modules/auth.ts +++ b/store/modules/auth.ts @@ -1,12 +1,15 @@ import { ActionTree, MutationTree, GetterTree, ActionContext } from 'vuex' import { RootState } from 'store' +import { uniq } from 'lodash' import { responseDocument } from '~/server/types/proxys/user' export const name = 'auth' export const types = { - SET: 'SET' + SET: 'SET', + EMAIL: 'EMAIL', + MOBILE: 'MOBILE' } export interface State { @@ -34,8 +37,18 @@ export const actions: Actions = { } export const mutations: MutationTree = { - [types.SET] (state: State, user: responseDocument | null) { + [types.SET] (state: State, user: responseDocument | null): void { state.user = user state.token = user && user.jw_token ? user.jw_token : null + }, + [types.EMAIL] (state: State, email: string): void { + if (!state.user) return + state.user.email = email + state.user.binds = uniq(state.user.binds.concat('email')) + }, + [types.MOBILE] (state: State, mobile: string): void { + if (!state.user) return + state.user.mobile = mobile + state.user.binds = uniq(state.user.binds.concat('mobile')) } } \ No newline at end of file diff --git a/types/index.d.ts b/types/index.d.ts index fd6e92f..c6b9e07 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -31,6 +31,7 @@ export declare namespace Security { type statusType = 'success' | 'warning' | 'info' type statusIcon = 'el-icon-success success' | 'el-icon-warning warning' | 'el-icon-info info' + type viewType = 'password' | 'email' | 'mobile' | 'overview' interface Overview { key : string @@ -52,4 +53,24 @@ export declare namespace Security { value ?: string format ?: (value: string) => string } + + interface sendCode { + type : 'email' | 'mobile' + name ?: string + verify_id ?: string + } + + interface verifyCode { + code : string + } + + interface setEmail { + email ?: string + code ?: string + } + + interface setMobile { + mobile ?: string + code ?: string + } } \ No newline at end of file