From a652900c633838fd67df8527eeda3450940a6f7c Mon Sep 17 00:00:00 2001 From: linju Date: Wed, 19 Oct 2022 14:35:24 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E6=9B=B4=E6=96=B0=E4=BE=9D=E8=B5=96?= =?UTF-8?q?=E7=9A=84=E7=9A=84=E7=89=88=E6=9C=AC=E4=B8=BA1.0.26?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App.vue | 7 +- changelog.md | 2 + common/appInit.js | 34 +- manifest.json | 3 + uni-starter.config.js | 4 +- uni_modules/uni-easyinput/changelog.md | 4 + .../uni-easyinput/uni-easyinput.vue | 31 +- uni_modules/uni-easyinput/package.json | 2 +- uni_modules/uni-id-pages/changelog.md | 152 +- uni_modules/uni-id-pages/common/password.js | 2 +- uni_modules/uni-id-pages/common/store.js | 110 +- .../uni-id-pages-email-form.vue | 492 ++--- .../uni-id-pages-fab-login.vue | 154 +- .../uni-id-pages-user-profile.vue | 352 ++-- uni_modules/uni-id-pages/init.js | 17 +- uni_modules/uni-id-pages/package.json | 2 +- .../pages/common/webview/webview.vue | 80 +- .../pages/login/login-smscode.vue | 244 +-- .../pages/login/login-withoutpwd.vue | 433 ++--- .../pages/register/register-admin.vue | 358 ++-- .../pages/register/register-by-email.vue | 432 ++--- .../uni-id-pages/pages/register/register.vue | 5 +- .../pages/retrieve/retrieve-by-email.vue | 446 ++--- .../uni-id-pages/pages/retrieve/retrieve.vue | 492 ++--- .../userinfo/bind-mobile/bind-mobile.vue | 260 +-- .../pages/userinfo/cropImage/cropImage.vue | 76 +- .../userinfo/cropImage/limeClipper/README.md | 452 ++--- .../cropImage/limeClipper/images/photo.svg | 38 +- .../cropImage/limeClipper/images/rotate.svg | 30 +- .../userinfo/cropImage/limeClipper/index.css | 320 ++-- .../cropImage/limeClipper/limeClipper.vue | 1630 ++++++++--------- .../uni-id-pages/pages/userinfo/userinfo.vue | 471 ++--- uni_modules/uni-id-pages/readme.md | 28 +- .../uni-id-pages/static/limeClipper/photo.svg | 38 +- .../static/limeClipper/rotate.svg | 30 +- .../uni-id-pages/static/login/weixin.png | Bin 13348 -> 13060 bytes .../uni-id-co/common/constants.js | 170 +- .../cloudfunctions/uni-id-co/common/error.js | 109 +- .../cloudfunctions/uni-id-co/common/utils.js | 387 ++-- .../uni-id-co/common/validator.js | 864 ++++----- .../uni-id-co/config/permission.js | 144 +- .../cloudfunctions/uni-id-co/index.obj.js | 47 +- .../cloudfunctions/uni-id-co/lang/en.js | 93 +- .../cloudfunctions/uni-id-co/lang/index.js | 44 +- .../cloudfunctions/uni-id-co/lang/zh-hans.js | 93 +- .../cloudfunctions/uni-id-co/lib/README.md | 4 +- .../lib/third-party/alipay/account/index.js | 32 +- .../third-party/alipay/account/protocols.js | 20 +- .../lib/third-party/alipay/alipayBase.js | 462 ++--- .../lib/third-party/apple/account/index.js | 152 +- .../third-party/apple/rsa-public-key-pem.js | 128 +- .../uni-id-co/lib/third-party/index.js | 72 +- .../lib/third-party/qq/account/index.js | 194 +- .../uni-id-co/lib/third-party/qq/normalize.js | 170 +- .../lib/third-party/share/create-api.js | 146 +- .../lib/third-party/weixin/account/index.js | 200 +- .../lib/third-party/weixin/normalize.js | 190 +- .../uni-id-co/lib/third-party/weixin/utils.js | 174 +- .../uni-id-co/lib/utils/account.js | 260 +-- .../uni-id-co/lib/utils/captcha.js | 152 +- .../uni-id-co/lib/utils/config.js | 270 +-- .../uni-id-co/lib/utils/fission.js | 384 ++-- .../uni-id-co/lib/utils/login.js | 463 ++--- .../uni-id-co/lib/utils/logout.js | 92 +- .../uni-id-co/lib/utils/password.js | 232 +-- .../cloudfunctions/uni-id-co/lib/utils/qq.js | 304 +-- .../uni-id-co/lib/utils/register.js | 422 ++--- .../uni-id-co/lib/utils/relate.js | 224 ++- .../cloudfunctions/uni-id-co/lib/utils/sms.js | 162 +- .../uni-id-co/lib/utils/unified-login.js | 196 +- .../uni-id-co/lib/utils/univerify.js | 54 +- .../uni-id-co/lib/utils/update-user-info.js | 50 +- .../uni-id-co/lib/utils/verify-code.js | 304 +-- .../uni-id-co/lib/utils/weixin.js | 384 ++-- .../uni-id-co/middleware/access-control.js | 118 +- .../uni-id-co/middleware/auth.js | 34 +- .../uni-id-co/middleware/index.js | 14 +- .../uni-id-co/middleware/rbac.js | 78 +- .../uni-id-co/middleware/uni-id-log.js | 78 +- .../uni-id-co/middleware/validate.js | 14 +- .../uni-id-co/module/account/close-account.js | 32 +- .../module/account/get-account-info.js | 138 +- .../uni-id-co/module/account/index.js | 14 +- .../module/account/reset-pwd-by-email.js | 238 +-- .../uni-id-co/module/admin/add-user.js | 236 +-- .../uni-id-co/module/admin/index.js | 8 +- .../module/dev/get-supported-login-type.js | 142 +- .../uni-id-co/module/dev/index.js | 6 +- .../uni-id-co/module/fission/accept-invite.js | 50 +- .../module/fission/get-invited-user.js | 160 +- .../uni-id-co/module/fission/index.js | 8 +- .../uni-id-co/module/login/index.js | 39 +- .../uni-id-co/module/login/login-by-alipay.js | 140 +- .../uni-id-co/module/login/login-by-apple.js | 154 +- .../uni-id-co/module/login/login-by-baidu.js | 18 +- .../module/login/login-by-dingtalk.js | 18 +- .../uni-id-co/module/login/login-by-douyin.js | 18 +- .../module/login/login-by-email-code.js | 18 +- .../module/login/login-by-email-link.js | 18 +- .../module/login/login-by-facebook.js | 18 +- .../uni-id-co/module/login/login-by-google.js | 18 +- .../uni-id-co/module/login/login-by-qq.js | 328 ++-- .../uni-id-co/module/login/login-by-taobao.js | 18 +- .../module/login/login-by-toutiao.js | 18 +- .../module/login/login-by-univerify.js | 138 +- .../uni-id-co/module/login/login-by-weibo.js | 18 +- .../module/login/login-by-weixin-mobile.js | 109 ++ .../uni-id-co/module/login/login-by-weixin.js | 308 ++-- .../uni-id-co/module/login/login.js | 188 +- .../uni-id-co/module/logout/index.js | 6 +- .../uni-id-co/module/logout/logout.js | 30 +- .../module/multi-end/authorize-app-login.js | 74 +- .../uni-id-co/module/multi-end/index.js | 10 +- .../module/multi-end/remove-authorized-app.js | 60 +- .../module/multi-end/set-authorized-app.js | 72 +- .../uni-id-co/module/multi-end/utils.js | 72 +- .../uni-id-co/module/register/index.js | 10 +- .../module/register/register-admin.js | 134 +- .../module/register/register-user-by-email.js | 174 +- .../uni-id-co/module/relate/bind-alipay.js | 126 +- .../uni-id-co/module/relate/bind-apple.js | 124 +- .../module/relate/bind-mobile-by-mp-weixin.js | 65 +- .../module/relate/bind-mobile-by-univerify.js | 140 +- .../uni-id-co/module/relate/bind-qq.js | 220 +-- .../uni-id-co/module/relate/bind-weixin.js | 200 +- .../uni-id-co/module/relate/index.js | 22 +- .../uni-id-co/module/relate/unbind-alipay.js | 32 + .../uni-id-co/module/relate/unbind-apple.js | 32 + .../uni-id-co/module/relate/unbind-qq.js | 46 + .../uni-id-co/module/relate/unbind-weixin.js | 40 + .../uni-id-co/module/utils/index.js | 8 +- .../uni-id-co/module/utils/refresh-token.js | 38 +- .../uni-id-co/module/utils/set-push-cid.js | 282 +-- .../uni-id-co/module/verify/create-captcha.js | 68 +- .../uni-id-co/module/verify/index.js | 14 +- .../module/verify/refresh-captcha.js | 68 +- .../module/verify/send-email-code.js | 120 +- .../module/verify/send-email-link.js | 24 +- .../uni-id-co/module/verify/send-sms-code.js | 142 +- .../cloudfunctions/uni-id-co/package.json | 36 +- .../database/opendb-device.schema.json | 282 +-- .../database/uni-id-device.schema.json | 164 +- .../uniCloud/database/uni-id-log.schema.json | 142 +- .../database/uni-id-permissions.schema.json | 104 +- .../database/uni-id-roles.schema.json | 100 +- .../database/uni-id-users.schema.json | 154 +- 146 files changed, 11043 insertions(+), 10423 deletions(-) create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin-mobile.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-alipay.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-apple.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-qq.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-weixin.js diff --git a/App.vue b/App.vue index bc02d158..e3f3a825 100644 --- a/App.vue +++ b/App.vue @@ -5,6 +5,7 @@ openApp() //创建在h5端全局悬浮引导用户下载app的功能 // #endif import checkIsAgree from '@/pages/uni-agree/utils/uni-agree.js'; + import uniIdPageInit from '@/uni_modules/uni-id-pages/init.js'; export default { globalData: { searchText: '', @@ -17,9 +18,11 @@ console.log('App Launch') this.globalData.$i18n = this.$i18n this.globalData.$t = str => this.$t(str) - - initApp(); + console.log('uni.getPushClientId',uni.getPushClientId); + + initApp(); + uniIdPageInit() // #ifdef APP-PLUS //checkIsAgree(); APP端暂时先用原生默认生成的。目前,自定义方式启动vue界面时,原生层已经请求了部分权限这并不符合国家的法规 diff --git a/changelog.md b/changelog.md index 91584bfe..39160070 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,5 @@ +## 2.0.5(2022-10-19) +- 更新依赖的`uni-id-pages`的版本为1.0.26 ## 2.0.4(2022-09-21) - 新增 使用uni-id-pages的账号信息的状态管理功能 ## 2.0.3(2022-09-20) diff --git a/common/appInit.js b/common/appInit.js index 9b0ac07b..0e9bf7fe 100644 --- a/common/appInit.js +++ b/common/appInit.js @@ -47,11 +47,11 @@ export default async function() { methodName, // 云对象的方法名称 params // 参数列表 }) { - console.log('interceptObject',{ - objectName, // 云对象名称 - methodName, // 云对象的方法名称 - params // 参数列表 - }); + // console.log('interceptObject',{ + // objectName, // 云对象名称 + // methodName, // 云对象的方法名称 + // params // 参数列表 + // }); if(objectName == "uni-id-co" && (methodName.includes('loginBy') || ['login','registerUser'].includes(methodName) )){ console.log('执行登录相关云对象'); params[0].inviteCode = await new Promise((callBack) => { @@ -84,7 +84,7 @@ export default async function() { }) // console.log(params); } - console.log(params); + // console.log(params); }, success(e) { console.log(e); @@ -94,17 +94,17 @@ export default async function() { }, fail(e){ console.error(e); - if (debug) { - uni.showModal({ - content: JSON.stringify(e), - showCancel: false - }); - }else{ - uni.showToast({ - title: '系统错误请稍后再试', - icon:'error' - }); - } + // if (debug) { + // uni.showModal({ + // content: JSON.stringify(e), + // showCancel: false + // }); + // }else{ + // uni.showToast({ + // title: '系统错误请稍后再试', + // icon:'error' + // }); + // } } }) diff --git a/manifest.json b/manifest.json index 9e064240..da54b188 100644 --- a/manifest.json +++ b/manifest.json @@ -40,6 +40,9 @@ "ios": { }, "sdkConfigs": { + "push": { + "unipush": null + } } } }, diff --git a/uni-starter.config.js b/uni-starter.config.js index dbe202ae..7825630b 100644 --- a/uni-starter.config.js +++ b/uni-starter.config.js @@ -1,7 +1,5 @@ //这是应用的配置页面,App.vue挂载到getApp().globalData.config export default { - //是否打开调试模式 - "debug":false, "h5": { "url": "https://uni-starter.dcloud.net.cn", // 前端网页托管的域名 // 在h5端全局悬浮引导用户下载app的功能 更多自定义要求在/common/openApp.js中修改 @@ -17,7 +15,7 @@ export default { "mp": { "weixin": { //微信小程序原始id,微信小程序分享时 - "id": "gh_33446d7f7a26" + "id": "" } }, //关于应用 diff --git a/uni_modules/uni-easyinput/changelog.md b/uni_modules/uni-easyinput/changelog.md index 74b72690..33130c66 100644 --- a/uni_modules/uni-easyinput/changelog.md +++ b/uni_modules/uni-easyinput/changelog.md @@ -1,3 +1,7 @@ +## 1.1.3(2022-09-22) +- 修复,引入 uni.scss 引入默认主题色报错的问题 +## 1.1.2(2022-09-22) +- 增加主题色 primaryColor 配置选项 ## 1.1.1(2022-09-19) - 修复,输入后回车,change 事件触发两次,[详情](https://ask.dcloud.net.cn/question/152149) ## 1.1.0(2022-06-30) diff --git a/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue b/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue index a1250dd6..fdc023a4 100644 --- a/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue +++ b/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue @@ -18,7 +18,7 @@ + :color="focusShow ? primaryColor :'#c0c4cc'" @click="onEyes"> - - + + + + + diff --git a/uni_modules/uni-id-pages/init.js b/uni_modules/uni-id-pages/init.js index b1b3d1f0..e89b0dc2 100644 --- a/uni_modules/uni-id-pages/init.js +++ b/uni_modules/uni-id-pages/init.js @@ -34,7 +34,7 @@ export default async function() { google: 'google', alipay: 'alipay', apple: "apple" - } + } //遍历客户端配置的登录方式,与服务端比对。并在错误时抛出错误提示 let list = loginTypes.filter(type => !supportedLoginType.includes(data[type])) if (list.length) { @@ -55,7 +55,8 @@ export default async function() { }) } // #endif - + +/* 注释此代码块原因:与uni-starter中的appinit逻辑一致 //3. 绑定clientDB错误事件 // clientDB对象 const db = uniCloud.database() @@ -72,9 +73,9 @@ export default async function() { } // 解绑clientDB错误事件 //db.off('error', onDBError) +*/ - - //4. 同步客户端push_clientid至device表 + //4. 同步客户端push_clientid至uni-id-device表 if (uniCloud.onRefreshToken) { uniCloud.onRefreshToken(() => { console.log('onRefreshToken'); @@ -90,10 +91,14 @@ export default async function() { console.log('getPushClientId', res); }, fail(e) { - console.log(e) + console.error(e, + "uni-id-pages 默认在刷新token(登录、注销、切换用户)后获取push客户端标识同步至uni-id-device表;", + "\n", + "如果你不使用push模块,请注释或删除,路径:/uni-starter/uni_modules/uni-id-pages/init.js 第79-103行代码" + ) } }) } }) - } + } } diff --git a/uni_modules/uni-id-pages/package.json b/uni_modules/uni-id-pages/package.json index 03c9393c..4f013830 100644 --- a/uni_modules/uni-id-pages/package.json +++ b/uni_modules/uni-id-pages/package.json @@ -1,7 +1,7 @@ { "id": "uni-id-pages", "displayName": "uni-id-pages", - "version": "1.0.21", + "version": "1.0.26", "description": "云端一体简单、统一、可扩展的用户中心页面模版", "keywords": [ "用户管理", diff --git a/uni_modules/uni-id-pages/pages/common/webview/webview.vue b/uni_modules/uni-id-pages/pages/common/webview/webview.vue index 83d07ec7..ce78dd2e 100644 --- a/uni_modules/uni-id-pages/pages/common/webview/webview.vue +++ b/uni_modules/uni-id-pages/pages/common/webview/webview.vue @@ -1,40 +1,40 @@ - - - - - - + + + + + + diff --git a/uni_modules/uni-id-pages/pages/login/login-smscode.vue b/uni_modules/uni-id-pages/pages/login/login-smscode.vue index df67bc48..ec00e5d5 100644 --- a/uni_modules/uni-id-pages/pages/login/login-smscode.vue +++ b/uni_modules/uni-id-pages/pages/login/login-smscode.vue @@ -1,122 +1,122 @@ - - - - + + + + diff --git a/uni_modules/uni-id-pages/pages/login/login-withoutpwd.vue b/uni_modules/uni-id-pages/pages/login/login-withoutpwd.vue index a4e1804d..785a45c5 100644 --- a/uni_modules/uni-id-pages/pages/login/login-withoutpwd.vue +++ b/uni_modules/uni-id-pages/pages/login/login-withoutpwd.vue @@ -1,212 +1,221 @@ - - - - - - + + + + + + diff --git a/uni_modules/uni-id-pages/pages/register/register-admin.vue b/uni_modules/uni-id-pages/pages/register/register-admin.vue index 71690d95..df96425c 100644 --- a/uni_modules/uni-id-pages/pages/register/register-admin.vue +++ b/uni_modules/uni-id-pages/pages/register/register-admin.vue @@ -1,179 +1,179 @@ - - - - - - + + + + + + diff --git a/uni_modules/uni-id-pages/pages/register/register-by-email.vue b/uni_modules/uni-id-pages/pages/register/register-by-email.vue index f45dc57a..a6cf62c5 100644 --- a/uni_modules/uni-id-pages/pages/register/register-by-email.vue +++ b/uni_modules/uni-id-pages/pages/register/register-by-email.vue @@ -1,216 +1,216 @@ - - - - - - + + + + + + diff --git a/uni_modules/uni-id-pages/pages/register/register.vue b/uni_modules/uni-id-pages/pages/register/register.vue index 28c5d12a..e769f346 100644 --- a/uni_modules/uni-id-pages/pages/register/register.vue +++ b/uni_modules/uni-id-pages/pages/register/register.vue @@ -53,9 +53,6 @@ mutations } from '@/uni_modules/uni-id-pages/common/store.js' - const { - loginSuccess - } = mutations const uniIdCo = uniCloud.importObject("uni-id-co") export default { mixins: [mixin], @@ -118,7 +115,7 @@ submitForm(params) { uniIdCo.registerUser(this.formData).then(e => { console.log(e); - loginSuccess() + this.loginSuccess(e) }) .catch(e => { console.log(e); diff --git a/uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email.vue b/uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email.vue index 71ca8fe7..d2333983 100644 --- a/uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email.vue +++ b/uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email.vue @@ -1,223 +1,223 @@ - - - - - - + + + + + + diff --git a/uni_modules/uni-id-pages/pages/retrieve/retrieve.vue b/uni_modules/uni-id-pages/pages/retrieve/retrieve.vue index 74ed220c..f1a17c32 100644 --- a/uni_modules/uni-id-pages/pages/retrieve/retrieve.vue +++ b/uni_modules/uni-id-pages/pages/retrieve/retrieve.vue @@ -1,246 +1,246 @@ - - - - - - + + + + + + diff --git a/uni_modules/uni-id-pages/pages/userinfo/bind-mobile/bind-mobile.vue b/uni_modules/uni-id-pages/pages/userinfo/bind-mobile/bind-mobile.vue index 15d68ebf..67442efd 100644 --- a/uni_modules/uni-id-pages/pages/userinfo/bind-mobile/bind-mobile.vue +++ b/uni_modules/uni-id-pages/pages/userinfo/bind-mobile/bind-mobile.vue @@ -1,130 +1,130 @@ - - - - - + + + + + diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/cropImage.vue b/uni_modules/uni-id-pages/pages/userinfo/cropImage/cropImage.vue index 0a9e7017..3c2d9896 100644 --- a/uni_modules/uni-id-pages/pages/userinfo/cropImage/cropImage.vue +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/cropImage.vue @@ -1,39 +1,39 @@ - - - - - \ No newline at end of file diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/README.md b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/README.md index 9219f815..160c207d 100644 --- a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/README.md +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/README.md @@ -1,227 +1,227 @@ -> 插件来源:[https://ext.dcloud.net.cn/plugin?id=3594](https://ext.dcloud.net.cn/plugin?id=3594) -##### 以下是作者写的插件介绍: - -# Clipper 图片裁剪 -> uniapp 图片裁剪,可用于图片头像等裁剪处理 -> [查看更多](http://liangei.gitee.io/limeui/#/clipper)
-> Q群:458377637 - - -## 平台兼容 - -| H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ 小程序 | App | -| --- | ---------- | ------------ | ---------- | ---------- | --------- | --- | -| √ | √ | √ | 未测 | √ | √ | √ | - - -## 代码演示 -### 基本用法 -`@success` 事件点击 👉 **确定** 后会返回生成的图片信息,包含 `url`、`width`、`height` - -```html - - - -``` - -```js -// 非uni_modules引入 -import lClipper from '@/components/lime-clipper/' -// uni_modules引入 -import lClipper from '@/uni_modules/lime-clipper/components/lime-clipper/' -export default { - components: {lClipper}, - data() { - return { - show: false, - url: '', - } - } -} -``` - - -### 传入图片 -`image-url`可传入**相对路径**、**临时路径**、**本地路径**、**网络图片**
- -* **当为网络地址时** -* H5:👉 需要解决跨域问题。
-* 小程序:👉 需要配置 downloadFile 域名
- - -```html - - - -``` - -```js -export default { - components: {lClipper}, - data() { - return { - imageUrl: 'https://img12.360buyimg.com/pop/s1180x940_jfs/t1/97205/26/1142/87801/5dbac55aEf795d962/48a4d7a63ff80b8b.jpg', - show: false, - url: '', - } - } -} -``` - - -### 确定按钮颜色 -样式变量名:`--l-clipper-confirm-color` -可放到全局样式的 `page` 里或节点的 `style` -```html - -``` -```css -// css 中为组件设置 CSS 变量 -.clipper { - --l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24) -} -// 全局 -page { - --l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24) -} -``` - - -### 使用插槽 -共五个插槽 `cancel` 取消按钮、 `photo` 选择图片按钮、 `rotate` 旋转按钮、 `confirm` 确定按钮和默认插槽。 - -```html - - - - 取消 - 选择图片 - 旋转 - 确定 - - - 显示取消按钮 - - - 显示选择图片按钮 - - - 显示旋转按钮 - - - 显示确定按钮 - - - 锁定裁剪框宽度 - - - 锁定裁剪框高度 - - - 锁定裁剪框比例 - - - 限制移动范围 - - - 禁止缩放 - - - 禁止旋转 - - - - - -``` - -```js -export default { - components: {lClipper}, - data() { - return { - show: false, - url: '', - isLockWidth: false, - isLockHeight: false, - isLockRatio: true, - isLimitMove: false, - isDisableScale: false, - isDisableRotate: false, - isShowCancelBtn: true, - isShowPhotoBtn: true, - isShowRotateBtn: true, - isShowConfirmBtn: true - } - } -} -``` - - -## API - -### Props - -| 参数 | 说明 | 类型 | 默认值 | -| ------------- | ------------ | ---------------- | ------------ | -| image-url | 图片路径 | string | | -| quality | 图片的质量,取值范围为 [0, 1],不在范围内时当作1处理 | number | `1` | -| source | `{album: '从相册中选择'}`key为图片来源类型,value为选项说明 | Object | | -| width | 裁剪框宽度,单位为 `rpx` | number | `400` | -| height | 裁剪框高度 | number | `400` | -| min-width | 裁剪框最小宽度 | number | `200` | -| min-height |裁剪框最小高度 | number | `200` | -| max-width | 裁剪框最大宽度 | number | `600` | -| max-height | 裁剪框最大宽度 | number | `600` | -| min-ratio | 图片最小缩放比 | number | `0.5` | -| max-ratio | 图片最大缩放比 | number | `2` | -| rotate-angle | 旋转按钮每次旋转的角度 | number | `90` | -| scale-ratio | 生成图片相对于裁剪框的比例, **比例越高生成图片越清晰** | number | `1` | -| is-lock-width | 是否锁定裁剪框宽度 | boolean | `false` | -| is-lock-height | 是否锁定裁剪框高度上 | boolean | `false` | -| is-lock-ratio | 是否锁定裁剪框比例 | boolean | `true` | -| is-disable-scale | 是否禁止缩放 | boolean | `false` | -| is-disable-rotate | 是否禁止旋转 | boolean | `false` | -| is-limit-move | 是否限制移动范围 | boolean | `false` | -| is-show-photo-btn | 是否显示选择图片按钮 | boolean | `true` | -| is-show-rotate-btn | 是否显示转按钮 | boolean | `true` | -| is-show-confirm-btn | 是否显示确定按钮 | boolean | `true` | -| is-show-cancel-btn | 是否显示关闭按钮 | boolean | `true` | - - - -### 事件 Events - -| 事件名 | 说明 | 回调 | -| ------- | ------------ | -------------- | -| success | 生成图片成功 | {`width`, `height`, `url`} | -| fail | 生成图片失败 | `error` | -| cancel | 关闭 | `false` | -| ready | 图片加载完成 | {`width`, `height`, `path`, `orientation`, `type`} | -| change | 图片大小改变时触发 | {`width`, `height`} | -| rotate | 图片旋转时触发 | `angle` | - -## 常见问题 -> 1、H5端使用网络图片需要解决跨域问题。
-> 2、小程序使用网络图片需要去公众平台增加下载白名单!二级域名也需要配!
-> 3、H5端生成图片是base64,有时显示只有一半可以使用原生标签``
-> 4、IOS APP 请勿使用HBX2.9.3.20201014的版本!这个版本无法生成图片。
-> 5、APP端无成功反馈、也无失败反馈时,请更新基座和HBX。
- - -## 打赏 -如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
+> 插件来源:[https://ext.dcloud.net.cn/plugin?id=3594](https://ext.dcloud.net.cn/plugin?id=3594) +##### 以下是作者写的插件介绍: + +# Clipper 图片裁剪 +> uniapp 图片裁剪,可用于图片头像等裁剪处理 +> [查看更多](http://liangei.gitee.io/limeui/#/clipper)
+> Q群:458377637 + + +## 平台兼容 + +| H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ 小程序 | App | +| --- | ---------- | ------------ | ---------- | ---------- | --------- | --- | +| √ | √ | √ | 未测 | √ | √ | √ | + + +## 代码演示 +### 基本用法 +`@success` 事件点击 👉 **确定** 后会返回生成的图片信息,包含 `url`、`width`、`height` + +```html + + + +``` + +```js +// 非uni_modules引入 +import lClipper from '@/components/lime-clipper/' +// uni_modules引入 +import lClipper from '@/uni_modules/lime-clipper/components/lime-clipper/' +export default { + components: {lClipper}, + data() { + return { + show: false, + url: '', + } + } +} +``` + + +### 传入图片 +`image-url`可传入**相对路径**、**临时路径**、**本地路径**、**网络图片**
+ +* **当为网络地址时** +* H5:👉 需要解决跨域问题。
+* 小程序:👉 需要配置 downloadFile 域名
+ + +```html + + + +``` + +```js +export default { + components: {lClipper}, + data() { + return { + imageUrl: 'https://img12.360buyimg.com/pop/s1180x940_jfs/t1/97205/26/1142/87801/5dbac55aEf795d962/48a4d7a63ff80b8b.jpg', + show: false, + url: '', + } + } +} +``` + + +### 确定按钮颜色 +样式变量名:`--l-clipper-confirm-color` +可放到全局样式的 `page` 里或节点的 `style` +```html + +``` +```css +// css 中为组件设置 CSS 变量 +.clipper { + --l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24) +} +// 全局 +page { + --l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24) +} +``` + + +### 使用插槽 +共五个插槽 `cancel` 取消按钮、 `photo` 选择图片按钮、 `rotate` 旋转按钮、 `confirm` 确定按钮和默认插槽。 + +```html + + + + 取消 + 选择图片 + 旋转 + 确定 + + + 显示取消按钮 + + + 显示选择图片按钮 + + + 显示旋转按钮 + + + 显示确定按钮 + + + 锁定裁剪框宽度 + + + 锁定裁剪框高度 + + + 锁定裁剪框比例 + + + 限制移动范围 + + + 禁止缩放 + + + 禁止旋转 + + + + + +``` + +```js +export default { + components: {lClipper}, + data() { + return { + show: false, + url: '', + isLockWidth: false, + isLockHeight: false, + isLockRatio: true, + isLimitMove: false, + isDisableScale: false, + isDisableRotate: false, + isShowCancelBtn: true, + isShowPhotoBtn: true, + isShowRotateBtn: true, + isShowConfirmBtn: true + } + } +} +``` + + +## API + +### Props + +| 参数 | 说明 | 类型 | 默认值 | +| ------------- | ------------ | ---------------- | ------------ | +| image-url | 图片路径 | string | | +| quality | 图片的质量,取值范围为 [0, 1],不在范围内时当作1处理 | number | `1` | +| source | `{album: '从相册中选择'}`key为图片来源类型,value为选项说明 | Object | | +| width | 裁剪框宽度,单位为 `rpx` | number | `400` | +| height | 裁剪框高度 | number | `400` | +| min-width | 裁剪框最小宽度 | number | `200` | +| min-height |裁剪框最小高度 | number | `200` | +| max-width | 裁剪框最大宽度 | number | `600` | +| max-height | 裁剪框最大宽度 | number | `600` | +| min-ratio | 图片最小缩放比 | number | `0.5` | +| max-ratio | 图片最大缩放比 | number | `2` | +| rotate-angle | 旋转按钮每次旋转的角度 | number | `90` | +| scale-ratio | 生成图片相对于裁剪框的比例, **比例越高生成图片越清晰** | number | `1` | +| is-lock-width | 是否锁定裁剪框宽度 | boolean | `false` | +| is-lock-height | 是否锁定裁剪框高度上 | boolean | `false` | +| is-lock-ratio | 是否锁定裁剪框比例 | boolean | `true` | +| is-disable-scale | 是否禁止缩放 | boolean | `false` | +| is-disable-rotate | 是否禁止旋转 | boolean | `false` | +| is-limit-move | 是否限制移动范围 | boolean | `false` | +| is-show-photo-btn | 是否显示选择图片按钮 | boolean | `true` | +| is-show-rotate-btn | 是否显示转按钮 | boolean | `true` | +| is-show-confirm-btn | 是否显示确定按钮 | boolean | `true` | +| is-show-cancel-btn | 是否显示关闭按钮 | boolean | `true` | + + + +### 事件 Events + +| 事件名 | 说明 | 回调 | +| ------- | ------------ | -------------- | +| success | 生成图片成功 | {`width`, `height`, `url`} | +| fail | 生成图片失败 | `error` | +| cancel | 关闭 | `false` | +| ready | 图片加载完成 | {`width`, `height`, `path`, `orientation`, `type`} | +| change | 图片大小改变时触发 | {`width`, `height`} | +| rotate | 图片旋转时触发 | `angle` | + +## 常见问题 +> 1、H5端使用网络图片需要解决跨域问题。
+> 2、小程序使用网络图片需要去公众平台增加下载白名单!二级域名也需要配!
+> 3、H5端生成图片是base64,有时显示只有一半可以使用原生标签``
+> 4、IOS APP 请勿使用HBX2.9.3.20201014的版本!这个版本无法生成图片。
+> 5、APP端无成功反馈、也无失败反馈时,请更新基座和HBX。
+ + +## 打赏 +如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
![输入图片说明](https://images.gitee.com/uploads/images/2020/1122/222521_bb543f96_518581.jpeg "微信图片编辑_20201122220352.jpg") \ No newline at end of file diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/photo.svg b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/photo.svg index 7b4b5905..4fd415f2 100644 --- a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/photo.svg +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/photo.svg @@ -1,19 +1,19 @@ - - - - - - - - - + + + + + + + + + diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/rotate.svg b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/rotate.svg index 0143706c..4cc7dbae 100644 --- a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/rotate.svg +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/rotate.svg @@ -1,15 +1,15 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/index.css b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/index.css index ce542bf1..3794573a 100644 --- a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/index.css +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/index.css @@ -1,160 +1,160 @@ -.flex-auto { - flex: auto; -} -.bg-transparent { - background-color: rgba(0,0,0,0.9); - transition-duration: 0.35s; -} -.l-clipper { - width: 100vw; - height: calc(100vh - var(--window-top)); - background-color: rgba(0,0,0,0.9); - position: fixed; - top: var(--window-top); - left: 0; - z-index: 1; -} -.l-clipper-mask { - position: relative; - z-index: 2; - pointer-events: none; -} -.l-clipper__content { - pointer-events: none; - position: absolute; - border: 1rpx solid rgba(255,255,255,0.3); - box-sizing: border-box; - box-shadow: rgba(0,0,0,0.5) 0 0 0 80vh; - background: transparent; -} -.l-clipper__content::before, -.l-clipper__content::after { - content: ''; - position: absolute; - border: 1rpx dashed rgba(255,255,255,0.3); -} -.l-clipper__content::before { - width: 100%; - top: 33.33%; - height: 33.33%; - border-left: none; - border-right: none; -} -.l-clipper__content::after { - width: 33.33%; - left: 33.33%; - height: 100%; - border-top: none; - border-bottom: none; -} -.l-clipper__edge { - position: absolute; - width: 34rpx; - height: 34rpx; - border: 6rpx solid #fff; - pointer-events: auto; -} -.l-clipper__edge::before { - content: ''; - position: absolute; - width: 40rpx; - height: 40rpx; - background-color: transparent; -} -.l-clipper__edge:nth-child(1) { - left: -6rpx; - top: -6rpx; - border-bottom-width: 0 !important; - border-right-width: 0 !important; -} -.l-clipper__edge:nth-child(1):before { - top: -50%; - left: -50%; -} -.l-clipper__edge:nth-child(2) { - right: -6rpx; - top: -6rpx; - border-bottom-width: 0 !important; - border-left-width: 0 !important; -} -.l-clipper__edge:nth-child(2):before { - top: -50%; - left: 50%; -} -.l-clipper__edge:nth-child(3) { - left: -6rpx; - bottom: -6rpx; - border-top-width: 0 !important; - border-right-width: 0 !important; -} -.l-clipper__edge:nth-child(3):before { - bottom: -50%; - left: -50%; -} -.l-clipper__edge:nth-child(4) { - right: -6rpx; - bottom: -6rpx; - border-top-width: 0 !important; - border-left-width: 0 !important; -} -.l-clipper__edge:nth-child(4):before { - bottom: -50%; - left: 50%; -} -.l-clipper-image { - width: 100%; - border-style: none; - position: absolute; - top: 0; - left: 0; - z-index: 1; - -webkit-backface-visibility: hidden; - backface-visibility: hidden; - transform-origin: center; -} -.l-clipper-canvas { - position: fixed; - z-index: 10; - left: -200vw; - top: -200vw; - pointer-events: none; -} -.l-clipper-tools { - position: fixed; - left: 0; - bottom: 10px; - width: 100%; - z-index: 99; - color: #fff; -} -.l-clipper-tools__btns { - font-weight: bold; - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - padding: 20rpx 40rpx; - box-sizing: border-box; -} -.l-clipper-tools__btns .cancel { - width: 112rpx; - height: 60rpx; - text-align: center; - line-height: 60rpx; -} -.l-clipper-tools__btns .confirm { - width: 112rpx; - height: 60rpx; - line-height: 60rpx; - background-color: #07c160; - border-radius: 6rpx; - text-align: center; -} -.l-clipper-tools__btns image { - display: block; - width: 60rpx; - height: 60rpx; -} -.l-clipper-tools__btns { - flex-direction: row; -} +.flex-auto { + flex: auto; +} +.bg-transparent { + background-color: rgba(0,0,0,0.9); + transition-duration: 0.35s; +} +.l-clipper { + width: 100vw; + height: calc(100vh - var(--window-top)); + background-color: rgba(0,0,0,0.9); + position: fixed; + top: var(--window-top); + left: 0; + z-index: 1; +} +.l-clipper-mask { + position: relative; + z-index: 2; + pointer-events: none; +} +.l-clipper__content { + pointer-events: none; + position: absolute; + border: 1rpx solid rgba(255,255,255,0.3); + box-sizing: border-box; + box-shadow: rgba(0,0,0,0.5) 0 0 0 80vh; + background: transparent; +} +.l-clipper__content::before, +.l-clipper__content::after { + content: ''; + position: absolute; + border: 1rpx dashed rgba(255,255,255,0.3); +} +.l-clipper__content::before { + width: 100%; + top: 33.33%; + height: 33.33%; + border-left: none; + border-right: none; +} +.l-clipper__content::after { + width: 33.33%; + left: 33.33%; + height: 100%; + border-top: none; + border-bottom: none; +} +.l-clipper__edge { + position: absolute; + width: 34rpx; + height: 34rpx; + border: 6rpx solid #fff; + pointer-events: auto; +} +.l-clipper__edge::before { + content: ''; + position: absolute; + width: 40rpx; + height: 40rpx; + background-color: transparent; +} +.l-clipper__edge:nth-child(1) { + left: -6rpx; + top: -6rpx; + border-bottom-width: 0 !important; + border-right-width: 0 !important; +} +.l-clipper__edge:nth-child(1):before { + top: -50%; + left: -50%; +} +.l-clipper__edge:nth-child(2) { + right: -6rpx; + top: -6rpx; + border-bottom-width: 0 !important; + border-left-width: 0 !important; +} +.l-clipper__edge:nth-child(2):before { + top: -50%; + left: 50%; +} +.l-clipper__edge:nth-child(3) { + left: -6rpx; + bottom: -6rpx; + border-top-width: 0 !important; + border-right-width: 0 !important; +} +.l-clipper__edge:nth-child(3):before { + bottom: -50%; + left: -50%; +} +.l-clipper__edge:nth-child(4) { + right: -6rpx; + bottom: -6rpx; + border-top-width: 0 !important; + border-left-width: 0 !important; +} +.l-clipper__edge:nth-child(4):before { + bottom: -50%; + left: 50%; +} +.l-clipper-image { + width: 100%; + border-style: none; + position: absolute; + top: 0; + left: 0; + z-index: 1; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + transform-origin: center; +} +.l-clipper-canvas { + position: fixed; + z-index: 10; + left: -200vw; + top: -200vw; + pointer-events: none; +} +.l-clipper-tools { + position: fixed; + left: 0; + bottom: 10px; + width: 100%; + z-index: 99; + color: #fff; +} +.l-clipper-tools__btns { + font-weight: bold; + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + padding: 20rpx 40rpx; + box-sizing: border-box; +} +.l-clipper-tools__btns .cancel { + width: 112rpx; + height: 60rpx; + text-align: center; + line-height: 60rpx; +} +.l-clipper-tools__btns .confirm { + width: 112rpx; + height: 60rpx; + line-height: 60rpx; + background-color: #07c160; + border-radius: 6rpx; + text-align: center; +} +.l-clipper-tools__btns image { + display: block; + width: 60rpx; + height: 60rpx; +} +.l-clipper-tools__btns { + flex-direction: row; +} diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/limeClipper.vue b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/limeClipper.vue index 9caae2dc..52f3bd9f 100644 --- a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/limeClipper.vue +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/limeClipper.vue @@ -1,816 +1,816 @@ - - - - - \ No newline at end of file diff --git a/uni_modules/uni-id-pages/pages/userinfo/userinfo.vue b/uni_modules/uni-id-pages/pages/userinfo/userinfo.vue index 2943265e..7852f45b 100644 --- a/uni_modules/uni-id-pages/pages/userinfo/userinfo.vue +++ b/uni_modules/uni-id-pages/pages/userinfo/userinfo.vue @@ -1,218 +1,253 @@ - - - - + + + + diff --git a/uni_modules/uni-id-pages/readme.md b/uni_modules/uni-id-pages/readme.md index 1650e459..1fa07263 100644 --- a/uni_modules/uni-id-pages/readme.md +++ b/uni_modules/uni-id-pages/readme.md @@ -1,15 +1,15 @@ -# 文档已移至uni-id-pages文档[https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html) - - - -关于插件更新的说明: - -所有uni_modules,在HBuilderX里点右键都可以直接升级。或者在插件市场导入覆盖。 - -覆盖时HBuilderX会弹出代码差异比对,可以决定接受哪些更改、拒绝哪些更改。 - -当拒绝局部修改时,注意可能产生兼容性问题。 - -你需要二次开发uni-id-pages的前端页面, -- 如果改动不大,那么每次更新uni-id-pages时,在HBuilderX的对比界面对比一下就好 +# 文档已移至uni-id-pages文档[https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html) + + + +关于插件更新的说明: + +所有uni_modules,在HBuilderX里点右键都可以直接升级。或者在插件市场导入覆盖。 + +覆盖时HBuilderX会弹出代码差异比对,可以决定接受哪些更改、拒绝哪些更改。 + +当拒绝局部修改时,注意可能产生兼容性问题。 + +你需要二次开发uni-id-pages的前端页面, +- 如果改动不大,那么每次更新uni-id-pages时,在HBuilderX的对比界面对比一下就好 - 如果改动较大,建议复制一套前端页面到自己工程的pages目录下,pages.json里只引用根目录pages下的页面,不引用uni_modules下的页面。然后每次uni-id-pages更新,你对比下比上一版uni-id-pages改了什么,看你是否需要再合并到你自己的pages里。pages.json里不引用uni_modules里的页面的话,打包时不会把这些页面打包进去,不影响发行后的包体积 \ No newline at end of file diff --git a/uni_modules/uni-id-pages/static/limeClipper/photo.svg b/uni_modules/uni-id-pages/static/limeClipper/photo.svg index 7b4b5905..4fd415f2 100644 --- a/uni_modules/uni-id-pages/static/limeClipper/photo.svg +++ b/uni_modules/uni-id-pages/static/limeClipper/photo.svg @@ -1,19 +1,19 @@ - - - - - - - - - + + + + + + + + + diff --git a/uni_modules/uni-id-pages/static/limeClipper/rotate.svg b/uni_modules/uni-id-pages/static/limeClipper/rotate.svg index 0143706c..4cc7dbae 100644 --- a/uni_modules/uni-id-pages/static/limeClipper/rotate.svg +++ b/uni_modules/uni-id-pages/static/limeClipper/rotate.svg @@ -1,15 +1,15 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/uni_modules/uni-id-pages/static/login/weixin.png b/uni_modules/uni-id-pages/static/login/weixin.png index 913a9d1d6959aef1b0efef8171f74f6878adfd37..6976b691fbeb313301bd55bb3e949722319c228c 100644 GIT binary patch delta 11525 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 delta 11792 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 diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/constants.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/constants.js index 0322db6a..1e44b98c 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/constants.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/constants.js @@ -1,83 +1,87 @@ -const db = uniCloud.database() -const dbCmd = db.command -const userCollectionName = 'uni-id-users' -const userCollection = db.collection(userCollectionName) -const verifyCollectionName = 'opendb-verify-codes' -const verifyCollection = db.collection(verifyCollectionName) -const deviceCollectionName = 'uni-id-device' -const deviceCollection = db.collection(deviceCollectionName) - -const USER_IDENTIFIER = { - username: 'username', - mobile: 'mobile', - email: 'email', - wx_unionid: 'wechat-account', - 'wx_openid.app': 'wechat-account', - 'wx_openid.mp': 'wechat-account', - 'wx_openid.h5': 'wechat-account', - 'wx_openid.web': 'wechat-account', - qq_unionid: 'qq-account', - 'qq_openid.app': 'qq-account', - 'qq_openid.mp': 'qq-account', - ali_openid: 'alipay-account', - apple_openid: 'alipay-account' -} - -const USER_STATUS = { - NORMAL: 0, - BANNED: 1, - AUDITING: 2, - AUDIT_FAILED: 3, - CLOSED: 4 -} - -const CAPTCHA_SCENE = { - REGISTER: 'register', - LOGIN_BY_PWD: 'login-by-pwd', - LOGIN_BY_SMS: 'login-by-sms', - RESET_PWD_BY_SMS: 'reset-pwd-by-sms', - RESET_PWD_BY_EMAIL: 'reset-pwd-by-email', - SEND_SMS_CODE: 'send-sms-code', - SEND_EMAIL_CODE: 'send-email-code', - BIND_MOBILE_BY_SMS: 'bind-mobile-by-sms' -} - -const LOG_TYPE = { - LOGOUT: 'logout', - LOGIN: 'login', - REGISTER: 'register', - RESET_PWD_BY_SMS: 'reset-pwd', - RESET_PWD_BY_EMAIL: 'reset-pwd', - BIND_MOBILE: 'bind-mobile', - BIND_WEIXIN: 'bind-weixin', - BIND_QQ: 'bind-qq', - BIND_APPLE: 'bind-apple', - BIND_ALIPAY: 'bind-alipay' -} - -const SMS_SCENE = { - LOGIN_BY_SMS: 'login-by-sms', - RESET_PWD_BY_SMS: 'reset-pwd-by-sms', - BIND_MOBILE_BY_SMS: 'bind-mobile-by-sms' -} - -const EMAIL_SCENE = { - REGISTER: 'register', - LOGIN_BY_EMAIL: 'login-by-email', - RESET_PWD_BY_EMAIL: 'reset-pwd-by-email', - BIND_EMAIL: 'bind-email' -} - -module.exports = { - db, - dbCmd, - userCollection, - verifyCollection, - deviceCollection, - USER_IDENTIFIER, - USER_STATUS, - CAPTCHA_SCENE, - LOG_TYPE, - SMS_SCENE, - EMAIL_SCENE -} +const db = uniCloud.database() +const dbCmd = db.command +const userCollectionName = 'uni-id-users' +const userCollection = db.collection(userCollectionName) +const verifyCollectionName = 'opendb-verify-codes' +const verifyCollection = db.collection(verifyCollectionName) +const deviceCollectionName = 'uni-id-device' +const deviceCollection = db.collection(deviceCollectionName) + +const USER_IDENTIFIER = { + username: 'username', + mobile: 'mobile', + email: 'email', + wx_unionid: 'wechat-account', + 'wx_openid.app': 'wechat-account', + 'wx_openid.mp': 'wechat-account', + 'wx_openid.h5': 'wechat-account', + 'wx_openid.web': 'wechat-account', + qq_unionid: 'qq-account', + 'qq_openid.app': 'qq-account', + 'qq_openid.mp': 'qq-account', + ali_openid: 'alipay-account', + apple_openid: 'alipay-account' +} + +const USER_STATUS = { + NORMAL: 0, + BANNED: 1, + AUDITING: 2, + AUDIT_FAILED: 3, + CLOSED: 4 +} + +const CAPTCHA_SCENE = { + REGISTER: 'register', + LOGIN_BY_PWD: 'login-by-pwd', + LOGIN_BY_SMS: 'login-by-sms', + RESET_PWD_BY_SMS: 'reset-pwd-by-sms', + RESET_PWD_BY_EMAIL: 'reset-pwd-by-email', + SEND_SMS_CODE: 'send-sms-code', + SEND_EMAIL_CODE: 'send-email-code', + BIND_MOBILE_BY_SMS: 'bind-mobile-by-sms' +} + +const LOG_TYPE = { + LOGOUT: 'logout', + LOGIN: 'login', + REGISTER: 'register', + RESET_PWD_BY_SMS: 'reset-pwd', + RESET_PWD_BY_EMAIL: 'reset-pwd', + BIND_MOBILE: 'bind-mobile', + BIND_WEIXIN: 'bind-weixin', + BIND_QQ: 'bind-qq', + BIND_APPLE: 'bind-apple', + BIND_ALIPAY: 'bind-alipay', + UNBIND_WEIXIN: 'unbind-weixin', + UNBIND_QQ: 'unbind-qq', + UNBIND_ALIPAY: 'unbind-alipay', + UNBIND_APPLE: 'unbind-apple' +} + +const SMS_SCENE = { + LOGIN_BY_SMS: 'login-by-sms', + RESET_PWD_BY_SMS: 'reset-pwd-by-sms', + BIND_MOBILE_BY_SMS: 'bind-mobile-by-sms' +} + +const EMAIL_SCENE = { + REGISTER: 'register', + LOGIN_BY_EMAIL: 'login-by-email', + RESET_PWD_BY_EMAIL: 'reset-pwd-by-email', + BIND_EMAIL: 'bind-email' +} + +module.exports = { + db, + dbCmd, + userCollection, + verifyCollection, + deviceCollection, + USER_IDENTIFIER, + USER_STATUS, + CAPTCHA_SCENE, + LOG_TYPE, + SMS_SCENE, + EMAIL_SCENE +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/error.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/error.js index 3095e5f7..ca08116e 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/error.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/error.js @@ -1,52 +1,57 @@ -const ERROR = { - ACCOUNT_EXISTS: 'uni-id-account-exists', - ACCOUNT_NOT_EXISTS: 'uni-id-account-not-exists', - ACCOUNT_CONFLICT: 'uni-id-account-conflict', - ACCOUNT_BANNED: 'uni-id-account-banned', - ACCOUNT_AUDITING: 'uni-id-account-auditing', - ACCOUNT_AUDIT_FAILED: 'uni-id-account-audit-failed', - ACCOUNT_CLOSED: 'uni-id-account-closed', - CAPTCHA_REQUIRED: 'uni-id-captcha-required', - PASSWORD_ERROR: 'uni-id-password-error', - PASSWORD_ERROR_EXCEED_LIMIT: 'uni-id-password-error-exceed-limit', - INVALID_USERNAME: 'uni-id-invalid-username', - INVALID_PASSWORD: 'uni-id-invalid-password', - INVALID_PASSWORD_SUPER: 'uni-id-invalid-password-super', - INVALID_PASSWORD_STRONG: 'uni-id-invalid-password-strong', - INVALID_PASSWORD_MEDIUM: 'uni-id-invalid-password-medium', - INVALID_PASSWORD_WEAK: 'uni-id-invalid-password-weak', - INVALID_MOBILE: 'uni-id-invalid-mobile', - INVALID_EMAIL: 'uni-id-invalid-email', - INVALID_NICKNAME: 'uni-id-invalid-nickname', - INVALID_PARAM: 'uni-id-invalid-param', - PARAM_REQUIRED: 'uni-id-param-required', - GET_THIRD_PARTY_ACCOUNT_FAILED: 'uni-id-get-third-party-account-failed', - GET_THIRD_PARTY_USER_INFO_FAILED: 'uni-id-get-third-party-user-info-failed', - MOBILE_VERIFY_CODE_ERROR: 'uni-id-mobile-verify-code-error', - EMAIL_VERIFY_CODE_ERROR: 'uni-id-email-verify-code-error', - ADMIN_EXISTS: 'uni-id-admin-exists', - PERMISSION_ERROR: 'uni-id-permission-error', - SYSTEM_ERROR: 'uni-id-system-error', - SET_INVITE_CODE_FAILED: 'uni-id-set-invite-code-failed', - INVALID_INVITE_CODE: 'uni-id-invalid-invite-code', - CHANGE_INVITER_FORBIDDEN: 'uni-id-change-inviter-forbidden', - BIND_CONFLICT: 'uni-id-bind-conflict' -} - -function isUniIdError (errCode) { - return Object.values(ERROR).includes(errCode) -} - -class UniCloudError extends Error { - constructor (options) { - super(options.message) - this.errMsg = options.message || '' - this.errCode = options.code - } -} - -module.exports = { - ERROR, - isUniIdError, - UniCloudError -} +const ERROR = { + ACCOUNT_EXISTS: 'uni-id-account-exists', + ACCOUNT_NOT_EXISTS: 'uni-id-account-not-exists', + ACCOUNT_CONFLICT: 'uni-id-account-conflict', + ACCOUNT_BANNED: 'uni-id-account-banned', + ACCOUNT_AUDITING: 'uni-id-account-auditing', + ACCOUNT_AUDIT_FAILED: 'uni-id-account-audit-failed', + ACCOUNT_CLOSED: 'uni-id-account-closed', + CAPTCHA_REQUIRED: 'uni-id-captcha-required', + PASSWORD_ERROR: 'uni-id-password-error', + PASSWORD_ERROR_EXCEED_LIMIT: 'uni-id-password-error-exceed-limit', + INVALID_USERNAME: 'uni-id-invalid-username', + INVALID_PASSWORD: 'uni-id-invalid-password', + INVALID_PASSWORD_SUPER: 'uni-id-invalid-password-super', + INVALID_PASSWORD_STRONG: 'uni-id-invalid-password-strong', + INVALID_PASSWORD_MEDIUM: 'uni-id-invalid-password-medium', + INVALID_PASSWORD_WEAK: 'uni-id-invalid-password-weak', + INVALID_MOBILE: 'uni-id-invalid-mobile', + INVALID_EMAIL: 'uni-id-invalid-email', + INVALID_NICKNAME: 'uni-id-invalid-nickname', + INVALID_PARAM: 'uni-id-invalid-param', + PARAM_REQUIRED: 'uni-id-param-required', + GET_THIRD_PARTY_ACCOUNT_FAILED: 'uni-id-get-third-party-account-failed', + GET_THIRD_PARTY_USER_INFO_FAILED: 'uni-id-get-third-party-user-info-failed', + MOBILE_VERIFY_CODE_ERROR: 'uni-id-mobile-verify-code-error', + EMAIL_VERIFY_CODE_ERROR: 'uni-id-email-verify-code-error', + ADMIN_EXISTS: 'uni-id-admin-exists', + PERMISSION_ERROR: 'uni-id-permission-error', + SYSTEM_ERROR: 'uni-id-system-error', + SET_INVITE_CODE_FAILED: 'uni-id-set-invite-code-failed', + INVALID_INVITE_CODE: 'uni-id-invalid-invite-code', + CHANGE_INVITER_FORBIDDEN: 'uni-id-change-inviter-forbidden', + BIND_CONFLICT: 'uni-id-bind-conflict', + UNBIND_FAIL: 'uni-id-unbind-failed', + UNBIND_NOT_SUPPORTED: 'uni-id-unbind-not-supported', + UNBIND_UNIQUE_LOGIN: 'uni-id-unbind-unique-login', + UNBIND_PASSWORD_NOT_EXISTS: 'uni-id-unbind-password-not-exists', + UNBIND_MOBILE_NOT_EXISTS: 'uni-id-unbind-mobile-not-exists' +} + +function isUniIdError (errCode) { + return Object.values(ERROR).includes(errCode) +} + +class UniCloudError extends Error { + constructor (options) { + super(options.message) + this.errMsg = options.message || '' + this.errCode = options.code + } +} + +module.exports = { + ERROR, + isUniIdError, + UniCloudError +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/utils.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/utils.js index 432404b9..b998f846 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/utils.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/utils.js @@ -1,190 +1,197 @@ -function batchFindObjctValue (obj = {}, keys = []) { - const values = {} - for (let i = 0; i < keys.length; i++) { - const key = keys[i] - const keyPath = key.split('.') - let currentKey = keyPath.shift() - let result = obj - while (currentKey) { - if (!result) { - break - } - result = result[currentKey] - currentKey = keyPath.shift() - } - values[key] = result - } - return values -} - -function getType (val) { - return Object.prototype.toString.call(val).slice(8, -1).toLowerCase() -} - -function hasOwn (obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key) -} - -function isValidString (val) { - return val && getType(val) === 'string' -} - -function isPlainObject (obj) { - return getType(obj) === 'object' -} - -function isFn (fn) { - // 务必注意AsyncFunction - return typeof fn === 'function' -} - -// 获取文件后缀,只添加几种图片类型供客服消息接口使用 -const mime2ext = { - 'image/png': 'png', - 'image/jpeg': 'jpg', - 'image/gif': 'gif', - 'image/svg+xml': 'svg', - 'image/bmp': 'bmp', - 'image/webp': 'webp' -} - -function getExtension (contentType) { - return mime2ext[contentType] -} - -const isSnakeCase = /_(\w)/g -const isCamelCase = /[A-Z]/g - -function snake2camel (value) { - return value.replace(isSnakeCase, (_, c) => (c ? c.toUpperCase() : '')) -} - -function camel2snake (value) { - return value.replace(isCamelCase, str => '_' + str.toLowerCase()) -} - -function parseObjectKeys (obj, type) { - let parserReg, parser - switch (type) { - case 'snake2camel': - parser = snake2camel - parserReg = isSnakeCase - break - case 'camel2snake': - parser = camel2snake - parserReg = isCamelCase - break - } - for (const key in obj) { - if (hasOwn(obj, key)) { - if (parserReg.test(key)) { - const keyCopy = parser(key) - obj[keyCopy] = obj[key] - delete obj[key] - if (isPlainObject(obj[keyCopy])) { - obj[keyCopy] = parseObjectKeys(obj[keyCopy], type) - } else if (Array.isArray(obj[keyCopy])) { - obj[keyCopy] = obj[keyCopy].map((item) => { - return parseObjectKeys(item, type) - }) - } - } - } - } - return obj -} - -function snake2camelJson (obj) { - return parseObjectKeys(obj, 'snake2camel') -} - -function camel2snakeJson (obj) { - return parseObjectKeys(obj, 'camel2snake') -} - -function getOffsetDate (offset) { - return new Date( - Date.now() + (new Date().getTimezoneOffset() + (offset || 0) * 60) * 60000 - ) -} - -function getDateStr (date, separator = '-') { - date = date || new Date() - const dateArr = [] - dateArr.push(date.getFullYear()) - dateArr.push(('00' + (date.getMonth() + 1)).substr(-2)) - dateArr.push(('00' + date.getDate()).substr(-2)) - return dateArr.join(separator) -} - -function getTimeStr (date, separator = ':') { - date = date || new Date() - const timeArr = [] - timeArr.push(('00' + date.getHours()).substr(-2)) - timeArr.push(('00' + date.getMinutes()).substr(-2)) - timeArr.push(('00' + date.getSeconds()).substr(-2)) - return timeArr.join(separator) -} - -function getFullTimeStr (date) { - date = date || new Date() - return getDateStr(date) + ' ' + getTimeStr(date) -} - -function getDistinctArray (arr) { - return Array.from(new Set(arr)) -} - -/** - * 拼接url - * @param {string} base 基础路径 - * @param {string} path 在基础路径上拼接的路径 - * @returns - */ -function resolveUrl (base, path) { - if (/^https?:/.test(path)) { - return path - } - return base + path -} - -function getVerifyCode (len = 6) { - let code = '' - for (let i = 0; i < len; i++) { - code += Math.floor(Math.random() * 10) - } - return code -} - -function coverMobile (mobile) { - if (typeof mobile !== 'string') { - return mobile - } - return mobile.slice(0, 3) + '****' + mobile.slice(7) -} - -function getNonceStr (length = 16) { - let str = '' - while (str.length < length) { - str += Math.random().toString(32).substring(2) - } - return str.substring(0, length) -} - -module.exports = { - getType, - isValidString, - batchFindObjctValue, - isPlainObject, - isFn, - getDistinctArray, - getFullTimeStr, - resolveUrl, - getOffsetDate, - camel2snakeJson, - snake2camelJson, - getExtension, - getVerifyCode, - coverMobile, - getNonceStr -} +function batchFindObjctValue (obj = {}, keys = []) { + const values = {} + for (let i = 0; i < keys.length; i++) { + const key = keys[i] + const keyPath = key.split('.') + let currentKey = keyPath.shift() + let result = obj + while (currentKey) { + if (!result) { + break + } + result = result[currentKey] + currentKey = keyPath.shift() + } + values[key] = result + } + return values +} + +function getType (val) { + return Object.prototype.toString.call(val).slice(8, -1).toLowerCase() +} + +function hasOwn (obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key) +} + +function isValidString (val) { + return val && getType(val) === 'string' +} + +function isPlainObject (obj) { + return getType(obj) === 'object' +} + +function isFn (fn) { + // 务必注意AsyncFunction + return typeof fn === 'function' +} + +// 获取文件后缀,只添加几种图片类型供客服消息接口使用 +const mime2ext = { + 'image/png': 'png', + 'image/jpeg': 'jpg', + 'image/gif': 'gif', + 'image/svg+xml': 'svg', + 'image/bmp': 'bmp', + 'image/webp': 'webp' +} + +function getExtension (contentType) { + return mime2ext[contentType] +} + +const isSnakeCase = /_(\w)/g +const isCamelCase = /[A-Z]/g + +function snake2camel (value) { + return value.replace(isSnakeCase, (_, c) => (c ? c.toUpperCase() : '')) +} + +function camel2snake (value) { + return value.replace(isCamelCase, str => '_' + str.toLowerCase()) +} + +function parseObjectKeys (obj, type) { + let parserReg, parser + switch (type) { + case 'snake2camel': + parser = snake2camel + parserReg = isSnakeCase + break + case 'camel2snake': + parser = camel2snake + parserReg = isCamelCase + break + } + for (const key in obj) { + if (hasOwn(obj, key)) { + if (parserReg.test(key)) { + const keyCopy = parser(key) + obj[keyCopy] = obj[key] + delete obj[key] + if (isPlainObject(obj[keyCopy])) { + obj[keyCopy] = parseObjectKeys(obj[keyCopy], type) + } else if (Array.isArray(obj[keyCopy])) { + obj[keyCopy] = obj[keyCopy].map((item) => { + return parseObjectKeys(item, type) + }) + } + } + } + } + return obj +} + +function snake2camelJson (obj) { + return parseObjectKeys(obj, 'snake2camel') +} + +function camel2snakeJson (obj) { + return parseObjectKeys(obj, 'camel2snake') +} + +function getOffsetDate (offset) { + return new Date( + Date.now() + (new Date().getTimezoneOffset() + (offset || 0) * 60) * 60000 + ) +} + +function getDateStr (date, separator = '-') { + date = date || new Date() + const dateArr = [] + dateArr.push(date.getFullYear()) + dateArr.push(('00' + (date.getMonth() + 1)).substr(-2)) + dateArr.push(('00' + date.getDate()).substr(-2)) + return dateArr.join(separator) +} + +function getTimeStr (date, separator = ':') { + date = date || new Date() + const timeArr = [] + timeArr.push(('00' + date.getHours()).substr(-2)) + timeArr.push(('00' + date.getMinutes()).substr(-2)) + timeArr.push(('00' + date.getSeconds()).substr(-2)) + return timeArr.join(separator) +} + +function getFullTimeStr (date) { + date = date || new Date() + return getDateStr(date) + ' ' + getTimeStr(date) +} + +function getDistinctArray (arr) { + return Array.from(new Set(arr)) +} + +/** + * 拼接url + * @param {string} base 基础路径 + * @param {string} path 在基础路径上拼接的路径 + * @returns + */ +function resolveUrl (base, path) { + if (/^https?:/.test(path)) { + return path + } + return base + path +} + +function getVerifyCode (len = 6) { + let code = '' + for (let i = 0; i < len; i++) { + code += Math.floor(Math.random() * 10) + } + return code +} + +function coverMobile (mobile) { + if (typeof mobile !== 'string') { + return mobile + } + return mobile.slice(0, 3) + '****' + mobile.slice(7) +} + +function getNonceStr (length = 16) { + let str = '' + while (str.length < length) { + str += Math.random().toString(32).substring(2) + } + return str.substring(0, length) +} + +try { + require('lodash.merge') +} catch (error) { + console.error('uni-id-co缺少依赖,请在uniCloud/cloudfunctions/common/uni-id-co目录执行 npm install 安装依赖') + throw error +} + +module.exports = { + getType, + isValidString, + batchFindObjctValue, + isPlainObject, + isFn, + getDistinctArray, + getFullTimeStr, + resolveUrl, + getOffsetDate, + camel2snakeJson, + snake2camelJson, + getExtension, + getVerifyCode, + coverMobile, + getNonceStr +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/validator.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/validator.js index 34878ca8..d6f06b56 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/validator.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/validator.js @@ -1,432 +1,432 @@ -const { - isValidString, - getType -} = require('./utils.js') -const { - ERROR -} = require('./error') - -const baseValidator = Object.create(null) - -baseValidator.username = function (username) { - const errCode = ERROR.INVALID_USERNAME - if (!isValidString(username)) { - return { - errCode - } - } - if (/^\d+$/.test(username)) { - // 用户名不能为纯数字 - return { - errCode - } - }; - if (!/^[a-zA-Z0-9_-]+$/.test(username)) { - // 用户名仅能使用数字、字母、“_”及“-” - return { - errCode - } - } -} - -baseValidator.password = function (password) { - const errCode = ERROR.INVALID_PASSWORD - if (!isValidString(password)) { - return { - errCode - } - } - if (password.length < 6) { - // 密码长度不能小于6 - return { - errCode - } - } -} - -baseValidator.mobile = function (mobile) { - const errCode = ERROR.INVALID_MOBILE - if (!isValidString(mobile)) { - return { - errCode - } - } - if (!/^1\d{10}$/.test(mobile)) { - return { - errCode - } - } -} - -baseValidator.email = function (email) { - const errCode = ERROR.INVALID_EMAIL - if (!isValidString(email)) { - return { - errCode - } - } - if (!/@/.test(email)) { - return { - errCode - } - } -} - -baseValidator.nickname = function (nickname) { - const errCode = ERROR.INVALID_NICKNAME - if (nickname.indexOf('@') !== -1) { - // 昵称不允许含@ - return { - errCode - } - }; - if (/^\d+$/.test(nickname)) { - // 昵称不能为纯数字 - return { - errCode - } - }; - if (nickname.length > 100) { - // 昵称不可超过100字符 - return { - errCode - } - } -} - -const baseType = ['string', 'boolean', 'number', 'null'] // undefined不会由客户端提交上来 - -baseType.forEach((type) => { - baseValidator[type] = function (val) { - if (getType(val) === type) { - return - } - return { - errCode: ERROR.INVALID_PARAM - } - } -}) - -function tokenize(name) { - let i = 0 - const result = [] - let token = '' - while (i < name.length) { - const char = name[i] - switch (char) { - case '|': - case '<': - case '>': - token && result.push(token) - result.push(char) - token = '' - break - default: - token += char - break - } - i++ - if (i === name.length && token) { - result.push(token) - } - } - return result -} - -/** - * 处理validator名 - * @param {string} name - */ -function parseValidatorName(name) { - const tokenList = tokenize(name) - let i = 0 - let currentToken = tokenList[i] - const result = { - type: 'root', - children: [], - parent: null - } - let lastRealm = result - while (currentToken) { - switch (currentToken) { - case 'array': { - const currentRealm = { - type: 'array', - children: [], - parent: lastRealm - } - lastRealm.children.push(currentRealm) - lastRealm = currentRealm - break - } - case '<': - if (lastRealm.type !== 'array') { - throw new Error('Invalid validator token "<"') - } - break - case '>': - if (lastRealm.type !== 'array') { - throw new Error('Invalid validator token ">"') - } - lastRealm = lastRealm.parent - break - case '|': - if (lastRealm.type !== 'array' && lastRealm.type !== 'root') { - throw new Error('Invalid validator token "|"') - } - break - default: - lastRealm.children.push({ - type: currentToken - }) - break - } - i++ - currentToken = tokenList[i] - } - return result -} - -function getRuleCategory(rule) { - switch (rule.type) { - case 'array': - return 'array' - case 'root': - return 'root' - default: - return 'base' - } -} - -function isMatchUnionType(val, rule) { - if (!rule.children || rule.children.length === 0) { - return true - } - const children = rule.children - for (let i = 0; i < children.length; i++) { - const child = children[i] - const category = getRuleCategory(child) - let pass = false - switch (category) { - case 'base': - pass = isMatchBaseType(val, child) - break - case 'array': - pass = isMatchArrayType(val, child) - break - default: - break - } - if (pass) { - return true - } - } - return false -} - -function isMatchBaseType(val, rule) { - if (typeof baseValidator[rule.type] !== 'function') { - throw new Error(`invalid schema type: ${rule.type}`) - } - const validateRes = baseValidator[rule.type](val) - if (validateRes && validateRes.errCode) { - return false - } - return true -} - -function isMatchArrayType(arr, rule) { - if (getType(arr) !== 'array') { - return false - } - if (rule.children && rule.children.length && arr.some(item => !isMatchUnionType(item, rule))) { - return false - } - return true -} - -// 特殊符号 https://www.ibm.com/support/pages/password-strength-rules ~!@#$%^&*_-+=`|\(){}[]:;"'<>,.?/ -// const specialChar = '~!@#$%^&*_-+=`|\(){}[]:;"\'<>,.?/' -// const specialCharRegExp = /^[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]$/ -// for (let i = 0, arr = specialChar.split(''); i < arr.length; i++) { -// const char = arr[i] -// if (!specialCharRegExp.test(char)) { -// throw new Error('check special character error: ' + char) -// } -// } - -// 密码强度表达式 -const passwordRules = { - // 密码必须包含大小写字母、数字和特殊符号 - super: /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/, - // 密码必须包含字母、数字和特殊符号 - strong: /^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/, - // 密码必须为字母、数字和特殊符号任意两种的组合 - medium: /^(?![0-9]+$)(?![a-zA-Z]+$)(?![~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]+$)[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/, - // 密码必须包含字母和数字 - weak: /^(?=.*[0-9])(?=.*[a-zA-Z])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{6,16}$/, - -} - -function createPasswordVerifier({ - passwordStrength = '' -} = {}) { - return function (password) { - const passwordRegExp = passwordRules[passwordStrength] - if (!passwordRegExp) { - throw new Error('Invalid password strength config: ' + passwordStrength) - } - const errCode = ERROR.INVALID_PASSWORD - if (!isValidString(password)) { - return { - errCode - } - } - if (!passwordRegExp.test(password)) { - return { - errCode: errCode + '-' + passwordStrength - } - } - } -} - -class Validator { - constructor({ - passwordStrength = '' - } = {}) { - this.baseValidator = baseValidator - this.customValidator = Object.create(null) - if (passwordStrength) { - this.mixin( - 'password', - createPasswordVerifier({ - passwordStrength - }) - ) - } - } - - mixin(type, handler) { - this.customValidator[type] = handler - } - - getRealBaseValidator(type) { - return this.customValidator[type] || this.baseValidator[type] - } - - get validator() { - return new Proxy({}, { - get: (_, prop) => { - if (typeof prop !== 'string') { - return - } - const realBaseValidator = this.getRealBaseValidator(prop) - if (realBaseValidator) { - return realBaseValidator - } - const rule = parseValidatorName(prop) - return function (val) { - if (!isMatchUnionType(val, rule)) { - return { - errCode: ERROR.INVALID_PARAM - } - } - } - } - }) - } - - validate(value = {}, schema = {}) { - for (const schemaKey in schema) { - let schemaValue = schema[schemaKey] - if (getType(schemaValue) === 'string') { - schemaValue = { - required: true, - type: schemaValue - } - } - const { - required, - type - } = schemaValue - // value内未传入了schemaKey或对应值为undefined - if (value[schemaKey] === undefined) { - if (required) { - return { - errCode: ERROR.PARAM_REQUIRED, - errMsgValue: { - param: schemaKey - }, - schemaKey - } - } else { - continue - } - } - const validateMethod = this.validator[type] - if (!validateMethod) { - throw new Error(`invalid schema type: ${type}`) - } - const validateRes = validateMethod(value[schemaKey]) - if (validateRes) { - validateRes.schemaKey = schemaKey - return validateRes - } - } - } -} - -function checkClientInfo(clientInfo) { - const stringNotRequired = { - required: false, - type: 'string' - } - const numberNotRequired = { - required: false, - type: 'number' - } - const numberOrStringNotRequired = { - required: false, - type: 'number|string' - } - const schema = { - uniPlatform: 'string', - appId: 'string', - deviceId: stringNotRequired, - osName: stringNotRequired, - locale: stringNotRequired, - clientIP: stringNotRequired, - appName: stringNotRequired, - appVersion: stringNotRequired, - appVersionCode: numberOrStringNotRequired, - channel: numberOrStringNotRequired, - userAgent: stringNotRequired, - uniIdToken: stringNotRequired, - deviceBrand: stringNotRequired, - deviceModel: stringNotRequired, - osVersion: stringNotRequired, - osLanguage: stringNotRequired, - osTheme: stringNotRequired, - romName: stringNotRequired, - romVersion: stringNotRequired, - devicePixelRatio: numberNotRequired, - windowWidth: numberNotRequired, - windowHeight: numberNotRequired, - screenWidth: numberNotRequired, - screenHeight: numberNotRequired - } - const validateRes = new Validator().validate(clientInfo, schema) - if (validateRes) { - if (validateRes.errCode === ERROR.PARAM_REQUIRED) { - console.warn('- 如果使用HBuilderX运行本地云函数/云对象功能时出现此提示,请改为使用客户端调用本地云函数方式调试,或更新HBuilderX到3.4.12及以上版本。\n- 如果是缺少clientInfo.appId,请检查项目manifest.json内是否配置了DCloud AppId') - throw new Error(`"clientInfo.${validateRes.schemaKey}" is required.`) - } else { - throw new Error(`Invalid client info: clienInfo.${validateRes.schemaKey}`) - } - } -} - -module.exports = { - Validator, - checkClientInfo -} +const { + isValidString, + getType +} = require('./utils.js') +const { + ERROR +} = require('./error') + +const baseValidator = Object.create(null) + +baseValidator.username = function (username) { + const errCode = ERROR.INVALID_USERNAME + if (!isValidString(username)) { + return { + errCode + } + } + if (/^\d+$/.test(username)) { + // 用户名不能为纯数字 + return { + errCode + } + }; + if (!/^[a-zA-Z0-9_-]+$/.test(username)) { + // 用户名仅能使用数字、字母、“_”及“-” + return { + errCode + } + } +} + +baseValidator.password = function (password) { + const errCode = ERROR.INVALID_PASSWORD + if (!isValidString(password)) { + return { + errCode + } + } + if (password.length < 6) { + // 密码长度不能小于6 + return { + errCode + } + } +} + +baseValidator.mobile = function (mobile) { + const errCode = ERROR.INVALID_MOBILE + if (!isValidString(mobile)) { + return { + errCode + } + } + if (!/^1\d{10}$/.test(mobile)) { + return { + errCode + } + } +} + +baseValidator.email = function (email) { + const errCode = ERROR.INVALID_EMAIL + if (!isValidString(email)) { + return { + errCode + } + } + if (!/@/.test(email)) { + return { + errCode + } + } +} + +baseValidator.nickname = function (nickname) { + const errCode = ERROR.INVALID_NICKNAME + if (nickname.indexOf('@') !== -1) { + // 昵称不允许含@ + return { + errCode + } + }; + if (/^\d+$/.test(nickname)) { + // 昵称不能为纯数字 + return { + errCode + } + }; + if (nickname.length > 100) { + // 昵称不可超过100字符 + return { + errCode + } + } +} + +const baseType = ['string', 'boolean', 'number', 'null'] // undefined不会由客户端提交上来 + +baseType.forEach((type) => { + baseValidator[type] = function (val) { + if (getType(val) === type) { + return + } + return { + errCode: ERROR.INVALID_PARAM + } + } +}) + +function tokenize(name) { + let i = 0 + const result = [] + let token = '' + while (i < name.length) { + const char = name[i] + switch (char) { + case '|': + case '<': + case '>': + token && result.push(token) + result.push(char) + token = '' + break + default: + token += char + break + } + i++ + if (i === name.length && token) { + result.push(token) + } + } + return result +} + +/** + * 处理validator名 + * @param {string} name + */ +function parseValidatorName(name) { + const tokenList = tokenize(name) + let i = 0 + let currentToken = tokenList[i] + const result = { + type: 'root', + children: [], + parent: null + } + let lastRealm = result + while (currentToken) { + switch (currentToken) { + case 'array': { + const currentRealm = { + type: 'array', + children: [], + parent: lastRealm + } + lastRealm.children.push(currentRealm) + lastRealm = currentRealm + break + } + case '<': + if (lastRealm.type !== 'array') { + throw new Error('Invalid validator token "<"') + } + break + case '>': + if (lastRealm.type !== 'array') { + throw new Error('Invalid validator token ">"') + } + lastRealm = lastRealm.parent + break + case '|': + if (lastRealm.type !== 'array' && lastRealm.type !== 'root') { + throw new Error('Invalid validator token "|"') + } + break + default: + lastRealm.children.push({ + type: currentToken + }) + break + } + i++ + currentToken = tokenList[i] + } + return result +} + +function getRuleCategory(rule) { + switch (rule.type) { + case 'array': + return 'array' + case 'root': + return 'root' + default: + return 'base' + } +} + +function isMatchUnionType(val, rule) { + if (!rule.children || rule.children.length === 0) { + return true + } + const children = rule.children + for (let i = 0; i < children.length; i++) { + const child = children[i] + const category = getRuleCategory(child) + let pass = false + switch (category) { + case 'base': + pass = isMatchBaseType(val, child) + break + case 'array': + pass = isMatchArrayType(val, child) + break + default: + break + } + if (pass) { + return true + } + } + return false +} + +function isMatchBaseType(val, rule) { + if (typeof baseValidator[rule.type] !== 'function') { + throw new Error(`invalid schema type: ${rule.type}`) + } + const validateRes = baseValidator[rule.type](val) + if (validateRes && validateRes.errCode) { + return false + } + return true +} + +function isMatchArrayType(arr, rule) { + if (getType(arr) !== 'array') { + return false + } + if (rule.children && rule.children.length && arr.some(item => !isMatchUnionType(item, rule))) { + return false + } + return true +} + +// 特殊符号 https://www.ibm.com/support/pages/password-strength-rules ~!@#$%^&*_-+=`|\(){}[]:;"'<>,.?/ +// const specialChar = '~!@#$%^&*_-+=`|\(){}[]:;"\'<>,.?/' +// const specialCharRegExp = /^[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]$/ +// for (let i = 0, arr = specialChar.split(''); i < arr.length; i++) { +// const char = arr[i] +// if (!specialCharRegExp.test(char)) { +// throw new Error('check special character error: ' + char) +// } +// } + +// 密码强度表达式 +const passwordRules = { + // 密码必须包含大小写字母、数字和特殊符号 + super: /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/, + // 密码必须包含字母、数字和特殊符号 + strong: /^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/, + // 密码必须为字母、数字和特殊符号任意两种的组合 + medium: /^(?![0-9]+$)(?![a-zA-Z]+$)(?![~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]+$)[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/, + // 密码必须包含字母和数字 + weak: /^(?=.*[0-9])(?=.*[a-zA-Z])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{6,16}$/, + +} + +function createPasswordVerifier({ + passwordStrength = '' +} = {}) { + return function (password) { + const passwordRegExp = passwordRules[passwordStrength] + if (!passwordRegExp) { + throw new Error('Invalid password strength config: ' + passwordStrength) + } + const errCode = ERROR.INVALID_PASSWORD + if (!isValidString(password)) { + return { + errCode + } + } + if (!passwordRegExp.test(password)) { + return { + errCode: errCode + '-' + passwordStrength + } + } + } +} + +class Validator { + constructor({ + passwordStrength = '' + } = {}) { + this.baseValidator = baseValidator + this.customValidator = Object.create(null) + if (passwordStrength) { + this.mixin( + 'password', + createPasswordVerifier({ + passwordStrength + }) + ) + } + } + + mixin(type, handler) { + this.customValidator[type] = handler + } + + getRealBaseValidator(type) { + return this.customValidator[type] || this.baseValidator[type] + } + + get validator() { + return new Proxy({}, { + get: (_, prop) => { + if (typeof prop !== 'string') { + return + } + const realBaseValidator = this.getRealBaseValidator(prop) + if (realBaseValidator) { + return realBaseValidator + } + const rule = parseValidatorName(prop) + return function (val) { + if (!isMatchUnionType(val, rule)) { + return { + errCode: ERROR.INVALID_PARAM + } + } + } + } + }) + } + + validate(value = {}, schema = {}) { + for (const schemaKey in schema) { + let schemaValue = schema[schemaKey] + if (getType(schemaValue) === 'string') { + schemaValue = { + required: true, + type: schemaValue + } + } + const { + required, + type + } = schemaValue + // value内未传入了schemaKey或对应值为undefined + if (value[schemaKey] === undefined) { + if (required) { + return { + errCode: ERROR.PARAM_REQUIRED, + errMsgValue: { + param: schemaKey + }, + schemaKey + } + } else { + continue + } + } + const validateMethod = this.validator[type] + if (!validateMethod) { + throw new Error(`invalid schema type: ${type}`) + } + const validateRes = validateMethod(value[schemaKey]) + if (validateRes) { + validateRes.schemaKey = schemaKey + return validateRes + } + } + } +} + +function checkClientInfo(clientInfo) { + const stringNotRequired = { + required: false, + type: 'string' + } + const numberNotRequired = { + required: false, + type: 'number' + } + const numberOrStringNotRequired = { + required: false, + type: 'number|string' + } + const schema = { + uniPlatform: 'string', + appId: 'string', + deviceId: stringNotRequired, + osName: stringNotRequired, + locale: stringNotRequired, + clientIP: stringNotRequired, + appName: stringNotRequired, + appVersion: stringNotRequired, + appVersionCode: numberOrStringNotRequired, + channel: numberOrStringNotRequired, + userAgent: stringNotRequired, + uniIdToken: stringNotRequired, + deviceBrand: stringNotRequired, + deviceModel: stringNotRequired, + osVersion: stringNotRequired, + osLanguage: stringNotRequired, + osTheme: stringNotRequired, + romName: stringNotRequired, + romVersion: stringNotRequired, + devicePixelRatio: numberNotRequired, + windowWidth: numberNotRequired, + windowHeight: numberNotRequired, + screenWidth: numberNotRequired, + screenHeight: numberNotRequired + } + const validateRes = new Validator().validate(clientInfo, schema) + if (validateRes) { + if (validateRes.errCode === ERROR.PARAM_REQUIRED) { + console.warn('- 如果使用HBuilderX运行本地云函数/云对象功能时出现此提示,请改为使用客户端调用本地云函数方式调试,或更新HBuilderX到3.4.12及以上版本。\n- 如果是缺少clientInfo.appId,请检查项目manifest.json内是否配置了DCloud AppId') + throw new Error(`"clientInfo.${validateRes.schemaKey}" is required.`) + } else { + throw new Error(`Invalid client info: clienInfo.${validateRes.schemaKey}`) + } + } +} + +module.exports = { + Validator, + checkClientInfo +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/config/permission.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/config/permission.js index f67725c6..0bc2661e 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/config/permission.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/config/permission.js @@ -1,66 +1,78 @@ -// 各接口权限配置,未配置接口表示允许任何用户访问(包括未登录用户) -module.exports = { - // 管理接口 - addUser: { - // auth: true // 已登录用户方可操作,配置角色或权限时此项可不写 - role: ['admin'] // 允许进行此操作的角色,包含任一角色均可操作。 - // permission: [] // 允许进行此操作的权限,包含任一权限均可操作。 - // 权限角色均配置时,用户拥有任一权限或任一角色均可操作 - }, - updateUser: { - role: ['admin'] - }, - authorizeAppLogin: { - role: ['admin'] - }, - removeAuthorizedApp: { - role: ['admin'] - }, - setAuthorizedApp: { - role: ['admin'] - }, - - // 用户接口 - closeAccount: { - auth: true - }, - updatePwd: { - auth: true - }, - logout: { - auth: true - }, - bindMobileBySms: { - auth: true - }, - bindMobileByUniverify: { - auth: true - }, - bindMobileByMpWeixin: { - auth: true - }, - bindAlipay: { - auth: true - }, - bindApple: { - auth: true - }, - bindQQ: { - auth: true - }, - bindWeixin: { - auth: true - }, - acceptInvite: { - auth: true - }, - getInvitedUser: { - auth: true - }, - setPushCid: { - auth: true - }, - getAccountInfo: { - auth: true - } -} +// 各接口权限配置,未配置接口表示允许任何用户访问(包括未登录用户) +module.exports = { + // 管理接口 + addUser: { + // auth: true // 已登录用户方可操作,配置角色或权限时此项可不写 + role: ['admin'] // 允许进行此操作的角色,包含任一角色均可操作。 + // permission: [] // 允许进行此操作的权限,包含任一权限均可操作。 + // 权限角色均配置时,用户拥有任一权限或任一角色均可操作 + }, + updateUser: { + role: ['admin'] + }, + authorizeAppLogin: { + role: ['admin'] + }, + removeAuthorizedApp: { + role: ['admin'] + }, + setAuthorizedApp: { + role: ['admin'] + }, + + // 用户接口 + closeAccount: { + auth: true + }, + updatePwd: { + auth: true + }, + logout: { + auth: true + }, + bindMobileBySms: { + auth: true + }, + bindMobileByUniverify: { + auth: true + }, + bindMobileByMpWeixin: { + auth: true + }, + bindAlipay: { + auth: true + }, + bindApple: { + auth: true + }, + bindQQ: { + auth: true + }, + bindWeixin: { + auth: true + }, + acceptInvite: { + auth: true + }, + getInvitedUser: { + auth: true + }, + setPushCid: { + auth: true + }, + getAccountInfo: { + auth: true + }, + unbindWeixin: { + auth: true + }, + unbindAlipay: { + auth: true + }, + unbindQQ: { + auth: true + }, + unbindApple: { + auth: true + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/index.obj.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/index.obj.js index c8a3f112..24cbbc7b 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/index.obj.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/index.obj.js @@ -29,7 +29,8 @@ const { loginByWeixin, loginByAlipay, loginByQQ, - loginByApple + loginByApple, + loginByWeixinMobile } = require('./module/login/index') const { logout @@ -41,7 +42,11 @@ const { bindAlipay, bindApple, bindQQ, - bindWeixin + bindWeixin, + unbindWeixin, + unbindAlipay, + unbindQQ, + unbindApple } = require('./module/relate/index') const { updatePwd, @@ -74,7 +79,7 @@ const { } = require('./module/dev/index') module.exports = { - async _before() { + async _before () { const clientInfo = this.getClientInfo() /** * 检查clientInfo,无appId和uniPlatform时本云对象无法正常运行 @@ -157,7 +162,7 @@ module.exports = { // 挂载uni-captcha到this上,方便后续调用 this.uniCaptcha = uniCaptcha Object.defineProperty(this, 'uniOpenBridge', { - get() { + get () { return require('uni-open-bridge-common') } }) @@ -181,7 +186,7 @@ module.exports = { // 通用权限校验模块 await this.middleware.accessControl() }, - _after(error, result) { + _after (error, result) { if (error) { // 处理中间件内抛出的标准响应对象 if (error.errCode && getType(error) === 'object') { @@ -217,6 +222,10 @@ module.exports = { * @param {String} params.nickname 昵称 * @param {Array} params.authorizedApp 允许登录的AppID列表 * @param {Array} params.role 用户角色列表 + * @param {String} params.mobile 手机号 + * @param {String} params.email 邮箱 + * @param {Array} params.tags 用户标签 + * @param {Number} params.status 用户状态 * @returns */ addUser, @@ -359,6 +368,7 @@ module.exports = { * @returns */ loginByApple, + loginByWeixinMobile, /** * 用户退出登录 * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#logout @@ -541,5 +551,30 @@ module.exports = { * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-supported-login-type * @returns */ - getSupportedLoginType + getSupportedLoginType, + + /** + * 解绑微信 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-weixin + * @returns + */ + unbindWeixin, + /** + * 解绑支付宝 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-alipay + * @returns + */ + unbindAlipay, + /** + * 解绑QQ + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-qq + * @returns + */ + unbindQQ, + /** + * 解绑Apple + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-apple + * @returns + */ + unbindApple } diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/en.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/en.js index 1ef455ab..99c445d4 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/en.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/en.js @@ -1,44 +1,49 @@ -const word = { - login: 'login', - 'verify-mobile': 'verify phone number' -} - -const sentence = { - 'uni-id-account-exists': 'Account exists', - 'uni-id-account-not-exists': 'Account does not exists', - 'uni-id-account-conflict': 'User account conflict', - 'uni-id-account-banned': 'Account has been banned', - 'uni-id-account-auditing': 'Account audit in progress', - 'uni-id-account-audit-failed': 'Account audit failed', - 'uni-id-account-closed': 'Account has been closed', - 'uni-id-captcha-required': 'Captcha required', - 'uni-id-password-error': 'Username or password error', - 'uni-id-password-error-exceed-limit': 'The number of password errors is excessive', - 'uni-id-invalid-username': 'Invalid username', - 'uni-id-invalid-password': 'invalid password', - 'uni-id-invalid-password-super': 'Passwords must have 8-16 characters and contain uppercase letters, lowercase letters, numbers, and symbols.', - 'uni-id-invalid-password-strong': 'Passwords must have 8-16 characters and contain letters, numbers and symbols.', - 'uni-id-invalid-password-medium': 'Passwords must have 8-16 characters and contain at least two of the following: letters, numbers, and symbols.', - 'uni-id-invalid-password-weak': 'Passwords must have 6-16 characters and contain letters and numbers.', - 'uni-id-invalid-mobile': 'Invalid mobile phone number', - 'uni-id-invalid-email': 'Invalid email address', - 'uni-id-invalid-nickname': 'Invalid nickname', - 'uni-id-invalid-param': 'Invalid parameter', - 'uni-id-param-required': 'Parameter required: {param}', - 'uni-id-get-third-party-account-failed': 'Get third party account failed', - 'uni-id-get-third-party-user-info-failed': 'Get third party user info failed', - 'uni-id-mobile-verify-code-error': 'Verify code error or expired', - 'uni-id-email-verify-code-error': 'Verify code error or expired', - 'uni-id-admin-exists': 'Administrator exists', - 'uni-id-permission-error': 'Permission denied', - 'uni-id-system-error': 'System error', - 'uni-id-set-invite-code-failed': 'Set invite code failed', - 'uni-id-invalid-invite-code': 'Invalid invite code', - 'uni-id-change-inviter-forbidden': 'Change inviter is not allowed', - 'uni-id-bind-conflict': 'This account has been bound' -} - -module.exports = { - ...word, - ...sentence -} +const word = { + login: 'login', + 'verify-mobile': 'verify phone number' +} + +const sentence = { + 'uni-id-account-exists': 'Account exists', + 'uni-id-account-not-exists': 'Account does not exists', + 'uni-id-account-conflict': 'User account conflict', + 'uni-id-account-banned': 'Account has been banned', + 'uni-id-account-auditing': 'Account audit in progress', + 'uni-id-account-audit-failed': 'Account audit failed', + 'uni-id-account-closed': 'Account has been closed', + 'uni-id-captcha-required': 'Captcha required', + 'uni-id-password-error': 'Password error', + 'uni-id-password-error-exceed-limit': 'The number of password errors is excessive', + 'uni-id-invalid-username': 'Invalid username', + 'uni-id-invalid-password': 'invalid password', + 'uni-id-invalid-password-super': 'Passwords must have 8-16 characters and contain uppercase letters, lowercase letters, numbers, and symbols.', + 'uni-id-invalid-password-strong': 'Passwords must have 8-16 characters and contain letters, numbers and symbols.', + 'uni-id-invalid-password-medium': 'Passwords must have 8-16 characters and contain at least two of the following: letters, numbers, and symbols.', + 'uni-id-invalid-password-weak': 'Passwords must have 6-16 characters and contain letters and numbers.', + 'uni-id-invalid-mobile': 'Invalid mobile phone number', + 'uni-id-invalid-email': 'Invalid email address', + 'uni-id-invalid-nickname': 'Invalid nickname', + 'uni-id-invalid-param': 'Invalid parameter', + 'uni-id-param-required': 'Parameter required: {param}', + 'uni-id-get-third-party-account-failed': 'Get third party account failed', + 'uni-id-get-third-party-user-info-failed': 'Get third party user info failed', + 'uni-id-mobile-verify-code-error': 'Verify code error or expired', + 'uni-id-email-verify-code-error': 'Verify code error or expired', + 'uni-id-admin-exists': 'Administrator exists', + 'uni-id-permission-error': 'Permission denied', + 'uni-id-system-error': 'System error', + 'uni-id-set-invite-code-failed': 'Set invite code failed', + 'uni-id-invalid-invite-code': 'Invalid invite code', + 'uni-id-change-inviter-forbidden': 'Change inviter is not allowed', + 'uni-id-bind-conflict': 'This account has been bound', + 'uni-id-admin-exist-in-other-apps': 'Administrator is registered in other consoles', + 'uni-id-unbind-failed': 'Please bind first and then unbind', + 'uni-id-unbind-not-supported': 'Unbinding is not supported', + 'uni-id-unbind-mobile-not-exists': 'This is the only way to login at the moment, please bind your phone number and then try to unbind', + 'uni-id-unbind-password-not-exists': 'Please set a password first' +} + +module.exports = { + ...word, + ...sentence +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/index.js index 1f229989..557575d7 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/index.js @@ -1,22 +1,22 @@ -let lang = { - 'zh-Hans': require('./zh-hans'), - en: require('./en') -} - -function mergeLanguage (lang1, lang2) { - const localeList = Object.keys(lang1) - localeList.push(...Object.keys(lang2)) - const result = {} - for (let i = 0; i < localeList.length; i++) { - const locale = localeList[i] - result[locale] = Object.assign({}, lang1[locale], lang2[locale]) - } - return result -} - -try { - const langPath = require.resolve('uni-config-center/uni-id/lang/index.js') - lang = mergeLanguage(lang, require(langPath)) -} catch (error) { } - -module.exports = lang +let lang = { + 'zh-Hans': require('./zh-hans'), + en: require('./en') +} + +function mergeLanguage (lang1, lang2) { + const localeList = Object.keys(lang1) + localeList.push(...Object.keys(lang2)) + const result = {} + for (let i = 0; i < localeList.length; i++) { + const locale = localeList[i] + result[locale] = Object.assign({}, lang1[locale], lang2[locale]) + } + return result +} + +try { + const langPath = require.resolve('uni-config-center/uni-id/lang/index.js') + lang = mergeLanguage(lang, require(langPath)) +} catch (error) { } + +module.exports = lang diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/zh-hans.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/zh-hans.js index 5bd2443f..923d2af8 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/zh-hans.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/zh-hans.js @@ -1,44 +1,49 @@ -const word = { - login: '登录', - 'verify-mobile': '验证手机号' -} - -const sentence = { - 'uni-id-account-exists': '此账号已注册', - 'uni-id-account-not-exists': '此账号未注册', - 'uni-id-account-conflict': '用户账号冲突', - 'uni-id-account-banned': '此账号已封禁', - 'uni-id-account-auditing': '此账号正在审核中', - 'uni-id-account-audit-failed': '此账号审核失败', - 'uni-id-account-closed': '此账号已注销', - 'uni-id-captcha-required': '请输入图形验证码', - 'uni-id-password-error': '用户名或密码错误', - 'uni-id-password-error-exceed-limit': '密码错误次数过多,请稍后再试', - 'uni-id-invalid-username': '用户名不合法', - 'uni-id-invalid-password': '密码不合法', - 'uni-id-invalid-password-super': '密码必须包含大小写字母、数字和特殊符号,长度8-16位', - 'uni-id-invalid-password-strong': '密码必须包含字母、数字和特殊符号,长度8-16位不合法', - 'uni-id-invalid-password-medium': '密码必须为字母、数字和特殊符号任意两种的组合,长度8-16位', - 'uni-id-invalid-password-weak': '密码必须包含字母和数字,长度6-16位', - 'uni-id-invalid-mobile': '手机号码不合法', - 'uni-id-invalid-email': '邮箱不合法', - 'uni-id-invalid-nickname': '昵称不合法', - 'uni-id-invalid-param': '参数错误', - 'uni-id-param-required': '缺少参数: {param}', - 'uni-id-get-third-party-account-failed': '获取第三方账号失败', - 'uni-id-get-third-party-user-info-failed': '获取用户信息失败', - 'uni-id-mobile-verify-code-error': '手机验证码错误或已过期', - 'uni-id-email-verify-code-error': '邮箱验证码错误或已过期', - 'uni-id-admin-exists': '超级管理员已存在', - 'uni-id-permission-error': '权限错误', - 'uni-id-system-error': '系统错误', - 'uni-id-set-invite-code-failed': '设置邀请码失败', - 'uni-id-invalid-invite-code': '邀请码不可用', - 'uni-id-change-inviter-forbidden': '禁止修改邀请人', - 'uni-id-bind-conflict': '此账号已被绑定' -} - -module.exports = { - ...word, - ...sentence -} +const word = { + login: '登录', + 'verify-mobile': '验证手机号' +} + +const sentence = { + 'uni-id-account-exists': '此账号已注册', + 'uni-id-account-not-exists': '此账号未注册', + 'uni-id-account-conflict': '用户账号冲突', + 'uni-id-account-banned': '此账号已封禁', + 'uni-id-account-auditing': '此账号正在审核中', + 'uni-id-account-audit-failed': '此账号审核失败', + 'uni-id-account-closed': '此账号已注销', + 'uni-id-captcha-required': '请输入图形验证码', + 'uni-id-password-error': '密码错误', + 'uni-id-password-error-exceed-limit': '密码错误次数过多,请稍后再试', + 'uni-id-invalid-username': '用户名不合法', + 'uni-id-invalid-password': '密码不合法', + 'uni-id-invalid-password-super': '密码必须包含大小写字母、数字和特殊符号,长度8-16位', + 'uni-id-invalid-password-strong': '密码必须包含字母、数字和特殊符号,长度8-16位不合法', + 'uni-id-invalid-password-medium': '密码必须为字母、数字和特殊符号任意两种的组合,长度8-16位', + 'uni-id-invalid-password-weak': '密码必须包含字母和数字,长度6-16位', + 'uni-id-invalid-mobile': '手机号码不合法', + 'uni-id-invalid-email': '邮箱不合法', + 'uni-id-invalid-nickname': '昵称不合法', + 'uni-id-invalid-param': '参数错误', + 'uni-id-param-required': '缺少参数: {param}', + 'uni-id-get-third-party-account-failed': '获取第三方账号失败', + 'uni-id-get-third-party-user-info-failed': '获取用户信息失败', + 'uni-id-mobile-verify-code-error': '手机验证码错误或已过期', + 'uni-id-email-verify-code-error': '邮箱验证码错误或已过期', + 'uni-id-admin-exists': '超级管理员已存在', + 'uni-id-permission-error': '权限错误', + 'uni-id-system-error': '系统错误', + 'uni-id-set-invite-code-failed': '设置邀请码失败', + 'uni-id-invalid-invite-code': '邀请码不可用', + 'uni-id-change-inviter-forbidden': '禁止修改邀请人', + 'uni-id-bind-conflict': '此账号已被绑定', + 'uni-id-admin-exist-in-other-apps': '超级管理员已在其他控制台注册', + 'uni-id-unbind-failed': '请先绑定后再解绑', + 'uni-id-unbind-not-supported': '不支持解绑', + 'uni-id-unbind-mobile-not-exists': '这是当前唯一登录方式,请绑定手机号后再尝试解绑', + 'uni-id-unbind-password-not-exists': '请先设置密码在尝试解绑' +} + +module.exports = { + ...word, + ...sentence +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/README.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/README.md index 47d8c4c8..69e66178 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/README.md +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/README.md @@ -1,3 +1,3 @@ -# 说明 - +# 说明 + 此目录内为uni-id-co基础能力,不建议直接修改。如果你发现有些逻辑加入会更好,或者此部分代码有Bug可以向我们提交PR,仓库地址:[]()。如果有特殊的需求也可以在[论坛](https://ask.dcloud.net.cn/)提出,我们可以讨论下如何实现。 \ No newline at end of file diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/index.js index dbec0817..fd4c7bed 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/index.js @@ -1,16 +1,16 @@ -const AlipayBase = require('../alipayBase') -const protocols = require('./protocols') -module.exports = class Auth extends AlipayBase { - constructor (options) { - super(options) - this._protocols = protocols - } - - async code2Session (code) { - const result = await this._exec('alipay.system.oauth.token', { - grantType: 'authorization_code', - code - }) - return result - } -} +const AlipayBase = require('../alipayBase') +const protocols = require('./protocols') +module.exports = class Auth extends AlipayBase { + constructor (options) { + super(options) + this._protocols = protocols + } + + async code2Session (code) { + const result = await this._exec('alipay.system.oauth.token', { + grantType: 'authorization_code', + code + }) + return result + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/protocols.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/protocols.js index cff351d8..17c9860d 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/protocols.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/protocols.js @@ -1,10 +1,10 @@ -module.exports = { - code2Session: { - // args (fromArgs) { - // return fromArgs - // }, - returnValue: { - openid: 'userId' - } - } -} +module.exports = { + code2Session: { + // args (fromArgs) { + // return fromArgs + // }, + returnValue: { + openid: 'userId' + } + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/alipayBase.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/alipayBase.js index 1462b046..8b18706a 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/alipayBase.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/alipayBase.js @@ -1,231 +1,231 @@ -const { - camel2snakeJson, - snake2camelJson, - getOffsetDate, - getFullTimeStr -} = require('../../../common/utils') -const crypto = require('crypto') - -const ALIPAY_ALGORITHM_MAPPING = { - RSA: 'RSA-SHA1', - RSA2: 'RSA-SHA256' -} - -module.exports = class AlipayBase { - constructor (options = {}) { - if (!options.appId) throw new Error('appId required') - if (!options.privateKey) throw new Error('privateKey required') - const defaultOptions = { - gateway: 'https://openapi.alipay.com/gateway.do', - timeout: 5000, - charset: 'utf-8', - version: '1.0', - signType: 'RSA2', - timeOffset: -new Date().getTimezoneOffset() / 60, - keyType: 'PKCS8' - } - - if (options.sandbox) { - options.gateway = 'https://openapi.alipaydev.com/gateway.do' - } - - this.options = Object.assign({}, defaultOptions, options) - - const privateKeyType = - this.options.keyType === 'PKCS8' ? 'PRIVATE KEY' : 'RSA PRIVATE KEY' - - this.options.privateKey = this._formatKey( - this.options.privateKey, - privateKeyType - ) - if (this.options.alipayPublicKey) { - this.options.alipayPublicKey = this._formatKey( - this.options.alipayPublicKey, - 'PUBLIC KEY' - ) - } - } - - _formatKey (key, type) { - return `-----BEGIN ${type}-----\n${key}\n-----END ${type}-----` - } - - _formatUrl (url, params) { - let requestUrl = url - // 需要放在 url 中的参数列表 - const urlArgs = [ - 'app_id', - 'method', - 'format', - 'charset', - 'sign_type', - 'sign', - 'timestamp', - 'version', - 'notify_url', - 'return_url', - 'auth_token', - 'app_auth_token' - ] - - for (const key in params) { - if (urlArgs.indexOf(key) > -1) { - const val = encodeURIComponent(params[key]) - requestUrl = `${requestUrl}${requestUrl.includes('?') ? '&' : '?' - }${key}=${val}` - // 删除 postData 中对应的数据 - delete params[key] - } - } - - return { execParams: params, url: requestUrl } - } - - _getSign (method, params) { - const bizContent = params.bizContent || null - delete params.bizContent - - const signParams = Object.assign({ - method, - appId: this.options.appId, - charset: this.options.charset, - version: this.options.version, - signType: this.options.signType, - timestamp: getFullTimeStr(getOffsetDate(this.options.timeOffset)) - }, params) - - if (bizContent) { - signParams.bizContent = JSON.stringify(camel2snakeJson(bizContent)) - } - - // params key 驼峰转下划线 - const decamelizeParams = camel2snakeJson(signParams) - - // 排序 - const signStr = Object.keys(decamelizeParams) - .sort() - .map((key) => { - let data = decamelizeParams[key] - if (Array.prototype.toString.call(data) !== '[object String]') { - data = JSON.stringify(data) - } - return `${key}=${data}` - }) - .join('&') - - // 计算签名 - const sign = crypto - .createSign(ALIPAY_ALGORITHM_MAPPING[this.options.signType]) - .update(signStr, 'utf8') - .sign(this.options.privateKey, 'base64') - - return Object.assign(decamelizeParams, { sign }) - } - - async _exec (method, params = {}, option = {}) { - // 计算签名 - const signData = this._getSign(method, params) - const { url, execParams } = this._formatUrl(this.options.gateway, signData) - const { status, data } = await uniCloud.httpclient.request(url, { - method: 'POST', - data: execParams, - // 按 text 返回(为了验签) - dataType: 'text', - timeout: this.options.timeout - }) - if (status !== 200) throw new Error('request fail') - /** - * 示例响应格式 - * {"alipay_trade_precreate_response": - * {"code": "10000","msg": "Success","out_trade_no": "111111","qr_code": "https:\/\/"}, - * "sign": "abcde=" - * } - * 或者 - * {"error_response": - * {"code":"40002","msg":"Invalid Arguments","sub_code":"isv.code-invalid","sub_msg":"授权码code无效"}, - * } - */ - const result = JSON.parse(data) - const responseKey = `${method.replace(/\./g, '_')}_response` - const response = result[responseKey] - const errorResponse = result.error_response - if (response) { - // 按字符串验签 - const validateSuccess = option.validateSign ? this._checkResponseSign(data, responseKey) : true - if (validateSuccess) { - if (!response.code || response.code === '10000') { - const errCode = 0 - const errMsg = response.msg || '' - return { - errCode, - errMsg, - ...snake2camelJson(response) - } - } - const msg = response.sub_code ? `${response.sub_code} ${response.sub_msg}` : `${response.msg || 'unkonwn error'}` - throw new Error(msg) - } else { - throw new Error('check sign error') - } - } else if (errorResponse) { - throw new Error(errorResponse.sub_msg || errorResponse.msg || 'request fail') - } - - throw new Error('request fail') - } - - _checkResponseSign (signStr, responseKey) { - if (!this.options.alipayPublicKey || this.options.alipayPublicKey === '') { - console.warn('options.alipayPublicKey is empty') - // 支付宝公钥不存在时不做验签 - return true - } - - // 带验签的参数不存在时返回失败 - if (!signStr) { return false } - - // 根据服务端返回的结果截取需要验签的目标字符串 - const validateStr = this._getSignStr(signStr, responseKey) - // 服务端返回的签名 - const serverSign = JSON.parse(signStr).sign - - // 参数存在,并且是正常的结果(不包含 sub_code)时才验签 - const verifier = crypto.createVerify(ALIPAY_ALGORITHM_MAPPING[this.options.signType]) - verifier.update(validateStr, 'utf8') - return verifier.verify(this.options.alipayPublicKey, serverSign, 'base64') - } - - _getSignStr (originStr, responseKey) { - // 待签名的字符串 - let validateStr = originStr.trim() - // 找到 xxx_response 开始的位置 - const startIndex = originStr.indexOf(`${responseKey}"`) - // 找到最后一个 “"sign"” 字符串的位置(避免) - const lastIndex = originStr.lastIndexOf('"sign"') - - /** - * 删除 xxx_response 及之前的字符串 - * 假设原始字符串为 - * {"xxx_response":{"code":"10000"},"sign":"jumSvxTKwn24G5sAIN"} - * 删除后变为 - * :{"code":"10000"},"sign":"jumSvxTKwn24G5sAIN"} - */ - validateStr = validateStr.substr(startIndex + responseKey.length + 1) - - /** - * 删除最后一个 "sign" 及之后的字符串 - * 删除后变为 - * :{"code":"10000"}, - * {} 之间就是待验签的字符串 - */ - validateStr = validateStr.substr(0, lastIndex) - - // 删除第一个 { 之前的任何字符 - validateStr = validateStr.replace(/^[^{]*{/g, '{') - - // 删除最后一个 } 之后的任何字符 - validateStr = validateStr.replace(/\}([^}]*)$/g, '}') - - return validateStr - } -} +const { + camel2snakeJson, + snake2camelJson, + getOffsetDate, + getFullTimeStr +} = require('../../../common/utils') +const crypto = require('crypto') + +const ALIPAY_ALGORITHM_MAPPING = { + RSA: 'RSA-SHA1', + RSA2: 'RSA-SHA256' +} + +module.exports = class AlipayBase { + constructor (options = {}) { + if (!options.appId) throw new Error('appId required') + if (!options.privateKey) throw new Error('privateKey required') + const defaultOptions = { + gateway: 'https://openapi.alipay.com/gateway.do', + timeout: 5000, + charset: 'utf-8', + version: '1.0', + signType: 'RSA2', + timeOffset: -new Date().getTimezoneOffset() / 60, + keyType: 'PKCS8' + } + + if (options.sandbox) { + options.gateway = 'https://openapi.alipaydev.com/gateway.do' + } + + this.options = Object.assign({}, defaultOptions, options) + + const privateKeyType = + this.options.keyType === 'PKCS8' ? 'PRIVATE KEY' : 'RSA PRIVATE KEY' + + this.options.privateKey = this._formatKey( + this.options.privateKey, + privateKeyType + ) + if (this.options.alipayPublicKey) { + this.options.alipayPublicKey = this._formatKey( + this.options.alipayPublicKey, + 'PUBLIC KEY' + ) + } + } + + _formatKey (key, type) { + return `-----BEGIN ${type}-----\n${key}\n-----END ${type}-----` + } + + _formatUrl (url, params) { + let requestUrl = url + // 需要放在 url 中的参数列表 + const urlArgs = [ + 'app_id', + 'method', + 'format', + 'charset', + 'sign_type', + 'sign', + 'timestamp', + 'version', + 'notify_url', + 'return_url', + 'auth_token', + 'app_auth_token' + ] + + for (const key in params) { + if (urlArgs.indexOf(key) > -1) { + const val = encodeURIComponent(params[key]) + requestUrl = `${requestUrl}${requestUrl.includes('?') ? '&' : '?' + }${key}=${val}` + // 删除 postData 中对应的数据 + delete params[key] + } + } + + return { execParams: params, url: requestUrl } + } + + _getSign (method, params) { + const bizContent = params.bizContent || null + delete params.bizContent + + const signParams = Object.assign({ + method, + appId: this.options.appId, + charset: this.options.charset, + version: this.options.version, + signType: this.options.signType, + timestamp: getFullTimeStr(getOffsetDate(this.options.timeOffset)) + }, params) + + if (bizContent) { + signParams.bizContent = JSON.stringify(camel2snakeJson(bizContent)) + } + + // params key 驼峰转下划线 + const decamelizeParams = camel2snakeJson(signParams) + + // 排序 + const signStr = Object.keys(decamelizeParams) + .sort() + .map((key) => { + let data = decamelizeParams[key] + if (Array.prototype.toString.call(data) !== '[object String]') { + data = JSON.stringify(data) + } + return `${key}=${data}` + }) + .join('&') + + // 计算签名 + const sign = crypto + .createSign(ALIPAY_ALGORITHM_MAPPING[this.options.signType]) + .update(signStr, 'utf8') + .sign(this.options.privateKey, 'base64') + + return Object.assign(decamelizeParams, { sign }) + } + + async _exec (method, params = {}, option = {}) { + // 计算签名 + const signData = this._getSign(method, params) + const { url, execParams } = this._formatUrl(this.options.gateway, signData) + const { status, data } = await uniCloud.httpclient.request(url, { + method: 'POST', + data: execParams, + // 按 text 返回(为了验签) + dataType: 'text', + timeout: this.options.timeout + }) + if (status !== 200) throw new Error('request fail') + /** + * 示例响应格式 + * {"alipay_trade_precreate_response": + * {"code": "10000","msg": "Success","out_trade_no": "111111","qr_code": "https:\/\/"}, + * "sign": "abcde=" + * } + * 或者 + * {"error_response": + * {"code":"40002","msg":"Invalid Arguments","sub_code":"isv.code-invalid","sub_msg":"授权码code无效"}, + * } + */ + const result = JSON.parse(data) + const responseKey = `${method.replace(/\./g, '_')}_response` + const response = result[responseKey] + const errorResponse = result.error_response + if (response) { + // 按字符串验签 + const validateSuccess = option.validateSign ? this._checkResponseSign(data, responseKey) : true + if (validateSuccess) { + if (!response.code || response.code === '10000') { + const errCode = 0 + const errMsg = response.msg || '' + return { + errCode, + errMsg, + ...snake2camelJson(response) + } + } + const msg = response.sub_code ? `${response.sub_code} ${response.sub_msg}` : `${response.msg || 'unkonwn error'}` + throw new Error(msg) + } else { + throw new Error('check sign error') + } + } else if (errorResponse) { + throw new Error(errorResponse.sub_msg || errorResponse.msg || 'request fail') + } + + throw new Error('request fail') + } + + _checkResponseSign (signStr, responseKey) { + if (!this.options.alipayPublicKey || this.options.alipayPublicKey === '') { + console.warn('options.alipayPublicKey is empty') + // 支付宝公钥不存在时不做验签 + return true + } + + // 带验签的参数不存在时返回失败 + if (!signStr) { return false } + + // 根据服务端返回的结果截取需要验签的目标字符串 + const validateStr = this._getSignStr(signStr, responseKey) + // 服务端返回的签名 + const serverSign = JSON.parse(signStr).sign + + // 参数存在,并且是正常的结果(不包含 sub_code)时才验签 + const verifier = crypto.createVerify(ALIPAY_ALGORITHM_MAPPING[this.options.signType]) + verifier.update(validateStr, 'utf8') + return verifier.verify(this.options.alipayPublicKey, serverSign, 'base64') + } + + _getSignStr (originStr, responseKey) { + // 待签名的字符串 + let validateStr = originStr.trim() + // 找到 xxx_response 开始的位置 + const startIndex = originStr.indexOf(`${responseKey}"`) + // 找到最后一个 “"sign"” 字符串的位置(避免) + const lastIndex = originStr.lastIndexOf('"sign"') + + /** + * 删除 xxx_response 及之前的字符串 + * 假设原始字符串为 + * {"xxx_response":{"code":"10000"},"sign":"jumSvxTKwn24G5sAIN"} + * 删除后变为 + * :{"code":"10000"},"sign":"jumSvxTKwn24G5sAIN"} + */ + validateStr = validateStr.substr(startIndex + responseKey.length + 1) + + /** + * 删除最后一个 "sign" 及之后的字符串 + * 删除后变为 + * :{"code":"10000"}, + * {} 之间就是待验签的字符串 + */ + validateStr = validateStr.substr(0, lastIndex) + + // 删除第一个 { 之前的任何字符 + validateStr = validateStr.replace(/^[^{]*{/g, '{') + + // 删除最后一个 } 之后的任何字符 + validateStr = validateStr.replace(/\}([^}]*)$/g, '}') + + return validateStr + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/account/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/account/index.js index 0e51b4da..24cd60fc 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/account/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/account/index.js @@ -1,76 +1,76 @@ -const rsaPublicKeyPem = require('../rsa-public-key-pem') -let authKeysCache = null - -module.exports = class Auth { - constructor (options) { - this.options = Object.assign({ - baseUrl: 'https://appleid.apple.com', - timeout: 10000 - }, options) - } - - async _fetch (url, options) { - const { baseUrl } = this.options - return uniCloud.httpclient.request(baseUrl + url, options) - } - - async verifyIdentityToken (identityToken) { - // 解密出kid,拿取key - const jwtHeader = identityToken.split('.')[0] - const { kid } = JSON.parse(Buffer.from(jwtHeader, 'base64').toString()) - let authKeys - if (authKeysCache) { - authKeys = authKeysCache - } else { - authKeys = await this.getAuthKeys() - authKeysCache = authKeys - } - const usedKey = authKeys.find(item => item.kid === kid) - - /** - * identityToken 格式 - * - * { - * iss: 'https://appleid.apple.com', - * aud: 'io.dcloud.hellouniapp', - * exp: 1610626724, - * iat: 1610540324, - * sub: '000628.30119d332d9b45a3be4a297f9391fd5c.0403', - * c_hash: 'oFfgewoG36cJX00KUbj45A', - * email: 'x2awmap99s@privaterelay.appleid.com', - * email_verified: 'true', - * is_private_email: 'true', - * auth_time: 1610540324, - * nonce_supported: true - * } - */ - const payload = require('jsonwebtoken').verify( - identityToken, - rsaPublicKeyPem(usedKey.n, usedKey.e), - { - algorithms: usedKey.alg - } - ) - - if (payload.iss !== 'https://appleid.apple.com' || payload.aud !== this.options.bundleId) { - throw new Error('Invalid identity token') - } - - return { - openid: payload.sub, - email: payload.email, - emailVerified: payload.email_verified === 'true', - isPrivateEmail: payload.is_private_email === 'true' - } - } - - async getAuthKeys () { - const { status, data } = await this._fetch('/auth/keys', { - method: 'GET', - dataType: 'json', - timeout: this.options.timeout - }) - if (status !== 200) throw new Error('request https://appleid.apple.com/auth/keys fail') - return data.keys - } -} +const rsaPublicKeyPem = require('../rsa-public-key-pem') +let authKeysCache = null + +module.exports = class Auth { + constructor (options) { + this.options = Object.assign({ + baseUrl: 'https://appleid.apple.com', + timeout: 10000 + }, options) + } + + async _fetch (url, options) { + const { baseUrl } = this.options + return uniCloud.httpclient.request(baseUrl + url, options) + } + + async verifyIdentityToken (identityToken) { + // 解密出kid,拿取key + const jwtHeader = identityToken.split('.')[0] + const { kid } = JSON.parse(Buffer.from(jwtHeader, 'base64').toString()) + let authKeys + if (authKeysCache) { + authKeys = authKeysCache + } else { + authKeys = await this.getAuthKeys() + authKeysCache = authKeys + } + const usedKey = authKeys.find(item => item.kid === kid) + + /** + * identityToken 格式 + * + * { + * iss: 'https://appleid.apple.com', + * aud: 'io.dcloud.hellouniapp', + * exp: 1610626724, + * iat: 1610540324, + * sub: '000628.30119d332d9b45a3be4a297f9391fd5c.0403', + * c_hash: 'oFfgewoG36cJX00KUbj45A', + * email: 'x2awmap99s@privaterelay.appleid.com', + * email_verified: 'true', + * is_private_email: 'true', + * auth_time: 1610540324, + * nonce_supported: true + * } + */ + const payload = require('jsonwebtoken').verify( + identityToken, + rsaPublicKeyPem(usedKey.n, usedKey.e), + { + algorithms: usedKey.alg + } + ) + + if (payload.iss !== 'https://appleid.apple.com' || payload.aud !== this.options.bundleId) { + throw new Error('Invalid identity token') + } + + return { + openid: payload.sub, + email: payload.email, + emailVerified: payload.email_verified === 'true', + isPrivateEmail: payload.is_private_email === 'true' + } + } + + async getAuthKeys () { + const { status, data } = await this._fetch('/auth/keys', { + method: 'GET', + dataType: 'json', + timeout: this.options.timeout + }) + if (status !== 200) throw new Error('request https://appleid.apple.com/auth/keys fail') + return data.keys + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/rsa-public-key-pem.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/rsa-public-key-pem.js index e1dbb31d..8fcc5690 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/rsa-public-key-pem.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/rsa-public-key-pem.js @@ -1,64 +1,64 @@ -// http://stackoverflow.com/questions/18835132/xml-to-pem-in-node-js -/* eslint-disable camelcase */ -function rsaPublicKeyPem (modulus_b64, exponent_b64) { - const modulus = Buffer.from(modulus_b64, 'base64') - const exponent = Buffer.from(exponent_b64, 'base64') - - let modulus_hex = modulus.toString('hex') - let exponent_hex = exponent.toString('hex') - - modulus_hex = prepadSigned(modulus_hex) - exponent_hex = prepadSigned(exponent_hex) - - const modlen = modulus_hex.length / 2 - const explen = exponent_hex.length / 2 - - const encoded_modlen = encodeLengthHex(modlen) - const encoded_explen = encodeLengthHex(explen) - const encoded_pubkey = '30' + - encodeLengthHex( - modlen + - explen + - encoded_modlen.length / 2 + - encoded_explen.length / 2 + 2 - ) + - '02' + encoded_modlen + modulus_hex + - '02' + encoded_explen + exponent_hex - - const der_b64 = Buffer.from(encoded_pubkey, 'hex').toString('base64') - - const pem = '-----BEGIN RSA PUBLIC KEY-----\n' + - der_b64.match(/.{1,64}/g).join('\n') + - '\n-----END RSA PUBLIC KEY-----\n' - - return pem -} - -function prepadSigned (hexStr) { - const msb = hexStr[0] - if (msb < '0' || msb > '7') { - return '00' + hexStr - } else { - return hexStr - } -} - -function toHex (number) { - const nstr = number.toString(16) - if (nstr.length % 2) return '0' + nstr - return nstr -} - -// encode ASN.1 DER length field -// if <=127, short form -// if >=128, long form -function encodeLengthHex (n) { - if (n <= 127) return toHex(n) - else { - const n_hex = toHex(n) - const length_of_length_byte = 128 + n_hex.length / 2 // 0x80+numbytes - return toHex(length_of_length_byte) + n_hex - } -} - -module.exports = rsaPublicKeyPem +// http://stackoverflow.com/questions/18835132/xml-to-pem-in-node-js +/* eslint-disable camelcase */ +function rsaPublicKeyPem (modulus_b64, exponent_b64) { + const modulus = Buffer.from(modulus_b64, 'base64') + const exponent = Buffer.from(exponent_b64, 'base64') + + let modulus_hex = modulus.toString('hex') + let exponent_hex = exponent.toString('hex') + + modulus_hex = prepadSigned(modulus_hex) + exponent_hex = prepadSigned(exponent_hex) + + const modlen = modulus_hex.length / 2 + const explen = exponent_hex.length / 2 + + const encoded_modlen = encodeLengthHex(modlen) + const encoded_explen = encodeLengthHex(explen) + const encoded_pubkey = '30' + + encodeLengthHex( + modlen + + explen + + encoded_modlen.length / 2 + + encoded_explen.length / 2 + 2 + ) + + '02' + encoded_modlen + modulus_hex + + '02' + encoded_explen + exponent_hex + + const der_b64 = Buffer.from(encoded_pubkey, 'hex').toString('base64') + + const pem = '-----BEGIN RSA PUBLIC KEY-----\n' + + der_b64.match(/.{1,64}/g).join('\n') + + '\n-----END RSA PUBLIC KEY-----\n' + + return pem +} + +function prepadSigned (hexStr) { + const msb = hexStr[0] + if (msb < '0' || msb > '7') { + return '00' + hexStr + } else { + return hexStr + } +} + +function toHex (number) { + const nstr = number.toString(16) + if (nstr.length % 2) return '0' + nstr + return nstr +} + +// encode ASN.1 DER length field +// if <=127, short form +// if >=128, long form +function encodeLengthHex (n) { + if (n <= 127) return toHex(n) + else { + const n_hex = toHex(n) + const length_of_length_byte = 128 + n_hex.length / 2 // 0x80+numbytes + return toHex(length_of_length_byte) + n_hex + } +} + +module.exports = rsaPublicKeyPem diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/index.js index 149c7de9..499265e4 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/index.js @@ -1,36 +1,36 @@ -const WxAccount = require('./weixin/account/index') -const QQAccount = require('./qq/account/index') -const AliAccount = require('./alipay/account/index') -const AppleAccount = require('./apple/account/index') - -const createApi = require('./share/create-api') - -module.exports = { - initWeixin: function () { - const oauthConfig = this.configUtils.getOauthConfig({ provider: 'weixin' }) - return createApi(WxAccount, { - appId: oauthConfig.appid, - secret: oauthConfig.appsecret - }) - }, - initQQ: function () { - const oauthConfig = this.configUtils.getOauthConfig({ provider: 'qq' }) - return createApi(QQAccount, { - appId: oauthConfig.appid, - secret: oauthConfig.appsecret - }) - }, - initAlipay: function () { - const oauthConfig = this.configUtils.getOauthConfig({ provider: 'alipay' }) - return createApi(AliAccount, { - appId: oauthConfig.appid, - privateKey: oauthConfig.privateKey - }) - }, - initApple: function () { - const oauthConfig = this.configUtils.getOauthConfig({ provider: 'apple' }) - return createApi(AppleAccount, { - bundleId: oauthConfig.bundleId - }) - } -} +const WxAccount = require('./weixin/account/index') +const QQAccount = require('./qq/account/index') +const AliAccount = require('./alipay/account/index') +const AppleAccount = require('./apple/account/index') + +const createApi = require('./share/create-api') + +module.exports = { + initWeixin: function () { + const oauthConfig = this.configUtils.getOauthConfig({ provider: 'weixin' }) + return createApi(WxAccount, { + appId: oauthConfig.appid, + secret: oauthConfig.appsecret + }) + }, + initQQ: function () { + const oauthConfig = this.configUtils.getOauthConfig({ provider: 'qq' }) + return createApi(QQAccount, { + appId: oauthConfig.appid, + secret: oauthConfig.appsecret + }) + }, + initAlipay: function () { + const oauthConfig = this.configUtils.getOauthConfig({ provider: 'alipay' }) + return createApi(AliAccount, { + appId: oauthConfig.appid, + privateKey: oauthConfig.privateKey + }) + }, + initApple: function () { + const oauthConfig = this.configUtils.getOauthConfig({ provider: 'apple' }) + return createApi(AppleAccount, { + bundleId: oauthConfig.bundleId + }) + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/account/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/account/index.js index 9b4879a0..35a1a335 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/account/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/account/index.js @@ -1,97 +1,97 @@ -const { - UniCloudError -} = require('../../../../common/error') -const { - resolveUrl -} = require('../../../../common/utils') -const { - callQQOpenApi -} = require('../normalize') - -module.exports = class Auth { - constructor (options) { - this.options = Object.assign({ - baseUrl: 'https://graph.qq.com', - timeout: 5000 - }, options) - } - - async _requestQQOpenapi ({ name, url, data, options }) { - const defaultOptions = { - method: 'GET', - dataType: 'json', - dataAsQueryString: true, - timeout: this.options.timeout - } - const result = await callQQOpenApi({ - name: `auth.${name}`, - url: resolveUrl(this.options.baseUrl, url), - data, - options, - defaultOptions - }) - return result - } - - async getUserInfo ({ - accessToken, - openid - } = {}) { - const url = '/user/get_user_info' - const result = await this._requestQQOpenapi({ - name: 'getUserInfo', - url, - data: { - oauthConsumerKey: this.options.appId, - accessToken, - openid - } - }) - return { - nickname: result.nickname, - avatar: result.figureurl_qq_1 - } - } - - async getOpenidByToken ({ - accessToken - } = {}) { - const url = '/oauth2.0/me' - const result = await this._requestQQOpenapi({ - name: 'getOpenidByToken', - url, - data: { - accessToken, - unionid: 1, - fmt: 'json' - } - }) - if (result.clientId !== this.options.appId) { - throw new UniCloudError({ - code: 'APPID_NOT_MATCH', - message: 'appid not match' - }) - } - return { - openid: result.openid, - unionid: result.unionid - } - } - - async code2Session ({ - code - } = {}) { - const url = 'https://api.q.qq.com/sns/jscode2session' - const result = await this._requestQQOpenapi({ - name: 'getOpenidByToken', - url, - data: { - grant_type: 'authorization_code', - appid: this.options.appId, - secret: this.options.secret, - js_code: code - } - }) - return result - } -} +const { + UniCloudError +} = require('../../../../common/error') +const { + resolveUrl +} = require('../../../../common/utils') +const { + callQQOpenApi +} = require('../normalize') + +module.exports = class Auth { + constructor (options) { + this.options = Object.assign({ + baseUrl: 'https://graph.qq.com', + timeout: 5000 + }, options) + } + + async _requestQQOpenapi ({ name, url, data, options }) { + const defaultOptions = { + method: 'GET', + dataType: 'json', + dataAsQueryString: true, + timeout: this.options.timeout + } + const result = await callQQOpenApi({ + name: `auth.${name}`, + url: resolveUrl(this.options.baseUrl, url), + data, + options, + defaultOptions + }) + return result + } + + async getUserInfo ({ + accessToken, + openid + } = {}) { + const url = '/user/get_user_info' + const result = await this._requestQQOpenapi({ + name: 'getUserInfo', + url, + data: { + oauthConsumerKey: this.options.appId, + accessToken, + openid + } + }) + return { + nickname: result.nickname, + avatar: result.figureurl_qq_1 + } + } + + async getOpenidByToken ({ + accessToken + } = {}) { + const url = '/oauth2.0/me' + const result = await this._requestQQOpenapi({ + name: 'getOpenidByToken', + url, + data: { + accessToken, + unionid: 1, + fmt: 'json' + } + }) + if (result.clientId !== this.options.appId) { + throw new UniCloudError({ + code: 'APPID_NOT_MATCH', + message: 'appid not match' + }) + } + return { + openid: result.openid, + unionid: result.unionid + } + } + + async code2Session ({ + code + } = {}) { + const url = 'https://api.q.qq.com/sns/jscode2session' + const result = await this._requestQQOpenapi({ + name: 'getOpenidByToken', + url, + data: { + grant_type: 'authorization_code', + appid: this.options.appId, + secret: this.options.secret, + js_code: code + } + }) + return result + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/normalize.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/normalize.js index fcfdc1ef..ca0ebe60 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/normalize.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/normalize.js @@ -1,85 +1,85 @@ -const { - UniCloudError -} = require('../../../common/error') -const { - camel2snakeJson, - snake2camelJson -} = require('../../../common/utils') - -function generateApiResult (apiName, data) { - if (data.ret || data.error) { - // 这三种都是qq的错误码规范 - const code = data.ret || data.error || data.errcode || -2 - const message = data.msg || data.error_description || data.errmsg || `${apiName} fail` - throw new UniCloudError({ - code, - message - }) - } else { - delete data.ret - delete data.msg - delete data.error - delete data.error_description - delete data.errcode - delete data.errmsg - return { - ...data, - errMsg: `${apiName} ok`, - errCode: 0 - } - } -} - -function nomalizeError (apiName, error) { - throw new UniCloudError({ - code: error.code || -2, - message: error.message || `${apiName} fail` - }) -} - -async function callQQOpenApi ({ - name, - url, - data, - options, - defaultOptions -}) { - options = Object.assign({}, defaultOptions, options, { data: camel2snakeJson(Object.assign({}, data)) }) - let result - try { - result = await uniCloud.httpclient.request(url, options) - } catch (e) { - return nomalizeError(name, e) - } - let resData = result.data - const contentType = result.headers['content-type'] - if ( - Buffer.isBuffer(resData) && - (contentType.indexOf('text/plain') === 0 || - contentType.indexOf('application/json') === 0) - ) { - try { - resData = JSON.parse(resData.toString()) - } catch (e) { - resData = resData.toString() - } - } else if (Buffer.isBuffer(resData)) { - resData = { - buffer: resData, - contentType - } - } - return snake2camelJson( - generateApiResult( - name, - resData || { - errCode: -2, - errMsg: 'Request failed' - } - ) - ) -} - -module.exports = { - callQQOpenApi -} +const { + UniCloudError +} = require('../../../common/error') +const { + camel2snakeJson, + snake2camelJson +} = require('../../../common/utils') + +function generateApiResult (apiName, data) { + if (data.ret || data.error) { + // 这三种都是qq的错误码规范 + const code = data.ret || data.error || data.errcode || -2 + const message = data.msg || data.error_description || data.errmsg || `${apiName} fail` + throw new UniCloudError({ + code, + message + }) + } else { + delete data.ret + delete data.msg + delete data.error + delete data.error_description + delete data.errcode + delete data.errmsg + return { + ...data, + errMsg: `${apiName} ok`, + errCode: 0 + } + } +} + +function nomalizeError (apiName, error) { + throw new UniCloudError({ + code: error.code || -2, + message: error.message || `${apiName} fail` + }) +} + +async function callQQOpenApi ({ + name, + url, + data, + options, + defaultOptions +}) { + options = Object.assign({}, defaultOptions, options, { data: camel2snakeJson(Object.assign({}, data)) }) + let result + try { + result = await uniCloud.httpclient.request(url, options) + } catch (e) { + return nomalizeError(name, e) + } + let resData = result.data + const contentType = result.headers['content-type'] + if ( + Buffer.isBuffer(resData) && + (contentType.indexOf('text/plain') === 0 || + contentType.indexOf('application/json') === 0) + ) { + try { + resData = JSON.parse(resData.toString()) + } catch (e) { + resData = resData.toString() + } + } else if (Buffer.isBuffer(resData)) { + resData = { + buffer: resData, + contentType + } + } + return snake2camelJson( + generateApiResult( + name, + resData || { + errCode: -2, + errMsg: 'Request failed' + } + ) + ) +} + +module.exports = { + callQQOpenApi +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/share/create-api.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/share/create-api.js index c58f1e8d..abb1f414 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/share/create-api.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/share/create-api.js @@ -1,73 +1,73 @@ -const { - isFn, - isPlainObject -} = require('../../../common/utils') - -// 注意:不进行递归处理 -function parseParams (params = {}, rule) { - if (!rule || !params) { - return params - } - const internalKeys = ['_pre', '_purify', '_post'] - // 转换之前的处理 - if (rule._pre) { - params = rule._pre(params) - } - // 净化参数 - let purify = { shouldDelete: new Set([]) } - if (rule._purify) { - const _purify = rule._purify - for (const purifyKey in _purify) { - _purify[purifyKey] = new Set(_purify[purifyKey]) - } - purify = Object.assign(purify, _purify) - } - if (isPlainObject(rule)) { - for (const key in rule) { - const parser = rule[key] - if (isFn(parser) && internalKeys.indexOf(key) === -1) { - params[key] = parser(params) - } else if (typeof parser === 'string' && internalKeys.indexOf(key) === -1) { - // 直接转换属性名称的删除旧属性名 - params[key] = params[parser] - purify.shouldDelete.add(parser) - } - } - } else if (isFn(rule)) { - params = rule(params) - } - - if (purify.shouldDelete) { - for (const item of purify.shouldDelete) { - delete params[item] - } - } - - // 转换之后的处理 - if (rule._post) { - params = rule._post(params) - } - - return params -} - -function createApi (ApiClass, options) { - const apiInstance = new ApiClass(options) - return new Proxy(apiInstance, { - get: function (obj, prop) { - if (typeof obj[prop] === 'function' && prop.indexOf('_') !== 0 && obj._protocols && obj._protocols[prop]) { - const protocol = obj._protocols[prop] - return async function (params) { - params = parseParams(params, protocol.args) - let result = await obj[prop](params) - result = parseParams(result, protocol.returnValue) - return result - } - } else { - return obj[prop] - } - } - }) -} - -module.exports = createApi +const { + isFn, + isPlainObject +} = require('../../../common/utils') + +// 注意:不进行递归处理 +function parseParams (params = {}, rule) { + if (!rule || !params) { + return params + } + const internalKeys = ['_pre', '_purify', '_post'] + // 转换之前的处理 + if (rule._pre) { + params = rule._pre(params) + } + // 净化参数 + let purify = { shouldDelete: new Set([]) } + if (rule._purify) { + const _purify = rule._purify + for (const purifyKey in _purify) { + _purify[purifyKey] = new Set(_purify[purifyKey]) + } + purify = Object.assign(purify, _purify) + } + if (isPlainObject(rule)) { + for (const key in rule) { + const parser = rule[key] + if (isFn(parser) && internalKeys.indexOf(key) === -1) { + params[key] = parser(params) + } else if (typeof parser === 'string' && internalKeys.indexOf(key) === -1) { + // 直接转换属性名称的删除旧属性名 + params[key] = params[parser] + purify.shouldDelete.add(parser) + } + } + } else if (isFn(rule)) { + params = rule(params) + } + + if (purify.shouldDelete) { + for (const item of purify.shouldDelete) { + delete params[item] + } + } + + // 转换之后的处理 + if (rule._post) { + params = rule._post(params) + } + + return params +} + +function createApi (ApiClass, options) { + const apiInstance = new ApiClass(options) + return new Proxy(apiInstance, { + get: function (obj, prop) { + if (typeof obj[prop] === 'function' && prop.indexOf('_') !== 0 && obj._protocols && obj._protocols[prop]) { + const protocol = obj._protocols[prop] + return async function (params) { + params = parseParams(params, protocol.args) + let result = await obj[prop](params) + result = parseParams(result, protocol.returnValue) + return result + } + } else { + return obj[prop] + } + } + }) +} + +module.exports = createApi diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/account/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/account/index.js index 5fafc78e..734f6423 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/account/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/account/index.js @@ -1,89 +1,111 @@ -const { - callWxOpenApi, - buildUrl -} = require('../normalize') - -module.exports = class Auth { - constructor (options) { - this.options = Object.assign({ - baseUrl: 'https://api.weixin.qq.com', - timeout: 5000 - }, options) - } - - async _requestWxOpenapi ({ name, url, data, options }) { - const defaultOptions = { - method: 'GET', - dataType: 'json', - dataAsQueryString: true, - timeout: this.options.timeout - } - const result = await callWxOpenApi({ - name: `auth.${name}`, - url: `${this.options.baseUrl}${buildUrl(url, data)}`, - data, - options, - defaultOptions - }) - return result - } - - async code2Session (code) { - const url = '/sns/jscode2session' - const result = await this._requestWxOpenapi({ - name: 'code2Session', - url, - data: { - grant_type: 'authorization_code', - appid: this.options.appId, - secret: this.options.secret, - js_code: code - } - }) - return result - } - - async getOauthAccessToken (code) { - const url = '/sns/oauth2/access_token' - const result = await this._requestWxOpenapi({ - name: 'getOauthAccessToken', - url, - data: { - grant_type: 'authorization_code', - appid: this.options.appId, - secret: this.options.secret, - code - } - }) - if (result.expiresIn) { - result.expired = Date.now() + result.expiresIn * 1000 - // delete result.expiresIn - } - return result - } - - async getUserInfo ({ - accessToken, - openid - } = {}) { - const url = '/sns/userinfo' - const { - nickname, - headimgurl: avatar - } = await this._requestWxOpenapi({ - name: 'getUserInfo', - url, - data: { - accessToken, - openid, - appid: this.options.appId, - secret: this.options.secret, - scope: 'snsapi_userinfo' - } - }) - return { - nickname, - avatar - } - } -} +const { + callWxOpenApi, + buildUrl +} = require('../normalize') + +module.exports = class Auth { + constructor (options) { + this.options = Object.assign({ + baseUrl: 'https://api.weixin.qq.com', + timeout: 5000 + }, options) + } + + async _requestWxOpenapi ({ name, url, data, options }) { + const defaultOptions = { + method: 'GET', + dataType: 'json', + dataAsQueryString: true, + timeout: this.options.timeout + } + const result = await callWxOpenApi({ + name: `auth.${name}`, + url: `${this.options.baseUrl}${buildUrl(url, data)}`, + data, + options, + defaultOptions + }) + return result + } + + async code2Session (code) { + const url = '/sns/jscode2session' + const result = await this._requestWxOpenapi({ + name: 'code2Session', + url, + data: { + grant_type: 'authorization_code', + appid: this.options.appId, + secret: this.options.secret, + js_code: code + } + }) + return result + } + + async getOauthAccessToken (code) { + const url = '/sns/oauth2/access_token' + const result = await this._requestWxOpenapi({ + name: 'getOauthAccessToken', + url, + data: { + grant_type: 'authorization_code', + appid: this.options.appId, + secret: this.options.secret, + code + } + }) + if (result.expiresIn) { + result.expired = Date.now() + result.expiresIn * 1000 + // delete result.expiresIn + } + return result + } + + async getUserInfo ({ + accessToken, + openid + } = {}) { + const url = '/sns/userinfo' + const { + nickname, + headimgurl: avatar + } = await this._requestWxOpenapi({ + name: 'getUserInfo', + url, + data: { + accessToken, + openid, + appid: this.options.appId, + secret: this.options.secret, + scope: 'snsapi_userinfo' + } + }) + return { + nickname, + avatar + } + } + + async getPhoneNumber (accessToken, code) { + const url = `/wxa/business/getuserphonenumber?access_token=${accessToken}` + const { phoneInfo } = await this._requestWxOpenapi({ + name: 'getPhoneNumber', + url, + data: { + code + }, + options: { + method: 'POST', + dataAsQueryString: false, + headers: { + 'content-type': 'application/json' + } + } + }) + + return { + purePhoneNumber: phoneInfo.purePhoneNumber + } + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/normalize.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/normalize.js index 908d916d..9749c383 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/normalize.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/normalize.js @@ -1,95 +1,95 @@ -const { - UniCloudError -} = require('../../../common/error') -const { - camel2snakeJson, snake2camelJson -} = require('../../../common/utils') - -function generateApiResult (apiName, data) { - if (data.errcode) { - throw new UniCloudError({ - code: data.errcode || -2, - message: data.errmsg || `${apiName} fail` - }) - } else { - delete data.errcode - delete data.errmsg - return { - ...data, - errMsg: `${apiName} ok`, - errCode: 0 - } - } -} - -function nomalizeError (apiName, error) { - throw new UniCloudError({ - code: error.code || -2, - message: error.message || `${apiName} fail` - }) -} - -// 微信openapi接口接收蛇形(snake case)参数返回蛇形参数,这里进行转化,如果是formdata里面的参数需要在对应api实现时就转为蛇形 -async function callWxOpenApi ({ - name, - url, - data, - options, - defaultOptions -}) { - let result = {} - // 获取二维码的接口wxacode.get和wxacode.getUnlimited不可以传入access_token(可能有其他接口也不可以),否则会返回data format error - const dataCopy = camel2snakeJson(Object.assign({}, data)) - if (dataCopy && dataCopy.access_token) { - delete dataCopy.access_token - } - try { - options = Object.assign({}, defaultOptions, options, { data: dataCopy }) - result = await uniCloud.httpclient.request(url, options) - } catch (e) { - return nomalizeError(name, e) - } - - // 有几个接口成功返回buffer失败返回json,对这些接口统一成返回buffer,然后分别解析 - let resData = result.data - const contentType = result.headers['content-type'] - if ( - Buffer.isBuffer(resData) && - (contentType.indexOf('text/plain') === 0 || - contentType.indexOf('application/json') === 0) - ) { - try { - resData = JSON.parse(resData.toString()) - } catch (e) { - resData = resData.toString() - } - } else if (Buffer.isBuffer(resData)) { - resData = { - buffer: resData, - contentType - } - } - return snake2camelJson( - generateApiResult( - name, - resData || { - errCode: -2, - errMsg: 'Request failed' - } - ) - ) -} - -function buildUrl (url, data) { - let query = '' - if (data && data.accessToken) { - const divider = url.indexOf('?') > -1 ? '&' : '?' - query = `${divider}access_token=${data.accessToken}` - } - return `${url}${query}` -} - -module.exports = { - callWxOpenApi, - buildUrl -} +const { + UniCloudError +} = require('../../../common/error') +const { + camel2snakeJson, snake2camelJson +} = require('../../../common/utils') + +function generateApiResult (apiName, data) { + if (data.errcode) { + throw new UniCloudError({ + code: data.errcode || -2, + message: data.errmsg || `${apiName} fail` + }) + } else { + delete data.errcode + delete data.errmsg + return { + ...data, + errMsg: `${apiName} ok`, + errCode: 0 + } + } +} + +function nomalizeError (apiName, error) { + throw new UniCloudError({ + code: error.code || -2, + message: error.message || `${apiName} fail` + }) +} + +// 微信openapi接口接收蛇形(snake case)参数返回蛇形参数,这里进行转化,如果是formdata里面的参数需要在对应api实现时就转为蛇形 +async function callWxOpenApi ({ + name, + url, + data, + options, + defaultOptions +}) { + let result = {} + // 获取二维码的接口wxacode.get和wxacode.getUnlimited不可以传入access_token(可能有其他接口也不可以),否则会返回data format error + const dataCopy = camel2snakeJson(Object.assign({}, data)) + if (dataCopy && dataCopy.access_token) { + delete dataCopy.access_token + } + try { + options = Object.assign({}, defaultOptions, options, { data: dataCopy }) + result = await uniCloud.httpclient.request(url, options) + } catch (e) { + return nomalizeError(name, e) + } + + // 有几个接口成功返回buffer失败返回json,对这些接口统一成返回buffer,然后分别解析 + let resData = result.data + const contentType = result.headers['content-type'] + if ( + Buffer.isBuffer(resData) && + (contentType.indexOf('text/plain') === 0 || + contentType.indexOf('application/json') === 0) + ) { + try { + resData = JSON.parse(resData.toString()) + } catch (e) { + resData = resData.toString() + } + } else if (Buffer.isBuffer(resData)) { + resData = { + buffer: resData, + contentType + } + } + return snake2camelJson( + generateApiResult( + name, + resData || { + errCode: -2, + errMsg: 'Request failed' + } + ) + ) +} + +function buildUrl (url, data) { + let query = '' + if (data && data.accessToken) { + const divider = url.indexOf('?') > -1 ? '&' : '?' + query = `${divider}access_token=${data.accessToken}` + } + return `${url}${query}` +} + +module.exports = { + callWxOpenApi, + buildUrl +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/utils.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/utils.js index c1410169..acb053ad 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/utils.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/utils.js @@ -1,87 +1,87 @@ -const crypto = require('crypto') -const { - isPlainObject -} = require('../../../common/utils') - -// 退款通知解密key=md5(key) -function decryptData (encryptedData, key, iv = '') { - // 解密 - const decipher = crypto.createDecipheriv('aes-128-cbc', key, iv) - // 设置自动 padding 为 true,删除填充补位 - decipher.setAutoPadding(true) - let decoded = decipher.update(encryptedData, 'base64', 'utf8') - decoded += decipher.final('utf8') - return decoded -} - -function md5 (str, encoding = 'utf8') { - return crypto - .createHash('md5') - .update(str, encoding) - .digest('hex') -} - -function sha256 (str, key, encoding = 'utf8') { - return crypto - .createHmac('sha256', key) - .update(str, encoding) - .digest('hex') -} - -function getSignStr (obj) { - return Object.keys(obj) - .filter(key => key !== 'sign' && obj[key] !== undefined && obj[key] !== '') - .sort() - .map(key => key + '=' + obj[key]) - .join('&') -} - -function getNonceStr (length = 16) { - let str = '' - while (str.length < length) { - str += Math.random().toString(32).substring(2) - } - return str.substring(0, length) -} - -// 简易版Object转XML,只可在微信支付时使用,不支持嵌套 -function buildXML (obj, rootName = 'xml') { - const content = Object.keys(obj).map(item => { - if (isPlainObject(obj[item])) { - return `<${item}>` - } else { - return `<${item}>` - } - }) - return `<${rootName}>${content.join('')}` -} - -function isXML (str) { - const reg = /^(<\?xml.*\?>)?(\r?\n)*(.|\r?\n)*<\/xml>$/i - return reg.test(str.trim()) -}; - -// 简易版XML转Object,只可在微信支付时使用,不支持嵌套 -function parseXML (xml) { - const xmlReg = /<(?:xml|root).*?>([\s|\S]*)<\/(?:xml|root)>/ - const str = xmlReg.exec(xml)[1] - const obj = {} - const nodeReg = /<(.*?)>(?:){0,1}<\/.*?>/g - let matches = null - // eslint-disable-next-line no-cond-assign - while ((matches = nodeReg.exec(str))) { - obj[matches[1]] = matches[2] - } - return obj -} - -module.exports = { - decryptData, - md5, - sha256, - getSignStr, - getNonceStr, - buildXML, - parseXML, - isXML -} +const crypto = require('crypto') +const { + isPlainObject +} = require('../../../common/utils') + +// 退款通知解密key=md5(key) +function decryptData (encryptedData, key, iv = '') { + // 解密 + const decipher = crypto.createDecipheriv('aes-128-cbc', key, iv) + // 设置自动 padding 为 true,删除填充补位 + decipher.setAutoPadding(true) + let decoded = decipher.update(encryptedData, 'base64', 'utf8') + decoded += decipher.final('utf8') + return decoded +} + +function md5 (str, encoding = 'utf8') { + return crypto + .createHash('md5') + .update(str, encoding) + .digest('hex') +} + +function sha256 (str, key, encoding = 'utf8') { + return crypto + .createHmac('sha256', key) + .update(str, encoding) + .digest('hex') +} + +function getSignStr (obj) { + return Object.keys(obj) + .filter(key => key !== 'sign' && obj[key] !== undefined && obj[key] !== '') + .sort() + .map(key => key + '=' + obj[key]) + .join('&') +} + +function getNonceStr (length = 16) { + let str = '' + while (str.length < length) { + str += Math.random().toString(32).substring(2) + } + return str.substring(0, length) +} + +// 简易版Object转XML,只可在微信支付时使用,不支持嵌套 +function buildXML (obj, rootName = 'xml') { + const content = Object.keys(obj).map(item => { + if (isPlainObject(obj[item])) { + return `<${item}>` + } else { + return `<${item}>` + } + }) + return `<${rootName}>${content.join('')}` +} + +function isXML (str) { + const reg = /^(<\?xml.*\?>)?(\r?\n)*(.|\r?\n)*<\/xml>$/i + return reg.test(str.trim()) +}; + +// 简易版XML转Object,只可在微信支付时使用,不支持嵌套 +function parseXML (xml) { + const xmlReg = /<(?:xml|root).*?>([\s|\S]*)<\/(?:xml|root)>/ + const str = xmlReg.exec(xml)[1] + const obj = {} + const nodeReg = /<(.*?)>(?:){0,1}<\/.*?>/g + let matches = null + // eslint-disable-next-line no-cond-assign + while ((matches = nodeReg.exec(str))) { + obj[matches[1]] = matches[2] + } + return obj +} + +module.exports = { + decryptData, + md5, + sha256, + getSignStr, + getNonceStr, + buildXML, + parseXML, + isXML +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/account.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/account.js index c62e3ebf..bc87e029 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/account.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/account.js @@ -1,130 +1,130 @@ -const { - db, - dbCmd, - userCollection -} = require('../../common/constants') -const { - USER_IDENTIFIER -} = require('../../common/constants') -const { - batchFindObjctValue, - getType -} = require('../../common/utils') - -/** - * 查询满足条件的用户 - * @param {Object} params - * @param {Object} params.userQuery 用户唯一标识组成的查询条件 - * @param {Object} params.authorizedApp 用户允许登录的应用 - * @returns userMatched 满足条件的用户列表 - */ -async function findUser (params = {}) { - const { - userQuery, - authorizedApp = [] - } = params - const condition = getUserQueryCondition(userQuery) - if (condition.length === 0) { - throw new Error('Invalid user query') - } - const authorizedAppType = getType(authorizedApp) - let appQuery = null - if (authorizedAppType === 'string') { - // 传入authorizedApp为单个appId时 - appQuery = dbCmd.or( - { - dcloud_appid: authorizedApp - }, - { - dcloud_appid: dbCmd.exists(false) - } - ) - } else if (authorizedAppType === 'array') { - if (authorizedApp.length === 0) { - // 传入空数组表示希望获取不能登录任一客户端的用户 - appQuery = { - dcloud_appid: [] - } - } else if (authorizedApp.length === 1) { - appQuery = dbCmd.or( - { - dcloud_appid: authorizedApp[0] - }, - { - dcloud_appid: dbCmd.exists(false) - } - ) - } else { - appQuery = dbCmd.or( - { - dcloud_appid: db.command.in(authorizedApp) - }, - { - dcloud_appid: dbCmd.exists(false) - } - ) - } - } else { - throw new Error('Invalid authorized app') - } - - let finalQuery - - if (condition.length === 1) { - finalQuery = dbCmd.and(condition[0], appQuery) - } else { - finalQuery = dbCmd.and( - dbCmd.or(condition), - appQuery - ) - } - const userQueryRes = await userCollection.where(finalQuery).get() - return userQueryRes.data -} - -function getUserIdentifier (userRecord = {}) { - const keys = Object.keys(USER_IDENTIFIER) - return batchFindObjctValue(userRecord, keys) -} - -function getUserQueryCondition (userRecord = {}) { - const userIdentifier = getUserIdentifier(userRecord) - const condition = [] - for (const key in userIdentifier) { - const value = userIdentifier[key] - if (!value) { - // 过滤所有value为假值的条件,在查询用户时没有意义 - continue - } - const queryItem = { - [key]: value - } - // 为兼容用户老数据用户名及邮箱需要同时查小写及原始大小写数据 - if (key === 'mobile') { - queryItem.mobile_confirmed = 1 - } else if (key === 'email') { - queryItem.email_confirmed = 1 - const email = userIdentifier.email - if (email.toLowerCase() !== email) { - condition.push({ - email: email.toLowerCase(), - email_confirmed: 1 - }) - } - } else if (key === 'username') { - const username = userIdentifier.username - if (username.toLowerCase() !== username) { - condition.push({ - username: username.toLowerCase() - }) - } - } - condition.push(queryItem) - } - return condition -} - -module.exports = { - findUser, - getUserIdentifier -} +const { + db, + dbCmd, + userCollection +} = require('../../common/constants') +const { + USER_IDENTIFIER +} = require('../../common/constants') +const { + batchFindObjctValue, + getType +} = require('../../common/utils') + +/** + * 查询满足条件的用户 + * @param {Object} params + * @param {Object} params.userQuery 用户唯一标识组成的查询条件 + * @param {Object} params.authorizedApp 用户允许登录的应用 + * @returns userMatched 满足条件的用户列表 + */ +async function findUser (params = {}) { + const { + userQuery, + authorizedApp = [] + } = params + const condition = getUserQueryCondition(userQuery) + if (condition.length === 0) { + throw new Error('Invalid user query') + } + const authorizedAppType = getType(authorizedApp) + let appQuery = null + if (authorizedAppType === 'string') { + // 传入authorizedApp为单个appId时 + appQuery = dbCmd.or( + { + dcloud_appid: authorizedApp + }, + { + dcloud_appid: dbCmd.exists(false) + } + ) + } else if (authorizedAppType === 'array') { + if (authorizedApp.length === 0) { + // 传入空数组表示希望获取不能登录任一客户端的用户 + appQuery = { + dcloud_appid: [] + } + } else if (authorizedApp.length === 1) { + appQuery = dbCmd.or( + { + dcloud_appid: authorizedApp[0] + }, + { + dcloud_appid: dbCmd.exists(false) + } + ) + } else { + appQuery = dbCmd.or( + { + dcloud_appid: db.command.in(authorizedApp) + }, + { + dcloud_appid: dbCmd.exists(false) + } + ) + } + } else { + throw new Error('Invalid authorized app') + } + + let finalQuery + + if (condition.length === 1) { + finalQuery = dbCmd.and(condition[0], appQuery) + } else { + finalQuery = dbCmd.and( + dbCmd.or(condition), + appQuery + ) + } + const userQueryRes = await userCollection.where(finalQuery).get() + return userQueryRes.data +} + +function getUserIdentifier (userRecord = {}) { + const keys = Object.keys(USER_IDENTIFIER) + return batchFindObjctValue(userRecord, keys) +} + +function getUserQueryCondition (userRecord = {}) { + const userIdentifier = getUserIdentifier(userRecord) + const condition = [] + for (const key in userIdentifier) { + const value = userIdentifier[key] + if (!value) { + // 过滤所有value为假值的条件,在查询用户时没有意义 + continue + } + const queryItem = { + [key]: value + } + // 为兼容用户老数据用户名及邮箱需要同时查小写及原始大小写数据 + if (key === 'mobile') { + queryItem.mobile_confirmed = 1 + } else if (key === 'email') { + queryItem.email_confirmed = 1 + const email = userIdentifier.email + if (email.toLowerCase() !== email) { + condition.push({ + email: email.toLowerCase(), + email_confirmed: 1 + }) + } + } else if (key === 'username') { + const username = userIdentifier.username + if (username.toLowerCase() !== username) { + condition.push({ + username: username.toLowerCase() + }) + } + } + condition.push(queryItem) + } + return condition +} + +module.exports = { + findUser, + getUserIdentifier +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/captcha.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/captcha.js index 4618fa5d..726f4060 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/captcha.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/captcha.js @@ -1,76 +1,76 @@ -const { - ERROR -} = require('../../common/error') - -async function getNeedCaptcha ({ - uid, - username, - mobile, - email, - type = 'login', - limitDuration = 7200000, // 两小时 - limitTimes = 3 // 记录次数 -} = {}) { - const db = uniCloud.database() - const dbCmd = db.command - // 当用户最近“2小时内(limitDuration)”登录失败达到3次(limitTimes)时。要求用户提交验证码 - const now = Date.now() - const uniIdLogCollection = db.collection('uni-id-log') - const userIdentifier = { - user_id: uid, - username, - mobile, - email - } - - let totalKey = 0; let deleteKey = 0 - for (const key in userIdentifier) { - totalKey++ - if (!userIdentifier[key] || typeof userIdentifier[key] !== 'string') { - deleteKey++ - delete userIdentifier[key] - } - } - - if (deleteKey === totalKey) { - throw new Error('System error') // 正常情况下不会进入此条件,但是考虑到后续会有其他开发者修改此云对象,在此处做一个判断 - } - - const { - data: recentRecord - } = await uniIdLogCollection.where({ - ip: this.getClientInfo().clientIP, - ...userIdentifier, - type, - create_date: dbCmd.gt(now - limitDuration) - }) - .orderBy('create_date', 'desc') - .limit(limitTimes) - .get() - return recentRecord.length === limitTimes && recentRecord.every(item => item.state === 0) -} - -async function verifyCaptcha (params = {}) { - const { - captcha, - scene - } = params - if (!captcha) { - throw { - errCode: ERROR.CAPTCHA_REQUIRED - } - } - const payload = await this.uniCaptcha.verify({ - deviceId: this.getClientInfo().deviceId, - captcha, - scene - }) - if (payload.errCode) { - throw payload - } -} - -module.exports = { - getNeedCaptcha, - verifyCaptcha -} +const { + ERROR +} = require('../../common/error') + +async function getNeedCaptcha ({ + uid, + username, + mobile, + email, + type = 'login', + limitDuration = 7200000, // 两小时 + limitTimes = 3 // 记录次数 +} = {}) { + const db = uniCloud.database() + const dbCmd = db.command + // 当用户最近“2小时内(limitDuration)”登录失败达到3次(limitTimes)时。要求用户提交验证码 + const now = Date.now() + const uniIdLogCollection = db.collection('uni-id-log') + const userIdentifier = { + user_id: uid, + username, + mobile, + email + } + + let totalKey = 0; let deleteKey = 0 + for (const key in userIdentifier) { + totalKey++ + if (!userIdentifier[key] || typeof userIdentifier[key] !== 'string') { + deleteKey++ + delete userIdentifier[key] + } + } + + if (deleteKey === totalKey) { + throw new Error('System error') // 正常情况下不会进入此条件,但是考虑到后续会有其他开发者修改此云对象,在此处做一个判断 + } + + const { + data: recentRecord + } = await uniIdLogCollection.where({ + ip: this.getClientInfo().clientIP, + ...userIdentifier, + type, + create_date: dbCmd.gt(now - limitDuration) + }) + .orderBy('create_date', 'desc') + .limit(limitTimes) + .get() + return recentRecord.length === limitTimes && recentRecord.every(item => item.state === 0) +} + +async function verifyCaptcha (params = {}) { + const { + captcha, + scene + } = params + if (!captcha) { + throw { + errCode: ERROR.CAPTCHA_REQUIRED + } + } + const payload = await this.uniCaptcha.verify({ + deviceId: this.getClientInfo().deviceId, + captcha, + scene + }) + if (payload.errCode) { + throw payload + } +} + +module.exports = { + getNeedCaptcha, + verifyCaptcha +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/config.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/config.js index fdc71605..47416bec 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/config.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/config.js @@ -1,135 +1,135 @@ -const { - getWeixinPlatform -} = require('./weixin') -const createConfig = require('uni-config-center') - -const requiredConfig = { - 'web.weixin-h5': ['appid', 'appsecret'], - 'web.weixin-web': ['appid', 'appsecret'], - 'app.weixin': ['appid', 'appsecret'], - 'mp-weixin.weixin': ['appid', 'appsecret'], - 'app.qq': ['appid', 'appsecret'], - 'mp-alipay.alipay': ['appid', 'privateKey'], - 'app.apple': ['bundleId'] -} - -const uniIdConfig = createConfig({ - pluginId: 'uni-id' -}) - -class ConfigUtils { - constructor ({ - context - } = {}) { - this.context = context - this.clientInfo = context.getClientInfo() - const { - appId, - uniPlatform - } = this.clientInfo - this.appId = appId - switch (uniPlatform) { - case 'app': - case 'app-plus': - this.platform = 'app' - break - case 'web': - case 'h5': - this.platform = 'web' - break - default: - this.platform = uniPlatform - break - } - } - - getConfigArray () { - let configContent - try { - configContent = require('uni-config-center/uni-id/config.json') - } catch (error) { - throw new Error('Invalid config file\n' + error.message) - } - if (configContent[0]) { - return Object.values(configContent) - } - configContent.isDefaultConfig = true - return [configContent] - } - - getAppConfig () { - const configArray = this.getConfigArray() - return configArray.find(item => item.dcloudAppid === this.appId) || configArray.find(item => item.isDefaultConfig) - } - - getPlatformConfig () { - const appConfig = this.getAppConfig() - if (!appConfig) { - throw new Error( - `Config for current app (${this.appId}) was not found, please check your config file or client appId`) - } - const platform = this.platform - if ( - (this.platform === 'app' && appConfig['app-plus']) || - (this.platform === 'web' && appConfig.h5) - ) { - throw new Error( - `Client platform is ${this.platform}, but ${this.platform === 'web' ? 'h5' : 'app-plus'} was found in config. Please refer to: https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary?id=m-to-co` - ) - } - - const defaultConfig = { - tokenExpiresIn: 7200, - tokenExpiresThreshold: 1200, - passwordErrorLimit: 6, - passwordErrorRetryTime: 3600 - } - return Object.assign(defaultConfig, appConfig, appConfig[platform]) - } - - getOauthProvider ({ - provider - } = {}) { - const clientPlatform = this.platform - let oatuhProivder = provider - if (provider === 'weixin' && clientPlatform === 'web') { - const weixinPlatform = getWeixinPlatform.call(this.context) - if (weixinPlatform === 'h5' || weixinPlatform === 'web') { - oatuhProivder = 'weixin-' + weixinPlatform // weixin-h5 公众号,weixin-web pc端 - } - } - return oatuhProivder - } - - getOauthConfig ({ - provider - } = {}) { - const config = this.getPlatformConfig() - const clientPlatform = this.platform - const oatuhProivder = this.getOauthProvider({ - provider - }) - const requireConfigKey = requiredConfig[`${clientPlatform}.${oatuhProivder}`] || [] - if (!config.oauth || !config.oauth[oatuhProivder]) { - throw new Error(`Config param required: ${clientPlatform}.oauth.${oatuhProivder}`) - } - const oauthConfig = config.oauth[oatuhProivder] - requireConfigKey.forEach((item) => { - if (!oauthConfig[item]) { - throw new Error(`Config param required: ${clientPlatform}.oauth.${oatuhProivder}.${item}`) - } - }) - return oauthConfig - } - - getHooks () { - if (uniIdConfig.hasFile('hooks/index.js')) { - return require( - uniIdConfig.resolve('hooks/index.js') - ) - } - return {} - } -} - -module.exports = ConfigUtils +const { + getWeixinPlatform +} = require('./weixin') +const createConfig = require('uni-config-center') + +const requiredConfig = { + 'web.weixin-h5': ['appid', 'appsecret'], + 'web.weixin-web': ['appid', 'appsecret'], + 'app.weixin': ['appid', 'appsecret'], + 'mp-weixin.weixin': ['appid', 'appsecret'], + 'app.qq': ['appid', 'appsecret'], + 'mp-alipay.alipay': ['appid', 'privateKey'], + 'app.apple': ['bundleId'] +} + +const uniIdConfig = createConfig({ + pluginId: 'uni-id' +}) + +class ConfigUtils { + constructor ({ + context + } = {}) { + this.context = context + this.clientInfo = context.getClientInfo() + const { + appId, + uniPlatform + } = this.clientInfo + this.appId = appId + switch (uniPlatform) { + case 'app': + case 'app-plus': + this.platform = 'app' + break + case 'web': + case 'h5': + this.platform = 'web' + break + default: + this.platform = uniPlatform + break + } + } + + getConfigArray () { + let configContent + try { + configContent = require('uni-config-center/uni-id/config.json') + } catch (error) { + throw new Error('Invalid config file\n' + error.message) + } + if (configContent[0]) { + return Object.values(configContent) + } + configContent.isDefaultConfig = true + return [configContent] + } + + getAppConfig () { + const configArray = this.getConfigArray() + return configArray.find(item => item.dcloudAppid === this.appId) || configArray.find(item => item.isDefaultConfig) + } + + getPlatformConfig () { + const appConfig = this.getAppConfig() + if (!appConfig) { + throw new Error( + `Config for current app (${this.appId}) was not found, please check your config file or client appId`) + } + const platform = this.platform + if ( + (this.platform === 'app' && appConfig['app-plus']) || + (this.platform === 'web' && appConfig.h5) + ) { + throw new Error( + `Client platform is ${this.platform}, but ${this.platform === 'web' ? 'h5' : 'app-plus'} was found in config. Please refer to: https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary?id=m-to-co` + ) + } + + const defaultConfig = { + tokenExpiresIn: 7200, + tokenExpiresThreshold: 1200, + passwordErrorLimit: 6, + passwordErrorRetryTime: 3600 + } + return Object.assign(defaultConfig, appConfig, appConfig[platform]) + } + + getOauthProvider ({ + provider + } = {}) { + const clientPlatform = this.platform + let oatuhProivder = provider + if (provider === 'weixin' && clientPlatform === 'web') { + const weixinPlatform = getWeixinPlatform.call(this.context) + if (weixinPlatform === 'h5' || weixinPlatform === 'web') { + oatuhProivder = 'weixin-' + weixinPlatform // weixin-h5 公众号,weixin-web pc端 + } + } + return oatuhProivder + } + + getOauthConfig ({ + provider + } = {}) { + const config = this.getPlatformConfig() + const clientPlatform = this.platform + const oatuhProivder = this.getOauthProvider({ + provider + }) + const requireConfigKey = requiredConfig[`${clientPlatform}.${oatuhProivder}`] || [] + if (!config.oauth || !config.oauth[oatuhProivder]) { + throw new Error(`Config param required: ${clientPlatform}.oauth.${oatuhProivder}`) + } + const oauthConfig = config.oauth[oatuhProivder] + requireConfigKey.forEach((item) => { + if (!oauthConfig[item]) { + throw new Error(`Config param required: ${clientPlatform}.oauth.${oatuhProivder}.${item}`) + } + }) + return oauthConfig + } + + getHooks () { + if (uniIdConfig.hasFile('hooks/index.js')) { + return require( + uniIdConfig.resolve('hooks/index.js') + ) + } + return {} + } +} + +module.exports = ConfigUtils diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/fission.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/fission.js index 84233c3e..65d48e27 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/fission.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/fission.js @@ -1,192 +1,192 @@ -const { - dbCmd, - userCollection -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') -/** - * 获取随机邀请码,邀请码由大写字母加数字组成,由于存在手动输入邀请码的场景,从可选字符中去除 0、1、I、O - * @param {number} len 邀请码长度,默认6位 - * @returns {string} 随机邀请码 - */ -function getRandomInviteCode (len = 6) { - const charArr = ['2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] - let code = '' - for (let i = 0; i < len; i++) { - code += charArr[Math.floor(Math.random() * charArr.length)] - } - return code -} - -/** - * 获取可用的邀请码,至多尝试十次以获取可用邀请码。从10亿可选值中随机,碰撞概率较低 - * 也有其他方案可以尝试,比如在数据库内设置一个从0开始计数的数字,每次调用此方法时使用updateAndReturn使数字加1并返回加1后的值,根据这个值生成对应的邀请码,比如(22222A + 1 == 22222B),此方式性能理论更好,但是不适用于旧项目 - * @param {object} param - * @param {string} param.inviteCode 初始随机邀请码 - */ -async function getValidInviteCode () { - let retry = 10 - let code - let codeValid = false - while (retry > 0 && !codeValid) { - retry-- - code = getRandomInviteCode() - const getUserRes = await userCollection.where({ - my_invite_code: code - }).limit(1).get() - if (getUserRes.data.length === 0) { - codeValid = true - break - } - } - if (!codeValid) { - throw { - errCode: ERROR.SET_INVITE_CODE_FAILED - } - } - return code -} - -/** - * 根据邀请码查询邀请人 - * @param {object} param - * @param {string} param.inviteCode 邀请码 - * @param {string} param.queryUid 受邀人id,非空时校验不可被下家或自己邀请 - * @returns - */ -async function findUserByInviteCode ({ - inviteCode, - queryUid -} = {}) { - if (typeof inviteCode !== 'string') { - throw { - errCode: ERROR.SYSTEM_ERROR - } - } - // 根据邀请码查询邀请人 - let getInviterRes - if (queryUid) { - getInviterRes = await userCollection.where({ - _id: dbCmd.neq(queryUid), - inviter_uid: dbCmd.not(dbCmd.all([queryUid])), - my_invite_code: inviteCode - }).get() - } else { - getInviterRes = await userCollection.where({ - my_invite_code: inviteCode - }).get() - } - if (getInviterRes.data.length > 1) { - // 正常情况下不可能进入此条件,以防用户自行修改数据库出错,在此做出判断 - throw { - errCode: ERROR.SYSTEM_ERROR - } - } - const inviterRecord = getInviterRes.data[0] - if (!inviterRecord) { - throw { - errCode: ERROR.INVALID_INVITE_CODE - } - } - return inviterRecord -} - -/** - * 根据邀请码生成邀请信息 - * @param {object} param - * @param {string} param.inviteCode 邀请码 - * @param {string} param.queryUid 受邀人id,非空时校验不可被下家或自己邀请 - * @returns - */ -async function generateInviteInfo ({ - inviteCode, - queryUid -} = {}) { - const inviterRecord = await findUserByInviteCode({ - inviteCode, - queryUid - }) - // 倒叙拼接当前用户邀请链 - const inviterUid = inviterRecord.inviter_uid || [] - inviterUid.unshift(inviterRecord._id) - return { - inviterUid, - inviteTime: Date.now() - } -} - -/** - * 检查当前用户是否可以接受邀请,如果可以返回用户记录 - * @param {string} uid - */ -async function checkInviteInfo (uid) { - // 检查当前用户是否已有邀请人 - const getUserRes = await userCollection.doc(uid).field({ - my_invite_code: true, - inviter_uid: true - }).get() - const userRecord = getUserRes.data[0] - if (!userRecord) { - throw { - errCode: ERROR.ACCOUNT_NOT_EXISTS - } - } - if (userRecord.inviter_uid && userRecord.inviter_uid.length > 0) { - throw { - errCode: ERROR.CHANGE_INVITER_FORBIDDEN - } - } - return userRecord -} - -/** - * 指定用户接受邀请码邀请 - * @param {object} param - * @param {string} param.uid 用户uid - * @param {string} param.inviteCode 邀请人的邀请码 - * @returns - */ -async function acceptInvite ({ - uid, - inviteCode -} = {}) { - await checkInviteInfo(uid) - const { - inviterUid, - inviteTime - } = await generateInviteInfo({ - inviteCode, - queryUid: uid - }) - - if (inviterUid === uid) { - throw { - errCode: ERROR.INVALID_INVITE_CODE - } - } - - // 更新当前用户的邀请人信息 - await userCollection.doc(uid).update({ - inviter_uid: inviterUid, - invite_time: inviteTime - }) - - // 更新当前用户邀请的用户的邀请人信息,这步可能较为耗时 - await userCollection.where({ - inviter_uid: uid - }).update({ - inviter_uid: dbCmd.push(inviterUid) - }) - - return { - errCode: 0, - errMsg: '' - } -} - -module.exports = { - acceptInvite, - generateInviteInfo, - getValidInviteCode -} +const { + dbCmd, + userCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +/** + * 获取随机邀请码,邀请码由大写字母加数字组成,由于存在手动输入邀请码的场景,从可选字符中去除 0、1、I、O + * @param {number} len 邀请码长度,默认6位 + * @returns {string} 随机邀请码 + */ +function getRandomInviteCode (len = 6) { + const charArr = ['2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] + let code = '' + for (let i = 0; i < len; i++) { + code += charArr[Math.floor(Math.random() * charArr.length)] + } + return code +} + +/** + * 获取可用的邀请码,至多尝试十次以获取可用邀请码。从10亿可选值中随机,碰撞概率较低 + * 也有其他方案可以尝试,比如在数据库内设置一个从0开始计数的数字,每次调用此方法时使用updateAndReturn使数字加1并返回加1后的值,根据这个值生成对应的邀请码,比如(22222A + 1 == 22222B),此方式性能理论更好,但是不适用于旧项目 + * @param {object} param + * @param {string} param.inviteCode 初始随机邀请码 + */ +async function getValidInviteCode () { + let retry = 10 + let code + let codeValid = false + while (retry > 0 && !codeValid) { + retry-- + code = getRandomInviteCode() + const getUserRes = await userCollection.where({ + my_invite_code: code + }).limit(1).get() + if (getUserRes.data.length === 0) { + codeValid = true + break + } + } + if (!codeValid) { + throw { + errCode: ERROR.SET_INVITE_CODE_FAILED + } + } + return code +} + +/** + * 根据邀请码查询邀请人 + * @param {object} param + * @param {string} param.inviteCode 邀请码 + * @param {string} param.queryUid 受邀人id,非空时校验不可被下家或自己邀请 + * @returns + */ +async function findUserByInviteCode ({ + inviteCode, + queryUid +} = {}) { + if (typeof inviteCode !== 'string') { + throw { + errCode: ERROR.SYSTEM_ERROR + } + } + // 根据邀请码查询邀请人 + let getInviterRes + if (queryUid) { + getInviterRes = await userCollection.where({ + _id: dbCmd.neq(queryUid), + inviter_uid: dbCmd.not(dbCmd.all([queryUid])), + my_invite_code: inviteCode + }).get() + } else { + getInviterRes = await userCollection.where({ + my_invite_code: inviteCode + }).get() + } + if (getInviterRes.data.length > 1) { + // 正常情况下不可能进入此条件,以防用户自行修改数据库出错,在此做出判断 + throw { + errCode: ERROR.SYSTEM_ERROR + } + } + const inviterRecord = getInviterRes.data[0] + if (!inviterRecord) { + throw { + errCode: ERROR.INVALID_INVITE_CODE + } + } + return inviterRecord +} + +/** + * 根据邀请码生成邀请信息 + * @param {object} param + * @param {string} param.inviteCode 邀请码 + * @param {string} param.queryUid 受邀人id,非空时校验不可被下家或自己邀请 + * @returns + */ +async function generateInviteInfo ({ + inviteCode, + queryUid +} = {}) { + const inviterRecord = await findUserByInviteCode({ + inviteCode, + queryUid + }) + // 倒叙拼接当前用户邀请链 + const inviterUid = inviterRecord.inviter_uid || [] + inviterUid.unshift(inviterRecord._id) + return { + inviterUid, + inviteTime: Date.now() + } +} + +/** + * 检查当前用户是否可以接受邀请,如果可以返回用户记录 + * @param {string} uid + */ +async function checkInviteInfo (uid) { + // 检查当前用户是否已有邀请人 + const getUserRes = await userCollection.doc(uid).field({ + my_invite_code: true, + inviter_uid: true + }).get() + const userRecord = getUserRes.data[0] + if (!userRecord) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + if (userRecord.inviter_uid && userRecord.inviter_uid.length > 0) { + throw { + errCode: ERROR.CHANGE_INVITER_FORBIDDEN + } + } + return userRecord +} + +/** + * 指定用户接受邀请码邀请 + * @param {object} param + * @param {string} param.uid 用户uid + * @param {string} param.inviteCode 邀请人的邀请码 + * @returns + */ +async function acceptInvite ({ + uid, + inviteCode +} = {}) { + await checkInviteInfo(uid) + const { + inviterUid, + inviteTime + } = await generateInviteInfo({ + inviteCode, + queryUid: uid + }) + + if (inviterUid === uid) { + throw { + errCode: ERROR.INVALID_INVITE_CODE + } + } + + // 更新当前用户的邀请人信息 + await userCollection.doc(uid).update({ + inviter_uid: inviterUid, + invite_time: inviteTime + }) + + // 更新当前用户邀请的用户的邀请人信息,这步可能较为耗时 + await userCollection.where({ + inviter_uid: uid + }).update({ + inviter_uid: dbCmd.push(inviterUid) + }) + + return { + errCode: 0, + errMsg: '' + } +} + +module.exports = { + acceptInvite, + generateInviteInfo, + getValidInviteCode +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/login.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/login.js index 203bec43..07bd0442 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/login.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/login.js @@ -1,231 +1,232 @@ -const { - findUser -} = require('./account') -const { - userCollection, - LOG_TYPE -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') -const { - logout -} = require('./logout') -const PasswordUtils = require('./password') - -async function realPreLogin (params = {}) { - const { - user - } = params - const appId = this.getClientInfo().appId - const userMatched = await findUser({ - userQuery: user, - authorizedApp: appId - }) - if (userMatched.length === 0) { - throw { - errCode: ERROR.ACCOUNT_NOT_EXISTS - } - } else if (userMatched.length > 1) { - throw { - errCode: ERROR.ACCOUNT_CONFLICT - } - } - const userRecord = userMatched[0] - checkLoginUserRecord(userRecord) - return userRecord -} - -async function preLogin (params = {}) { - const { - user - } = params - try { - const user = await realPreLogin.call(this, params) - return user - } catch (error) { - await this.middleware.uniIdLog({ - success: false, - data: user, - type: LOG_TYPE.LOGIN - }) - throw error - } -} - -async function preLoginWithPassword (params = {}) { - const { - user, - password - } = params - try { - const userRecord = await realPreLogin.call(this, params) - const { - passwordErrorLimit, - passwordErrorRetryTime - } = this.config - const { - clientIP - } = this.getClientInfo() - // 根据ip地址,密码错误次数过多,锁定登录 - let loginIPLimit = userRecord.login_ip_limit || [] - // 清理无用记录 - loginIPLimit = loginIPLimit.filter(item => item.last_error_time > Date.now() - passwordErrorRetryTime * 1000) - let currentIPLimit = loginIPLimit.find(item => item.ip === clientIP) - if (currentIPLimit && currentIPLimit.error_times >= passwordErrorLimit) { - throw { - errCode: ERROR.PASSWORD_ERROR_EXCEED_LIMIT - } - } - const passwordUtils = new PasswordUtils({ - passwordSecret: this.config.passwordSecret - }) - - const { - success: checkPasswordSuccess, - refreshPasswordInfo - } = passwordUtils.checkUserPassword({ - password, - passwordHash: userRecord.password, - passwordSecretVersion: userRecord.password_secret_version - }) - if (!checkPasswordSuccess) { - // 更新用户ip对应的密码错误记录 - if (!currentIPLimit) { - currentIPLimit = { - ip: clientIP, - error_times: 1, - last_error_time: Date.now() - } - loginIPLimit.push(currentIPLimit) - } else { - currentIPLimit.error_times++ - currentIPLimit.last_error_time = Date.now() - } - await userCollection.doc(userRecord._id).update({ - login_ip_limit: loginIPLimit - }) - throw { - errCode: ERROR.PASSWORD_ERROR - } - } - const extraData = {} - if (refreshPasswordInfo) { - extraData.password = refreshPasswordInfo.passwordHash - extraData.password_secret_version = refreshPasswordInfo.version - } - - const currentIPLimitIndex = loginIPLimit.indexOf(currentIPLimit) - if (currentIPLimitIndex > -1) { - loginIPLimit.splice(currentIPLimitIndex, 1) - } - extraData.login_ip_limit = loginIPLimit - return { - user: userRecord, - extraData - } - } catch (error) { - await this.middleware.uniIdLog({ - success: false, - data: user, - type: LOG_TYPE.LOGIN - }) - throw error - } -} - -function checkLoginUserRecord (user) { - switch (user.status) { - case undefined: - case 0: - break - case 1: - throw { - errCode: ERROR.ACCOUNT_BANNED - } - case 2: - throw { - errCode: ERROR.ACCOUNT_AUDITING - } - case 3: - throw { - errCode: ERROR.ACCOUNT_AUDIT_FAILED - } - case 4: - throw { - errCode: ERROR.ACCOUNT_CLOSED - } - default: - break - } -} - -async function thirdPartyLogin (params = {}) { - const { - user - } = params - return { - mobileComfirmd: user.mobile_comfirmd, - emailComfirmd: user.email_comfirmd - } -} - -async function postLogin (params = {}) { - const { - user, - extraData, - isThirdParty = false - } = params - const { - clientIP, - uniIdToken - } = this.getClientInfo() - const uid = user._id - const updateData = { - last_login_date: Date.now(), - last_login_ip: clientIP, - ...extraData - } - const { - token, - tokenExpired - } = await this.uniIdCommon.createToken({ - uid - }) - - if (uniIdToken) { - try { - await logout.call(this) - } catch (error) {} - } - - await userCollection.doc(uid).update(updateData) - await this.middleware.uniIdLog({ - data: { - user_id: uid - }, - type: LOG_TYPE.LOGIN - }) - return { - errCode: 0, - newToken: { - token, - tokenExpired - }, - uid, - ...( - isThirdParty - ? thirdPartyLogin({ - user - }) - : {} - ) - } -} - -module.exports = { - preLogin, - postLogin, - checkLoginUserRecord, - preLoginWithPassword -} +const { + findUser +} = require('./account') +const { + userCollection, + LOG_TYPE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + logout +} = require('./logout') +const PasswordUtils = require('./password') + +async function realPreLogin (params = {}) { + const { + user + } = params + const appId = this.getClientInfo().appId + const userMatched = await findUser({ + userQuery: user, + authorizedApp: appId + }) + if (userMatched.length === 0) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } else if (userMatched.length > 1) { + throw { + errCode: ERROR.ACCOUNT_CONFLICT + } + } + const userRecord = userMatched[0] + checkLoginUserRecord(userRecord) + return userRecord +} + +async function preLogin (params = {}) { + const { + user + } = params + try { + const user = await realPreLogin.call(this, params) + return user + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + data: user, + type: LOG_TYPE.LOGIN + }) + throw error + } +} + +async function preLoginWithPassword (params = {}) { + const { + user, + password + } = params + try { + const userRecord = await realPreLogin.call(this, params) + const { + passwordErrorLimit, + passwordErrorRetryTime + } = this.config + const { + clientIP + } = this.getClientInfo() + // 根据ip地址,密码错误次数过多,锁定登录 + let loginIPLimit = userRecord.login_ip_limit || [] + // 清理无用记录 + loginIPLimit = loginIPLimit.filter(item => item.last_error_time > Date.now() - passwordErrorRetryTime * 1000) + let currentIPLimit = loginIPLimit.find(item => item.ip === clientIP) + if (currentIPLimit && currentIPLimit.error_times >= passwordErrorLimit) { + throw { + errCode: ERROR.PASSWORD_ERROR_EXCEED_LIMIT + } + } + const passwordUtils = new PasswordUtils({ + passwordSecret: this.config.passwordSecret + }) + + const { + success: checkPasswordSuccess, + refreshPasswordInfo + } = passwordUtils.checkUserPassword({ + password, + passwordHash: userRecord.password, + passwordSecretVersion: userRecord.password_secret_version + }) + if (!checkPasswordSuccess) { + // 更新用户ip对应的密码错误记录 + if (!currentIPLimit) { + currentIPLimit = { + ip: clientIP, + error_times: 1, + last_error_time: Date.now() + } + loginIPLimit.push(currentIPLimit) + } else { + currentIPLimit.error_times++ + currentIPLimit.last_error_time = Date.now() + } + await userCollection.doc(userRecord._id).update({ + login_ip_limit: loginIPLimit + }) + throw { + errCode: ERROR.PASSWORD_ERROR + } + } + const extraData = {} + if (refreshPasswordInfo) { + extraData.password = refreshPasswordInfo.passwordHash + extraData.password_secret_version = refreshPasswordInfo.version + } + + const currentIPLimitIndex = loginIPLimit.indexOf(currentIPLimit) + if (currentIPLimitIndex > -1) { + loginIPLimit.splice(currentIPLimitIndex, 1) + } + extraData.login_ip_limit = loginIPLimit + return { + user: userRecord, + extraData + } + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + data: user, + type: LOG_TYPE.LOGIN + }) + throw error + } +} + +function checkLoginUserRecord (user) { + switch (user.status) { + case undefined: + case 0: + break + case 1: + throw { + errCode: ERROR.ACCOUNT_BANNED + } + case 2: + throw { + errCode: ERROR.ACCOUNT_AUDITING + } + case 3: + throw { + errCode: ERROR.ACCOUNT_AUDIT_FAILED + } + case 4: + throw { + errCode: ERROR.ACCOUNT_CLOSED + } + default: + break + } +} + +async function thirdPartyLogin (params = {}) { + const { + user + } = params + return { + mobileComfirmd: user.mobile_comfirmd, + emailComfirmd: user.email_comfirmd + } +} + +async function postLogin (params = {}) { + const { + user, + extraData, + isThirdParty = false + } = params + const { + clientIP, + uniIdToken + } = this.getClientInfo() + const uid = user._id + const updateData = { + last_login_date: Date.now(), + last_login_ip: clientIP, + ...extraData + } + const { + token, + tokenExpired + } = await this.uniIdCommon.createToken({ + uid + }) + + if (uniIdToken) { + try { + await logout.call(this) + } catch (error) {} + } + + await userCollection.doc(uid).update(updateData) + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: LOG_TYPE.LOGIN + }) + return { + errCode: 0, + newToken: { + token, + tokenExpired + }, + uid, + ...( + isThirdParty + ? thirdPartyLogin({ + user + }) + : {} + ), + passwordConfirmed: !!user.password + } +} + +module.exports = { + preLogin, + postLogin, + checkLoginUserRecord, + preLoginWithPassword +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/logout.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/logout.js index dc49fc7c..5cd9c617 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/logout.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/logout.js @@ -1,47 +1,47 @@ -const { - dbCmd, - LOG_TYPE, - deviceCollection, - userCollection -} = require('../../common/constants') - -async function logout() { - const { - uniIdToken, - deviceId - } = this.getClientInfo() - const { - uid - } = await this.uniIdCommon.checkToken( - uniIdToken, - { - autoRefresh: false - } - ) - - // 删除token - await userCollection.doc(uid).update({ - token: dbCmd.pull(uniIdToken) - }) - - // 仅当device表的device_id和user_id均对应时才进行更新 - await deviceCollection.where({ - device_id: deviceId, - user_id: uid - }).update({ - token_expired: 0 - }) - await this.middleware.uniIdLog({ - data: { - user_id: uid - }, - type: LOG_TYPE.LOGOUT - }) - return { - errCode: 0 - } -} - -module.exports = { - logout +const { + dbCmd, + LOG_TYPE, + deviceCollection, + userCollection +} = require('../../common/constants') + +async function logout() { + const { + uniIdToken, + deviceId + } = this.getClientInfo() + const { + uid + } = await this.uniIdCommon.checkToken( + uniIdToken, + { + autoRefresh: false + } + ) + + // 删除token + await userCollection.doc(uid).update({ + token: dbCmd.pull(uniIdToken) + }) + + // 仅当device表的device_id和user_id均对应时才进行更新 + await deviceCollection.where({ + device_id: deviceId, + user_id: uid + }).update({ + token_expired: 0 + }) + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: LOG_TYPE.LOGOUT + }) + return { + errCode: 0 + } +} + +module.exports = { + logout } \ No newline at end of file diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js index 19ee9205..b1da3842 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js @@ -1,116 +1,116 @@ -const { - getType -} = require('../../common/utils') -const crypto = require('crypto') - -const PasswordHashMethod = { - 'hmac-sha1': function (content, secret) { - const hmac = crypto.createHmac('sha1', secret.toString('ascii')) - hmac.update(content) - return hmac.digest('hex') - } -} - -class PasswordUtils { - constructor ({ - passwordSecret - } = {}) { - const passwordSecretType = getType(passwordSecret) - if (passwordSecretType === 'array') { - this.passwordSecret = passwordSecret.sort((a, b) => { - return a.version - b.version - }) - } else if (passwordSecretType === 'string') { - this.passwordSecret = [{ value: passwordSecret }] - } else { - throw new Error('Invalid password secret') - } - } - - getSecretByVersion (params = {}) { - const { - version - } = params - if (!version && version !== 0) { - return this.getOldestSecret() - } - if (this.passwordSecret.length === 1) { - return this.passwordSecret[0] - } - return this.passwordSecret.find(item => item.version === version) - } - - getLastestSecret () { - return this.passwordSecret[this.passwordSecret.length - 1] - } - - getOldestSecret () { - return this.passwordSecret[0] - } - - checkUserPassword (params = {}) { - const { - password, - passwordHash: passwordHashToCheck, - passwordSecretVersion, - autoRefresh = true - } = params - const currentPasswordSecret = this.getSecretByVersion({ - version: passwordSecretVersion - }) - if (!currentPasswordSecret) { - throw new Error('Invalid password version') - } - const { - value: passwordSecret - } = currentPasswordSecret - const { - passwordHash - } = this.generatePasswordHash({ - password, - passwordSecret, - passwordSecretVersion - }) - if (passwordHashToCheck !== passwordHash) { - return { - success: false - } - } - let refreshPasswordInfo - if (autoRefresh && passwordSecretVersion !== this.getLastestSecret().version) { - refreshPasswordInfo = this.generatePasswordHash({ - password - }) - } - return { - success: true, - refreshPasswordInfo - } - } - - generatePasswordHash (params = {}) { - let { - password, - passwordSecret, - passwordSecretVersion - } = params - if (getType(password) !== 'string') { - throw new Error('Invalid password') - } - password = password && password.trim() - if (!password) { - throw new Error('Invalid password') - } - if (!passwordSecret) { - const lastestSecret = this.getLastestSecret() - passwordSecret = lastestSecret.value - passwordSecretVersion = lastestSecret.version - } - return { - passwordHash: PasswordHashMethod['hmac-sha1'](password, passwordSecret), - version: passwordSecretVersion - } - } -} - -module.exports = PasswordUtils +const { + getType +} = require('../../common/utils') +const crypto = require('crypto') + +const PasswordHashMethod = { + 'hmac-sha1': function (content, secret) { + const hmac = crypto.createHmac('sha1', secret.toString('ascii')) + hmac.update(content) + return hmac.digest('hex') + } +} + +class PasswordUtils { + constructor ({ + passwordSecret + } = {}) { + const passwordSecretType = getType(passwordSecret) + if (passwordSecretType === 'array') { + this.passwordSecret = passwordSecret.sort((a, b) => { + return a.version - b.version + }) + } else if (passwordSecretType === 'string') { + this.passwordSecret = [{ value: passwordSecret }] + } else { + throw new Error('Invalid password secret') + } + } + + getSecretByVersion (params = {}) { + const { + version + } = params + if (!version && version !== 0) { + return this.getOldestSecret() + } + if (this.passwordSecret.length === 1) { + return this.passwordSecret[0] + } + return this.passwordSecret.find(item => item.version === version) + } + + getLastestSecret () { + return this.passwordSecret[this.passwordSecret.length - 1] + } + + getOldestSecret () { + return this.passwordSecret[0] + } + + checkUserPassword (params = {}) { + const { + password, + passwordHash: passwordHashToCheck, + passwordSecretVersion, + autoRefresh = true + } = params + const currentPasswordSecret = this.getSecretByVersion({ + version: passwordSecretVersion + }) + if (!currentPasswordSecret) { + throw new Error('Invalid password version') + } + const { + value: passwordSecret + } = currentPasswordSecret + const { + passwordHash + } = this.generatePasswordHash({ + password, + passwordSecret, + passwordSecretVersion + }) + if (passwordHashToCheck !== passwordHash) { + return { + success: false + } + } + let refreshPasswordInfo + if (autoRefresh && passwordSecretVersion !== this.getLastestSecret().version) { + refreshPasswordInfo = this.generatePasswordHash({ + password + }) + } + return { + success: true, + refreshPasswordInfo + } + } + + generatePasswordHash (params = {}) { + let { + password, + passwordSecret, + passwordSecretVersion + } = params + if (getType(password) !== 'string') { + throw new Error('Invalid password') + } + password = password && password.trim() + if (!password) { + throw new Error('Invalid password') + } + if (!passwordSecret) { + const lastestSecret = this.getLastestSecret() + passwordSecret = lastestSecret.value + passwordSecretVersion = lastestSecret.version + } + return { + passwordHash: PasswordHashMethod['hmac-sha1'](password, passwordSecret), + version: passwordSecretVersion + } + } +} + +module.exports = PasswordUtils diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/qq.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/qq.js index ebacbb1a..08da0356 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/qq.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/qq.js @@ -1,152 +1,152 @@ -const { - userCollection -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') - -function getQQPlatform() { - const platform = this.clientPlatform - switch (platform) { - case 'app': - case 'app-plus': - return 'app' - case 'mp-qq': - return 'mp' - default: - throw new Error('Unsupported qq platform') - } -} - -async function saveQQUserKey({ - openid, - sessionKey, // QQ小程序用户sessionKey - accessToken, // App端QQ用户accessToken - accessTokenExpired // App端QQ用户accessToken过期时间 -} = {}) { - // 微信公众平台、开放平台refreshToken有效期均为30天(微信没有在网络请求里面返回30天这个值,务必注意未来可能出现调整,需及时更新此处逻辑)。 - // 此前QQ开放平台有调整过accessToken的过期时间:[access_token有效期由90天缩短至30天](https://wiki.connect.qq.com/%E3%80%90qq%E4%BA%92%E8%81%94%E3%80%91access_token%E6%9C%89%E6%95%88%E6%9C%9F%E8%B0%83%E6%95%B4) - const appId = this.getClientInfo().appId - const qqPlatform = getQQPlatform.call(this) - const keyObj = { - dcloudAppid: appId, - openid, - platform: 'qq-' + qqPlatform - } - switch (qqPlatform) { - case 'mp': - await this.uniOpenBridge.setSessionKey(keyObj, { - session_key: sessionKey - }, 30 * 24 * 60 * 60) - break - case 'app': - case 'h5': - case 'web': - await this.uniOpenBridge.setUserAccessToken(keyObj, { - access_token: accessToken, - access_token_expired: accessTokenExpired - }, accessTokenExpired ? - Math.floor((accessTokenExpired - Date.now()) / 1000) : - 30 * 24 * 60 * 60 - ) - break - default: - break - } -} - -function generateQQCache({ - sessionKey, // QQ小程序用户sessionKey - accessToken, // App端QQ用户accessToken - accessTokenExpired // App端QQ用户accessToken过期时间 -} = {}) { - const platform = getQQPlatform.call(this) - let cache - switch (platform) { - case 'app': - cache = { - access_token: accessToken, - access_token_expired: accessTokenExpired - } - break - case 'mp': - cache = { - session_key: sessionKey - } - break - default: - throw new Error('Unsupported qq platform') - } - return { - third_party: { - [`${platform}_qq`]: cache - } - } -} - -function getQQOpenid({ - userRecord -} = {}) { - const qqPlatform = getQQPlatform.call(this) - const appId = this.getClientInfo().appId - const qqOpenidObj = userRecord.qq_openid - if (!qqOpenidObj) { - return - } - return qqOpenidObj[`${qqPlatform}_${appId}`] || qqOpenidObj[qqPlatform] -} - -async function getQQCacheFallback({ - userRecord, - key -} = {}) { - const platform = getQQPlatform.call(this) - const thirdParty = userRecord && userRecord.third_party - if (!thirdParty) { - return - } - const qqCache = thirdParty[`${platform}_qq`] - return qqCache && qqCache[key] -} - -async function getQQCache({ - uid, - userRecord, - key -} = {}) { - const qqPlatform = getQQPlatform.call(this) - const appId = this.getClientInfo().appId - - if (!userRecord) { - const getUserRes = await userCollection.doc(uid).get() - userRecord = getUserRes.data[0] - } - if (!userRecord) { - throw { - errCode: ERROR.ACCOUNT_NOT_EXISTS - } - } - const openid = getQQOpenid.call(this, { - userRecord - }) - const getCacheMethod = qqPlatform === 'mp' ? 'getSessionKey' : 'getUserAccessToken' - const userKey = await this.uniOpenBridge[getCacheMethod]({ - dcloudAppid: appId, - platform: 'qq-' + qqPlatform, - openid - }) - if (userKey) { - return userKey[key] - } - return getQQCacheFallback({ - userRecord, - key - }) -} - -module.exports = { - getQQPlatform, - generateQQCache, - getQQCache, - saveQQUserKey -} +const { + userCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +function getQQPlatform() { + const platform = this.clientPlatform + switch (platform) { + case 'app': + case 'app-plus': + return 'app' + case 'mp-qq': + return 'mp' + default: + throw new Error('Unsupported qq platform') + } +} + +async function saveQQUserKey({ + openid, + sessionKey, // QQ小程序用户sessionKey + accessToken, // App端QQ用户accessToken + accessTokenExpired // App端QQ用户accessToken过期时间 +} = {}) { + // 微信公众平台、开放平台refreshToken有效期均为30天(微信没有在网络请求里面返回30天这个值,务必注意未来可能出现调整,需及时更新此处逻辑)。 + // 此前QQ开放平台有调整过accessToken的过期时间:[access_token有效期由90天缩短至30天](https://wiki.connect.qq.com/%E3%80%90qq%E4%BA%92%E8%81%94%E3%80%91access_token%E6%9C%89%E6%95%88%E6%9C%9F%E8%B0%83%E6%95%B4) + const appId = this.getClientInfo().appId + const qqPlatform = getQQPlatform.call(this) + const keyObj = { + dcloudAppid: appId, + openid, + platform: 'qq-' + qqPlatform + } + switch (qqPlatform) { + case 'mp': + await this.uniOpenBridge.setSessionKey(keyObj, { + session_key: sessionKey + }, 30 * 24 * 60 * 60) + break + case 'app': + case 'h5': + case 'web': + await this.uniOpenBridge.setUserAccessToken(keyObj, { + access_token: accessToken, + access_token_expired: accessTokenExpired + }, accessTokenExpired ? + Math.floor((accessTokenExpired - Date.now()) / 1000) : + 30 * 24 * 60 * 60 + ) + break + default: + break + } +} + +function generateQQCache({ + sessionKey, // QQ小程序用户sessionKey + accessToken, // App端QQ用户accessToken + accessTokenExpired // App端QQ用户accessToken过期时间 +} = {}) { + const platform = getQQPlatform.call(this) + let cache + switch (platform) { + case 'app': + cache = { + access_token: accessToken, + access_token_expired: accessTokenExpired + } + break + case 'mp': + cache = { + session_key: sessionKey + } + break + default: + throw new Error('Unsupported qq platform') + } + return { + third_party: { + [`${platform}_qq`]: cache + } + } +} + +function getQQOpenid({ + userRecord +} = {}) { + const qqPlatform = getQQPlatform.call(this) + const appId = this.getClientInfo().appId + const qqOpenidObj = userRecord.qq_openid + if (!qqOpenidObj) { + return + } + return qqOpenidObj[`${qqPlatform}_${appId}`] || qqOpenidObj[qqPlatform] +} + +async function getQQCacheFallback({ + userRecord, + key +} = {}) { + const platform = getQQPlatform.call(this) + const thirdParty = userRecord && userRecord.third_party + if (!thirdParty) { + return + } + const qqCache = thirdParty[`${platform}_qq`] + return qqCache && qqCache[key] +} + +async function getQQCache({ + uid, + userRecord, + key +} = {}) { + const qqPlatform = getQQPlatform.call(this) + const appId = this.getClientInfo().appId + + if (!userRecord) { + const getUserRes = await userCollection.doc(uid).get() + userRecord = getUserRes.data[0] + } + if (!userRecord) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + const openid = getQQOpenid.call(this, { + userRecord + }) + const getCacheMethod = qqPlatform === 'mp' ? 'getSessionKey' : 'getUserAccessToken' + const userKey = await this.uniOpenBridge[getCacheMethod]({ + dcloudAppid: appId, + platform: 'qq-' + qqPlatform, + openid + }) + if (userKey) { + return userKey[key] + } + return getQQCacheFallback({ + userRecord, + key + }) +} + +module.exports = { + getQQPlatform, + generateQQCache, + getQQCache, + saveQQUserKey +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/register.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/register.js index 2ecd186e..274713c6 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/register.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/register.js @@ -1,211 +1,211 @@ -const { - userCollection, - LOG_TYPE -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') -const { - findUser -} = require('./account') -const { - getValidInviteCode, - generateInviteInfo -} = require('./fission') -const { - logout -} = require('./logout') -const PasswordUtils = require('./password') -const merge = require('lodash.merge') - -async function realPreRegister(params = {}) { - const { - user - } = params - const userMatched = await findUser({ - userQuery: user, - authorizedApp: this.getClientInfo().appId - }) - if (userMatched.length > 0) { - throw { - errCode: ERROR.ACCOUNT_EXISTS - } - } -} - -async function preRegister(params = {}) { - try { - await realPreRegister.call(this, params) - } catch (error) { - await this.middleware.uniIdLog({ - success: false, - type: LOG_TYPE.REGISTER - }) - throw error - } -} - -async function preRegisterWithPassword(params = {}) { - const { - user, - password - } = params - await preRegister.call(this, { - user - }) - const passwordUtils = new PasswordUtils({ - passwordSecret: this.config.passwordSecret - }) - const { - passwordHash, - version - } = passwordUtils.generatePasswordHash({ - password - }) - const extraData = { - password: passwordHash, - password_secret_version: version - } - return { - user, - extraData - } -} - -async function thirdPartyRegister({ - user = {} -} = {}) { - return { - mobileConfirmed: !!(user.mobile && user.mobile_confirmed) || false, - emailConfirmed: !!(user.email && user.email_confirmed) || false - } -} - -async function postRegister(params = {}) { - const { - user, - extraData = {}, - isThirdParty = false, - inviteCode - } = params - const { - appId, - appName, - appVersion, - appVersionCode, - channel, - scene, - clientIP, - osName, - uniIdToken - } = this.getClientInfo() - - merge(user, extraData) - - const registerChannel = channel || scene - user.register_env = { - appid: appId || '', - uni_platform: this.clientPlatform || '', - os_name: osName || '', - app_name: appName || '', - app_version: appVersion || '', - app_version_code: appVersionCode || '', - channel: registerChannel ? registerChannel + '' : '', // channel可能为数字,统一存为字符串 - client_ip: clientIP || '' - } - - user.register_date = Date.now() - user.dcloud_appid = [appId] - - if (user.username) { - user.username = user.username.toLowerCase() - } - if (user.email) { - user.email = user.email.toLowerCase() - } - - const { - autoSetInviteCode, // 注册时自动设置邀请码 - forceInviteCode // 必须有邀请码才允许注册,注意此逻辑不可对admin生效 - } = this.config - if (autoSetInviteCode) { - user.my_invite_code = await getValidInviteCode() - } - - const isAdmin = user.role && user.role.includes('admin') - - if (forceInviteCode && !isAdmin && !inviteCode) { - throw { - errCode: ERROR.INVALID_INVITE_CODE - } - } - - if (inviteCode) { - const { - inviterUid, - inviteTime - } = await generateInviteInfo({ - inviteCode - }) - user.inviter_uid = inviterUid - user.invite_time = inviteTime - } - - if (uniIdToken) { - try { - await logout.call(this) - } catch (error) {} - } - - const beforeRegister = this.hooks.beforeRegister - let userRecord = user - if (beforeRegister) { - userRecord = await beforeRegister({ - userRecord, - clientInfo: this.getClientInfo() - }) - } - - const { - id: uid - } = await userCollection.add(userRecord) - - const { - token, - tokenExpired - } = await this.uniIdCommon.createToken({ - uid - }) - - await this.middleware.uniIdLog({ - data: { - user_id: uid - }, - type: LOG_TYPE.REGISTER - }) - - return { - errCode: 0, - uid, - newToken: { - token, - tokenExpired - }, - ...( - isThirdParty - ? thirdPartyRegister({ - user: { - ...userRecord, - _id: uid - } - }) - : {} - ) - } -} - -module.exports = { - preRegister, - preRegisterWithPassword, - postRegister -} +const { + userCollection, + LOG_TYPE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + findUser +} = require('./account') +const { + getValidInviteCode, + generateInviteInfo +} = require('./fission') +const { + logout +} = require('./logout') +const PasswordUtils = require('./password') +const merge = require('lodash.merge') + +async function realPreRegister(params = {}) { + const { + user + } = params + const userMatched = await findUser({ + userQuery: user, + authorizedApp: this.getClientInfo().appId + }) + if (userMatched.length > 0) { + throw { + errCode: ERROR.ACCOUNT_EXISTS + } + } +} + +async function preRegister(params = {}) { + try { + await realPreRegister.call(this, params) + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.REGISTER + }) + throw error + } +} + +async function preRegisterWithPassword(params = {}) { + const { + user, + password + } = params + await preRegister.call(this, { + user + }) + const passwordUtils = new PasswordUtils({ + passwordSecret: this.config.passwordSecret + }) + const { + passwordHash, + version + } = passwordUtils.generatePasswordHash({ + password + }) + const extraData = { + password: passwordHash, + password_secret_version: version + } + return { + user, + extraData + } +} + +async function thirdPartyRegister({ + user = {} +} = {}) { + return { + mobileConfirmed: !!(user.mobile && user.mobile_confirmed) || false, + emailConfirmed: !!(user.email && user.email_confirmed) || false + } +} + +async function postRegister(params = {}) { + const { + user, + extraData = {}, + isThirdParty = false, + inviteCode + } = params + const { + appId, + appName, + appVersion, + appVersionCode, + channel, + scene, + clientIP, + osName, + uniIdToken + } = this.getClientInfo() + + merge(user, extraData) + + const registerChannel = channel || scene + user.register_env = { + appid: appId || '', + uni_platform: this.clientPlatform || '', + os_name: osName || '', + app_name: appName || '', + app_version: appVersion || '', + app_version_code: appVersionCode || '', + channel: registerChannel ? registerChannel + '' : '', // channel可能为数字,统一存为字符串 + client_ip: clientIP || '' + } + + user.register_date = Date.now() + user.dcloud_appid = [appId] + + if (user.username) { + user.username = user.username.toLowerCase() + } + if (user.email) { + user.email = user.email.toLowerCase() + } + + const { + autoSetInviteCode, // 注册时自动设置邀请码 + forceInviteCode // 必须有邀请码才允许注册,注意此逻辑不可对admin生效 + } = this.config + if (autoSetInviteCode) { + user.my_invite_code = await getValidInviteCode() + } + + const isAdmin = user.role && user.role.includes('admin') + + if (forceInviteCode && !isAdmin && !inviteCode) { + throw { + errCode: ERROR.INVALID_INVITE_CODE + } + } + + if (inviteCode) { + const { + inviterUid, + inviteTime + } = await generateInviteInfo({ + inviteCode + }) + user.inviter_uid = inviterUid + user.invite_time = inviteTime + } + + if (uniIdToken) { + try { + await logout.call(this) + } catch (error) {} + } + + const beforeRegister = this.hooks.beforeRegister + let userRecord = user + if (beforeRegister) { + userRecord = await beforeRegister({ + userRecord, + clientInfo: this.getClientInfo() + }) + } + + const { + id: uid + } = await userCollection.add(userRecord) + + const { + token, + tokenExpired + } = await this.uniIdCommon.createToken({ + uid + }) + + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: LOG_TYPE.REGISTER + }) + + return { + errCode: 0, + uid, + newToken: { + token, + tokenExpired + }, + ...( + isThirdParty + ? thirdPartyRegister({ + user: { + ...userRecord, + _id: uid + } + }) + : {} + ) + } +} + +module.exports = { + preRegister, + preRegisterWithPassword, + postRegister +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/relate.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/relate.js index efd55e53..e095780a 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/relate.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/relate.js @@ -1,62 +1,162 @@ -const { - findUser -} = require('./account') -const { - ERROR -} = require('../../common/error') -const { - userCollection -} = require('../../common/constants') -const merge = require('lodash.merge') - -/** - * - * @param {object} param - * @param {string} param.uid 用户id - * @param {string} param.bindAccount 要绑定的三方账户、手机号或邮箱 - */ -async function preBind ({ - uid, - bindAccount, - logType -} = {}) { - const userMatched = await findUser({ - userQuery: bindAccount, - authorizedApp: this.getClientInfo().appId - }) - if (userMatched.length > 0) { - await this.middleware.uniIdLog({ - data: { - user_id: uid - }, - type: logType, - success: false - }) - throw { - errCode: ERROR.BIND_CONFLICT - } - } -} - -async function postBind ({ - uid, - extraData = {}, - bindAccount, - logType -} = {}) { - await userCollection.doc(uid).update(merge(bindAccount, extraData)) - await this.middleware.uniIdLog({ - data: { - user_id: uid - }, - type: logType - }) - return { - errCode: 0 - } -} - -module.exports = { - preBind, - postBind -} +const { + findUser +} = require('./account') +const { + ERROR +} = require('../../common/error') +const { + userCollection, dbCmd, USER_IDENTIFIER +} = require('../../common/constants') +const { + getUserIdentifier +} = require('../../lib/utils/account') + +const { + batchFindObjctValue +} = require('../../common/utils') +const merge = require('lodash.merge') + +/** + * + * @param {object} param + * @param {string} param.uid 用户id + * @param {string} param.bindAccount 要绑定的三方账户、手机号或邮箱 + */ +async function preBind ({ + uid, + bindAccount, + logType +} = {}) { + const userMatched = await findUser({ + userQuery: bindAccount, + authorizedApp: this.getClientInfo().appId + }) + if (userMatched.length > 0) { + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: logType, + success: false + }) + throw { + errCode: ERROR.BIND_CONFLICT + } + } +} + +async function postBind ({ + uid, + extraData = {}, + bindAccount, + logType +} = {}) { + await userCollection.doc(uid).update(merge(bindAccount, extraData)) + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: logType + }) + return { + errCode: 0 + } +} + +async function preUnBind ({ + uid, + unBindAccount, + logType +}) { + const notUnBind = ['username', 'mobile', 'email'] + const userIdentifier = getUserIdentifier(unBindAccount) + const condition = Object.keys(userIdentifier).reduce((res, key) => { + if (userIdentifier[key]) { + if (notUnBind.includes(key)) { + throw { + errCode: ERROR.UNBIND_NOT_SUPPORTED + } + } + + res.push({ + [key]: userIdentifier[key] + }) + } + + return res + }, []) + const currentUnBindAccount = Object.keys(userIdentifier).reduce((res, key) => { + if (userIdentifier[key]) { + res.push(key) + } + return res + }, []) + const { data: users } = await userCollection.where(dbCmd.and( + { _id: uid }, + dbCmd.or(condition) + )).get() + + if (users.length <= 0) { + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: logType, + success: false + }) + throw { + errCode: ERROR.UNBIND_FAIL + } + } + + const [user] = users + const otherAccounts = batchFindObjctValue(user, Object.keys(USER_IDENTIFIER).filter(key => !notUnBind.includes(key) && !currentUnBindAccount.includes(key))) + let hasOtherAccountBind = false + + for (const key in otherAccounts) { + if (otherAccounts[key]) { + hasOtherAccountBind = true + break + } + } + + // 如果没有其他第三方登录方式 + if (!hasOtherAccountBind) { + // 存在用户名或者邮箱但是没有设置过没密码就提示设置密码 + if ((user.username || user.email) && !user.password) { + throw { + errCode: ERROR.UNBIND_PASSWORD_NOT_EXISTS + } + } + // 账号任何登录方式都没有就优先绑定手机号 + if (!user.mobile) { + throw { + errCode: ERROR.UNBIND_MOBILE_NOT_EXISTS + } + } + } +} + +async function postUnBind ({ + uid, + unBindAccount, + logType +}) { + await userCollection.doc(uid).update(unBindAccount) + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: logType + }) + return { + errCode: 0 + } +} + +module.exports = { + preBind, + postBind, + preUnBind, + postUnBind +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/sms.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/sms.js index 1f45a700..9caecaa2 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/sms.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/sms.js @@ -1,81 +1,81 @@ -const { - setMobileVerifyCode -} = require('./verify-code') -const { - getVerifyCode -} = require('../../common/utils') - -/** - * 发送短信 - * @param {object} param - * @param {string} param.mobile 手机号 - * @param {object} param.code 可选,验证码 - * @param {object} param.scene 短信场景 - * @param {object} param.templateId 可选,短信模板id - * @returns - */ -async function sendSmsCode ({ - mobile, - code, - scene, - templateId -} = {}) { - const requiredParams = [ - 'name', - 'smsKey', - 'smsSecret', - 'codeExpiresIn' - ] - const smsConfig = (this.config.service && this.config.service.sms) || {} - for (let i = 0; i < requiredParams.length; i++) { - const key = requiredParams[i] - if (!smsConfig[key]) { - throw new Error(`Missing config param: service.sms.${key}`) - } - } - if (!code) { - code = getVerifyCode() - } - let action - switch (scene) { - case 'login-by-sms': - action = this.t('login') - break - default: - action = this.t('verify-mobile') - break - } - const sceneConfig = smsConfig.scene || {} - if (!templateId) { - templateId = sceneConfig.templateId - } - if (!templateId) { - throw new Error('"templateId" is required') - } - const codeExpiresIn = sceneConfig.codeExpiresIn || smsConfig.codeExpiresIn - await setMobileVerifyCode.call(this, { - mobile, - code, - expiresIn: codeExpiresIn, - scene - }) - await uniCloud.sendSms({ - smsKey: smsConfig.smsKey, - smsSecret: smsConfig.smsSecret, - phone: mobile, - templateId, - data: { - name: smsConfig.name, - code, - action, - expMinute: '' + Math.round(codeExpiresIn / 60) - } - }) - return { - errCode: 0 - } -} - -module.exports = { - sendSmsCode -} +const { + setMobileVerifyCode +} = require('./verify-code') +const { + getVerifyCode +} = require('../../common/utils') + +/** + * 发送短信 + * @param {object} param + * @param {string} param.mobile 手机号 + * @param {object} param.code 可选,验证码 + * @param {object} param.scene 短信场景 + * @param {object} param.templateId 可选,短信模板id + * @returns + */ +async function sendSmsCode ({ + mobile, + code, + scene, + templateId +} = {}) { + const requiredParams = [ + 'name', + 'smsKey', + 'smsSecret', + 'codeExpiresIn' + ] + const smsConfig = (this.config.service && this.config.service.sms) || {} + for (let i = 0; i < requiredParams.length; i++) { + const key = requiredParams[i] + if (!smsConfig[key]) { + throw new Error(`Missing config param: service.sms.${key}`) + } + } + if (!code) { + code = getVerifyCode() + } + let action + switch (scene) { + case 'login-by-sms': + action = this.t('login') + break + default: + action = this.t('verify-mobile') + break + } + const sceneConfig = (smsConfig.scene || {})[scene] || {} + if (!templateId) { + templateId = sceneConfig.templateId + } + if (!templateId) { + throw new Error('"templateId" is required') + } + const codeExpiresIn = sceneConfig.codeExpiresIn || smsConfig.codeExpiresIn + await setMobileVerifyCode.call(this, { + mobile, + code, + expiresIn: codeExpiresIn, + scene + }) + await uniCloud.sendSms({ + smsKey: smsConfig.smsKey, + smsSecret: smsConfig.smsSecret, + phone: mobile, + templateId, + data: { + name: smsConfig.name, + code, + action, + expMinute: '' + Math.round(codeExpiresIn / 60) + } + }) + return { + errCode: 0 + } +} + +module.exports = { + sendSmsCode +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/unified-login.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/unified-login.js index cd758fe5..3665fe9f 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/unified-login.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/unified-login.js @@ -1,98 +1,98 @@ -const { - checkLoginUserRecord, - postLogin -} = require('./login') -const { - postRegister -} = require('./register') -const { - findUser -} = require('./account') -const { - ERROR -} = require('../../common/error') - -async function realPreUnifiedLogin (params = {}) { - const { - user, - type - } = params - const appId = this.getClientInfo().appId - const userMatched = await findUser({ - userQuery: user, - authorizedApp: appId - }) - if (userMatched.length === 0) { - if (type === 'login') { - throw { - errCode: ERROR.ACCOUNT_NOT_EXISTS - } - } - return { - type: 'register', - user - } - } if (userMatched.length === 1) { - if (type === 'register') { - throw { - errCode: ERROR.ACCOUNT_EXISTS - } - } - const userRecord = userMatched[0] - checkLoginUserRecord(userRecord) - return { - type: 'login', - user: userRecord - } - } else if (userMatched.length > 1) { - throw { - errCode: ERROR.ACCOUNT_CONFLICT - } - } -} - -async function preUnifiedLogin (params = {}) { - try { - const result = await realPreUnifiedLogin.call(this, params) - return result - } catch (error) { - await this.middleware.uniIdLog({ - success: false - }) - throw error - } -} - -async function postUnifiedLogin (params = {}) { - const { - user, - extraData = {}, - isThirdParty = false, - type, - inviteCode - } = params - let result - if (type === 'login') { - result = await postLogin.call(this, { - user, - extraData, - isThirdParty - }) - } else if (type === 'register') { - result = await postRegister.call(this, { - user, - extraData, - isThirdParty, - inviteCode - }) - } - return { - ...result, - type - } -} - -module.exports = { - preUnifiedLogin, - postUnifiedLogin -} +const { + checkLoginUserRecord, + postLogin +} = require('./login') +const { + postRegister +} = require('./register') +const { + findUser +} = require('./account') +const { + ERROR +} = require('../../common/error') + +async function realPreUnifiedLogin (params = {}) { + const { + user, + type + } = params + const appId = this.getClientInfo().appId + const userMatched = await findUser({ + userQuery: user, + authorizedApp: appId + }) + if (userMatched.length === 0) { + if (type === 'login') { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + return { + type: 'register', + user + } + } if (userMatched.length === 1) { + if (type === 'register') { + throw { + errCode: ERROR.ACCOUNT_EXISTS + } + } + const userRecord = userMatched[0] + checkLoginUserRecord(userRecord) + return { + type: 'login', + user: userRecord + } + } else if (userMatched.length > 1) { + throw { + errCode: ERROR.ACCOUNT_CONFLICT + } + } +} + +async function preUnifiedLogin (params = {}) { + try { + const result = await realPreUnifiedLogin.call(this, params) + return result + } catch (error) { + await this.middleware.uniIdLog({ + success: false + }) + throw error + } +} + +async function postUnifiedLogin (params = {}) { + const { + user, + extraData = {}, + isThirdParty = false, + type, + inviteCode + } = params + let result + if (type === 'login') { + result = await postLogin.call(this, { + user, + extraData, + isThirdParty + }) + } else if (type === 'register') { + result = await postRegister.call(this, { + user, + extraData, + isThirdParty, + inviteCode + }) + } + return { + ...result, + type + } +} + +module.exports = { + preUnifiedLogin, + postUnifiedLogin +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/univerify.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/univerify.js index ba3cb440..2ba70baa 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/univerify.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/univerify.js @@ -1,27 +1,27 @@ -async function getPhoneNumber ({ - // eslint-disable-next-line camelcase - access_token, - openid -} = {}) { - const requiredParams = ['apiKey', 'apiSecret'] - const univerifyConfig = (this.config.service && this.config.service.univerify) || {} - for (let i = 0; i < requiredParams.length; i++) { - const key = requiredParams[i] - if (!univerifyConfig[key]) { - throw new Error(`Missing config param: service.univerify.${key}`) - } - } - return uniCloud.getPhoneNumber({ - provider: 'univerify', - appid: this.getClientInfo().appId, - apiKey: univerifyConfig.apiKey, - apiSecret: univerifyConfig.apiSecret, - // eslint-disable-next-line camelcase - access_token, - openid - }) -} - -module.exports = { - getPhoneNumber -} +async function getPhoneNumber ({ + // eslint-disable-next-line camelcase + access_token, + openid +} = {}) { + const requiredParams = ['apiKey', 'apiSecret'] + const univerifyConfig = (this.config.service && this.config.service.univerify) || {} + for (let i = 0; i < requiredParams.length; i++) { + const key = requiredParams[i] + if (!univerifyConfig[key]) { + throw new Error(`Missing config param: service.univerify.${key}`) + } + } + return uniCloud.getPhoneNumber({ + provider: 'univerify', + appid: this.getClientInfo().appId, + apiKey: univerifyConfig.apiKey, + apiSecret: univerifyConfig.apiSecret, + // eslint-disable-next-line camelcase + access_token, + openid + }) +} + +module.exports = { + getPhoneNumber +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/update-user-info.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/update-user-info.js index ced33b9f..c2ebb1b4 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/update-user-info.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/update-user-info.js @@ -1,25 +1,25 @@ -const { - userCollection -} = require('../../common/constants') -const { - USER_STATUS -} = require('../../common/constants') -async function setUserStatus (uid, status) { - const updateData = { - status - } - if (status !== USER_STATUS.NORMAL) { - updateData.valid_token_date = Date.now() - } - await userCollection.doc(uid).update({ - status - }) - // TODO 此接口尚不完善,例如注销后其他客户端可能存在有效token,支持Redis后此处会补充额外逻辑 - return { - errCode: 0 - } -} - -module.exports = { - setUserStatus -} +const { + userCollection +} = require('../../common/constants') +const { + USER_STATUS +} = require('../../common/constants') +async function setUserStatus (uid, status) { + const updateData = { + status + } + if (status !== USER_STATUS.NORMAL) { + updateData.valid_token_date = Date.now() + } + await userCollection.doc(uid).update({ + status + }) + // TODO 此接口尚不完善,例如注销后其他客户端可能存在有效token,支持Redis后此处会补充额外逻辑 + return { + errCode: 0 + } +} + +module.exports = { + setUserStatus +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/verify-code.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/verify-code.js index acebc6bd..cc80004c 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/verify-code.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/verify-code.js @@ -1,152 +1,152 @@ -const { - dbCmd, - verifyCollection -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') -const { - getVerifyCode -} = require('../../common/utils') - -async function setVerifyCode ({ - mobile, - email, - code, - expiresIn, - scene -} = {}) { - const now = Date.now() - const record = { - mobile, - email, - scene, - code: code || getVerifyCode(), - state: 0, - ip: this.getClientInfo().clientIP, - created_date: now, - expired_date: now + expiresIn * 1000 - } - await verifyCollection.add(record) - return { - errCode: 0 - } -} - -async function setEmailVerifyCode ({ - email, - code, - expiresIn, - scene -} = {}) { - email = email && email.trim() - if (!email) { - throw { - errCode: ERROR.INVALID_EMAIL - } - } - email = email.toLowerCase() - return setVerifyCode.call(this, { - email, - code, - expiresIn, - scene - }) -} - -async function setMobileVerifyCode ({ - mobile, - code, - expiresIn, - scene -} = {}) { - mobile = mobile && mobile.trim() - if (!mobile) { - throw { - errCode: ERROR.INVALID_MOBILE - } - } - return setVerifyCode.call(this, { - mobile, - code, - expiresIn, - scene - }) -} - -async function verifyEmailCode ({ - email, - code, - scene -} = {}) { - email = email && email.trim() - if (!email) { - throw { - errCode: ERROR.INVALID_EMAIL - } - } - email = email.toLowerCase() - const { - data: codeRecord - } = await verifyCollection.where({ - email, - scene, - code, - state: 0, - expired_date: dbCmd.gt(Date.now()) - }).limit(1).get() - - if (codeRecord.length === 0) { - throw { - errCode: ERROR.EMAIL_VERIFY_CODE_ERROR - } - } - await verifyCollection.doc(codeRecord[0]._id).update({ - state: 1 - }) - return { - errCode: 0 - } -} - -async function verifyMobileCode ({ - mobile, - code, - scene -} = {}) { - mobile = mobile && mobile.trim() - if (!mobile) { - throw { - errCode: ERROR.INVALID_MOBILE - } - } - const { - data: codeRecord - } = await verifyCollection.where({ - mobile, - scene, - code, - state: 0, - expired_date: dbCmd.gt(Date.now()) - }).limit(1).get() - - if (codeRecord.length === 0) { - throw { - errCode: ERROR.MOBILE_VERIFY_CODE_ERROR - } - } - - await verifyCollection.doc(codeRecord[0]._id).update({ - state: 1 - }) - return { - errCode: 0 - } -} - -module.exports = { - verifyEmailCode, - verifyMobileCode, - setEmailVerifyCode, - setMobileVerifyCode -} +const { + dbCmd, + verifyCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + getVerifyCode +} = require('../../common/utils') + +async function setVerifyCode ({ + mobile, + email, + code, + expiresIn, + scene +} = {}) { + const now = Date.now() + const record = { + mobile, + email, + scene, + code: code || getVerifyCode(), + state: 0, + ip: this.getClientInfo().clientIP, + created_date: now, + expired_date: now + expiresIn * 1000 + } + await verifyCollection.add(record) + return { + errCode: 0 + } +} + +async function setEmailVerifyCode ({ + email, + code, + expiresIn, + scene +} = {}) { + email = email && email.trim() + if (!email) { + throw { + errCode: ERROR.INVALID_EMAIL + } + } + email = email.toLowerCase() + return setVerifyCode.call(this, { + email, + code, + expiresIn, + scene + }) +} + +async function setMobileVerifyCode ({ + mobile, + code, + expiresIn, + scene +} = {}) { + mobile = mobile && mobile.trim() + if (!mobile) { + throw { + errCode: ERROR.INVALID_MOBILE + } + } + return setVerifyCode.call(this, { + mobile, + code, + expiresIn, + scene + }) +} + +async function verifyEmailCode ({ + email, + code, + scene +} = {}) { + email = email && email.trim() + if (!email) { + throw { + errCode: ERROR.INVALID_EMAIL + } + } + email = email.toLowerCase() + const { + data: codeRecord + } = await verifyCollection.where({ + email, + scene, + code, + state: 0, + expired_date: dbCmd.gt(Date.now()) + }).limit(1).get() + + if (codeRecord.length === 0) { + throw { + errCode: ERROR.EMAIL_VERIFY_CODE_ERROR + } + } + await verifyCollection.doc(codeRecord[0]._id).update({ + state: 1 + }) + return { + errCode: 0 + } +} + +async function verifyMobileCode ({ + mobile, + code, + scene +} = {}) { + mobile = mobile && mobile.trim() + if (!mobile) { + throw { + errCode: ERROR.INVALID_MOBILE + } + } + const { + data: codeRecord + } = await verifyCollection.where({ + mobile, + scene, + code, + state: 0, + expired_date: dbCmd.gt(Date.now()) + }).limit(1).get() + + if (codeRecord.length === 0) { + throw { + errCode: ERROR.MOBILE_VERIFY_CODE_ERROR + } + } + + await verifyCollection.doc(codeRecord[0]._id).update({ + state: 1 + }) + return { + errCode: 0 + } +} + +module.exports = { + verifyEmailCode, + verifyMobileCode, + setEmailVerifyCode, + setMobileVerifyCode +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/weixin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/weixin.js index 8ff178f3..3bfbdfe3 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/weixin.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/weixin.js @@ -1,186 +1,198 @@ -const crypto = require('crypto') -const { - userCollection -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') - -function decryptWeixinData ({ - encryptedData, - sessionKey, - iv -} = {}) { - const oauthConfig = this.configUtils.getOauthConfig({ - provider: 'weixin' - }) - const decipher = crypto.createDecipheriv( - 'aes-128-cbc', - Buffer.from(sessionKey, 'base64'), - Buffer.from(iv, 'base64') - ) - // 设置自动 padding 为 true,删除填充补位 - decipher.setAutoPadding(true) - let decoded - decoded = decipher.update(encryptedData, 'base64', 'utf8') - decoded += decipher.final('utf8') - decoded = JSON.parse(decoded) - if (decoded.watermark.appid !== oauthConfig.appid) { - throw new Error('Invalid wechat appid in decode content') - } - return decoded -} - -function getWeixinPlatform () { - const platform = this.clientPlatform - const userAgent = this.getClientInfo().userAgent - switch (platform) { - case 'app': - case 'app-plus': - return 'app' - case 'mp-weixin': - return 'mp' - case 'h5': - case 'web': - return userAgent.indexOf('MicroMessenger') > -1 ? 'h5' : 'web' - default: - throw new Error('Unsupported weixin platform') - } -} - -async function saveWeixinUserKey ({ - openid, - sessionKey, // 微信小程序用户sessionKey - accessToken, // App端微信用户accessToken - refreshToken, // App端微信用户refreshToken - accessTokenExpired // App端微信用户accessToken过期时间 -} = {}) { - // 微信公众平台、开放平台refreshToken有效期均为30天(微信没有在网络请求里面返回30天这个值,务必注意未来可能出现调整,需及时更新此处逻辑)。 - // 此前QQ开放平台有调整过accessToken的过期时间:[access_token有效期由90天缩短至30天](https://wiki.connect.qq.com/%E3%80%90qq%E4%BA%92%E8%81%94%E3%80%91access_token%E6%9C%89%E6%95%88%E6%9C%9F%E8%B0%83%E6%95%B4) - - const appId = this.getClientInfo().appId - const weixinPlatform = getWeixinPlatform.call(this) - const keyObj = { - dcloudAppid: appId, - openid, - platform: 'weixin-' + weixinPlatform - } - switch (weixinPlatform) { - case 'mp': - await this.uniOpenBridge.setSessionKey(keyObj, { - session_key: sessionKey - }, 30 * 24 * 60 * 60) - break - case 'app': - case 'h5': - case 'web': - await this.uniOpenBridge.setUserAccessToken(keyObj, { - access_token: accessToken, - refresh_token: refreshToken, - access_token_expired: accessTokenExpired - }, 30 * 24 * 60 * 60) - break - default: - break - } -} - -function generateWeixinCache ({ - sessionKey, // 微信小程序用户sessionKey - accessToken, // App端微信用户accessToken - refreshToken, // App端微信用户refreshToken - accessTokenExpired // App端微信用户accessToken过期时间 -} = {}) { - const platform = getWeixinPlatform.call(this) - let cache - switch (platform) { - case 'app': - case 'h5': - case 'web': - cache = { - access_token: accessToken, - refresh_token: refreshToken, - access_token_expired: accessTokenExpired - } - break - case 'mp': - cache = { - session_key: sessionKey - } - break - default: - throw new Error('Unsupported weixin platform') - } - return { - third_party: { - [`${platform}_weixin`]: cache - } - } -} - -function getWeixinOpenid ({ - userRecord -} = {}) { - const weixinPlatform = getWeixinPlatform.call(this) - const appId = this.getClientInfo().appId - const wxOpenidObj = userRecord.wx_openid - if (!wxOpenidObj) { - return - } - return wxOpenidObj[`${weixinPlatform}_${appId}`] || wxOpenidObj[weixinPlatform] -} - -async function getWeixinCacheFallback ({ - userRecord, - key -} = {}) { - const platform = getWeixinPlatform.call(this) - const thirdParty = userRecord && userRecord.third_party - if (!thirdParty) { - return - } - const weixinCache = thirdParty[`${platform}_weixin`] - return weixinCache && weixinCache[key] -} - -async function getWeixinCache ({ - uid, - userRecord, - key -} = {}) { - const weixinPlatform = getWeixinPlatform.call(this) - const appId = this.getClientInfo().appId - if (!userRecord) { - const getUserRes = await userCollection.doc(uid).get() - userRecord = getUserRes.data[0] - } - if (!userRecord) { - throw { - errCode: ERROR.ACCOUNT_NOT_EXISTS - } - } - const openid = getWeixinOpenid.call(this, { - userRecord - }) - const getCacheMethod = weixinPlatform === 'mp' ? 'getSessionKey' : 'getUserAccessToken' - const userKey = await this.uniOpenBridge[getCacheMethod]({ - dcloudAppid: appId, - platform: 'weixin-' + weixinPlatform, - openid - }) - if (userKey) { - return userKey[key] - } - return getWeixinCacheFallback({ - userRecord, - key - }) -} - -module.exports = { - decryptWeixinData, - getWeixinPlatform, - generateWeixinCache, - getWeixinCache, - saveWeixinUserKey -} +const crypto = require('crypto') +const { + userCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +function decryptWeixinData ({ + encryptedData, + sessionKey, + iv +} = {}) { + const oauthConfig = this.configUtils.getOauthConfig({ + provider: 'weixin' + }) + const decipher = crypto.createDecipheriv( + 'aes-128-cbc', + Buffer.from(sessionKey, 'base64'), + Buffer.from(iv, 'base64') + ) + // 设置自动 padding 为 true,删除填充补位 + decipher.setAutoPadding(true) + let decoded + decoded = decipher.update(encryptedData, 'base64', 'utf8') + decoded += decipher.final('utf8') + decoded = JSON.parse(decoded) + if (decoded.watermark.appid !== oauthConfig.appid) { + throw new Error('Invalid wechat appid in decode content') + } + return decoded +} + +function getWeixinPlatform () { + const platform = this.clientPlatform + const userAgent = this.getClientInfo().userAgent + switch (platform) { + case 'app': + case 'app-plus': + return 'app' + case 'mp-weixin': + return 'mp' + case 'h5': + case 'web': + return userAgent.indexOf('MicroMessenger') > -1 ? 'h5' : 'web' + default: + throw new Error('Unsupported weixin platform') + } +} + +async function saveWeixinUserKey ({ + openid, + sessionKey, // 微信小程序用户sessionKey + accessToken, // App端微信用户accessToken + refreshToken, // App端微信用户refreshToken + accessTokenExpired // App端微信用户accessToken过期时间 +} = {}) { + // 微信公众平台、开放平台refreshToken有效期均为30天(微信没有在网络请求里面返回30天这个值,务必注意未来可能出现调整,需及时更新此处逻辑)。 + // 此前QQ开放平台有调整过accessToken的过期时间:[access_token有效期由90天缩短至30天](https://wiki.connect.qq.com/%E3%80%90qq%E4%BA%92%E8%81%94%E3%80%91access_token%E6%9C%89%E6%95%88%E6%9C%9F%E8%B0%83%E6%95%B4) + + const appId = this.getClientInfo().appId + const weixinPlatform = getWeixinPlatform.call(this) + const keyObj = { + dcloudAppid: appId, + openid, + platform: 'weixin-' + weixinPlatform + } + switch (weixinPlatform) { + case 'mp': + await this.uniOpenBridge.setSessionKey(keyObj, { + session_key: sessionKey + }, 30 * 24 * 60 * 60) + break + case 'app': + case 'h5': + case 'web': + await this.uniOpenBridge.setUserAccessToken(keyObj, { + access_token: accessToken, + refresh_token: refreshToken, + access_token_expired: accessTokenExpired + }, 30 * 24 * 60 * 60) + break + default: + break + } +} + +function generateWeixinCache ({ + sessionKey, // 微信小程序用户sessionKey + accessToken, // App端微信用户accessToken + refreshToken, // App端微信用户refreshToken + accessTokenExpired // App端微信用户accessToken过期时间 +} = {}) { + const platform = getWeixinPlatform.call(this) + let cache + switch (platform) { + case 'app': + case 'h5': + case 'web': + cache = { + access_token: accessToken, + refresh_token: refreshToken, + access_token_expired: accessTokenExpired + } + break + case 'mp': + cache = { + session_key: sessionKey + } + break + default: + throw new Error('Unsupported weixin platform') + } + return { + third_party: { + [`${platform}_weixin`]: cache + } + } +} + +function getWeixinOpenid ({ + userRecord +} = {}) { + const weixinPlatform = getWeixinPlatform.call(this) + const appId = this.getClientInfo().appId + const wxOpenidObj = userRecord.wx_openid + if (!wxOpenidObj) { + return + } + return wxOpenidObj[`${weixinPlatform}_${appId}`] || wxOpenidObj[weixinPlatform] +} + +async function getWeixinCacheFallback ({ + userRecord, + key +} = {}) { + const platform = getWeixinPlatform.call(this) + const thirdParty = userRecord && userRecord.third_party + if (!thirdParty) { + return + } + const weixinCache = thirdParty[`${platform}_weixin`] + return weixinCache && weixinCache[key] +} + +async function getWeixinCache ({ + uid, + userRecord, + key +} = {}) { + const weixinPlatform = getWeixinPlatform.call(this) + const appId = this.getClientInfo().appId + if (!userRecord) { + const getUserRes = await userCollection.doc(uid).get() + userRecord = getUserRes.data[0] + } + if (!userRecord) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + const openid = getWeixinOpenid.call(this, { + userRecord + }) + const getCacheMethod = weixinPlatform === 'mp' ? 'getSessionKey' : 'getUserAccessToken' + const userKey = await this.uniOpenBridge[getCacheMethod]({ + dcloudAppid: appId, + platform: 'weixin-' + weixinPlatform, + openid + }) + if (userKey) { + return userKey[key] + } + return getWeixinCacheFallback({ + userRecord, + key + }) +} + +async function getWeixinAccessToken () { + const weixinPlatform = getWeixinPlatform.call(this) + const appId = this.getClientInfo().appId + + const cache = await this.uniOpenBridge.getAccessToken({ + dcloudAppid: appId, + platform: 'weixin-' + weixinPlatform + }) + + return cache.access_token +} +module.exports = { + decryptWeixinData, + getWeixinPlatform, + generateWeixinCache, + getWeixinCache, + saveWeixinUserKey, + getWeixinAccessToken +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/access-control.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/access-control.js index e333fe01..6041ffa6 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/access-control.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/access-control.js @@ -1,59 +1,59 @@ -const methodPermission = require('../config/permission') -const { - ERROR -} = require('../common/error') - -function isAccessAllowed (user, setting) { - const { - role: userRole = [], - permission: userPermission = [] - } = user - const { - role: settingRole = [], - permission: settingPermission = [] - } = setting - if (userRole.includes('admin')) { - return - } - if ( - settingRole.length > 0 && - settingRole.every(item => !userRole.includes(item)) - ) { - throw { - errCode: ERROR.PERMISSION_ERROR - } - } - if ( - settingPermission.length > 0 && - settingPermission.every(item => !userPermission.includes(item)) - ) { - throw { - errCode: ERROR.PERMISSION_ERROR - } - } -} - -module.exports = async function () { - const methodName = this.getMethodName() - if (!(methodName in methodPermission)) { - return - } - const { - auth, - role, - permission - } = methodPermission[methodName] - if (auth || role || permission) { - await this.middleware.auth() - } - if (role && role.length === 0) { - throw new Error('[AccessControl]Empty role array is not supported') - } - if (permission && permission.length === 0) { - throw new Error('[AccessControl]Empty permission array is not supported') - } - return isAccessAllowed(this.authInfo, { - role, - permission - }) -} +const methodPermission = require('../config/permission') +const { + ERROR +} = require('../common/error') + +function isAccessAllowed (user, setting) { + const { + role: userRole = [], + permission: userPermission = [] + } = user + const { + role: settingRole = [], + permission: settingPermission = [] + } = setting + if (userRole.includes('admin')) { + return + } + if ( + settingRole.length > 0 && + settingRole.every(item => !userRole.includes(item)) + ) { + throw { + errCode: ERROR.PERMISSION_ERROR + } + } + if ( + settingPermission.length > 0 && + settingPermission.every(item => !userPermission.includes(item)) + ) { + throw { + errCode: ERROR.PERMISSION_ERROR + } + } +} + +module.exports = async function () { + const methodName = this.getMethodName() + if (!(methodName in methodPermission)) { + return + } + const { + auth, + role, + permission + } = methodPermission[methodName] + if (auth || role || permission) { + await this.middleware.auth() + } + if (role && role.length === 0) { + throw new Error('[AccessControl]Empty role array is not supported') + } + if (permission && permission.length === 0) { + throw new Error('[AccessControl]Empty permission array is not supported') + } + return isAccessAllowed(this.authInfo, { + role, + permission + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/auth.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/auth.js index 4c78b24d..945e6a1a 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/auth.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/auth.js @@ -1,17 +1,17 @@ -module.exports = async function () { - if (this.authInfo) { // 多次执行auth时如果第一次成功后续不再执行 - return - } - const token = this.getUniIdToken() - const payload = await this.uniIdCommon.checkToken(token) - if (payload.errCode) { - throw payload - } - this.authInfo = payload - if (payload.token) { - this.response.newToken = { - token: payload.token, - tokenExpired: payload.tokenExpired - } - } -} +module.exports = async function () { + if (this.authInfo) { // 多次执行auth时如果第一次成功后续不再执行 + return + } + const token = this.getUniIdToken() + const payload = await this.uniIdCommon.checkToken(token) + if (payload.errCode) { + throw payload + } + this.authInfo = payload + if (payload.token) { + this.response.newToken = { + token: payload.token, + tokenExpired: payload.tokenExpired + } + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/index.js index 0af498a4..cccac6f5 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/index.js @@ -1,7 +1,7 @@ -module.exports = { - auth: require('./auth'), - uniIdLog: require('./uni-id-log'), - validate: require('./validate'), - accessControl: require('./access-control'), - ...require('./rbac') -} +module.exports = { + auth: require('./auth'), + uniIdLog: require('./uni-id-log'), + validate: require('./validate'), + accessControl: require('./access-control'), + ...require('./rbac') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/rbac.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/rbac.js index f42ef8d9..32fe0f80 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/rbac.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/rbac.js @@ -1,39 +1,39 @@ -const { - ERROR -} = require('../common/error') - -function hasRole (...roleList) { - const userRole = this.authInfo.role || [] - if (userRole.includes('admin')) { - return - } - const isMatch = roleList.every(roleItem => { - return userRole.includes(roleItem) - }) - if (!isMatch) { - throw { - errCode: ERROR.PERMISSION_ERROR - } - } -} - -function hasPermission (...permissionList) { - const userRole = this.authInfo.role || [] - const userPermission = this.authInfo.permission || [] - if (userRole.includes('admin')) { - return - } - const isMatch = permissionList.every(permissionItem => { - return userPermission.includes(permissionItem) - }) - if (!isMatch) { - throw { - errCode: ERROR.PERMISSION_ERROR - } - } -} - -module.exports = { - hasRole, - hasPermission -} +const { + ERROR +} = require('../common/error') + +function hasRole (...roleList) { + const userRole = this.authInfo.role || [] + if (userRole.includes('admin')) { + return + } + const isMatch = roleList.every(roleItem => { + return userRole.includes(roleItem) + }) + if (!isMatch) { + throw { + errCode: ERROR.PERMISSION_ERROR + } + } +} + +function hasPermission (...permissionList) { + const userRole = this.authInfo.role || [] + const userPermission = this.authInfo.permission || [] + if (userRole.includes('admin')) { + return + } + const isMatch = permissionList.every(permissionItem => { + return userPermission.includes(permissionItem) + }) + if (!isMatch) { + throw { + errCode: ERROR.PERMISSION_ERROR + } + } +} + +module.exports = { + hasRole, + hasPermission +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/uni-id-log.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/uni-id-log.js index 37ce6552..8202d587 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/uni-id-log.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/uni-id-log.js @@ -1,39 +1,39 @@ -const db = uniCloud.database() -module.exports = async function ({ - data = {}, - success = true, - type = 'login' -} = {}) { - const now = Date.now() - const uniIdLogCollection = db.collection('uni-id-log') - const requiredDataKeyList = ['user_id', 'username', 'email', 'mobile'] - const dataCopy = {} - for (let i = 0; i < requiredDataKeyList.length; i++) { - const key = requiredDataKeyList[i] - if (key in data && typeof data[key] === 'string') { - dataCopy[key] = data[key] - } - } - const { - appId, - clientIP, - deviceId, - userAgent - } = this.getClientInfo() - const logData = { - appid: appId, - device_id: deviceId, - ip: clientIP, - type, - ua: userAgent, - create_date: now, - ...dataCopy - } - - if (success) { - logData.state = 1 - } else { - logData.state = 0 - } - return uniIdLogCollection.add(logData) -} +const db = uniCloud.database() +module.exports = async function ({ + data = {}, + success = true, + type = 'login' +} = {}) { + const now = Date.now() + const uniIdLogCollection = db.collection('uni-id-log') + const requiredDataKeyList = ['user_id', 'username', 'email', 'mobile'] + const dataCopy = {} + for (let i = 0; i < requiredDataKeyList.length; i++) { + const key = requiredDataKeyList[i] + if (key in data && typeof data[key] === 'string') { + dataCopy[key] = data[key] + } + } + const { + appId, + clientIP, + deviceId, + userAgent + } = this.getClientInfo() + const logData = { + appid: appId, + device_id: deviceId, + ip: clientIP, + type, + ua: userAgent, + create_date: now, + ...dataCopy + } + + if (success) { + logData.state = 1 + } else { + logData.state = 0 + } + return uniIdLogCollection.add(logData) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/validate.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/validate.js index 52ff0476..a58e8b47 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/validate.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/validate.js @@ -1,7 +1,7 @@ -module.exports = function (value = {}, schema = {}) { - const validateRes = this.validator.validate(value, schema) - if (validateRes) { - delete validateRes.schemaKey - throw validateRes - } -} +module.exports = function (value = {}, schema = {}) { + const validateRes = this.validator.validate(value, schema) + if (validateRes) { + delete validateRes.schemaKey + throw validateRes + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/close-account.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/close-account.js index f1bdf969..58fdb9d9 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/close-account.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/close-account.js @@ -1,16 +1,16 @@ -const { - setUserStatus -} = require('../../lib/utils/update-user-info') -const { - USER_STATUS -} = require('../../common/constants') - -/** - * 注销账户 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#close-account - * @returns - */ -module.exports = async function () { - const { uid } = this.authInfo - return setUserStatus(uid, USER_STATUS.CLOSED) -} +const { + setUserStatus +} = require('../../lib/utils/update-user-info') +const { + USER_STATUS +} = require('../../common/constants') + +/** + * 注销账户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#close-account + * @returns + */ +module.exports = async function () { + const { uid } = this.authInfo + return setUserStatus(uid, USER_STATUS.CLOSED) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/get-account-info.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/get-account-info.js index 7b8599a5..b57fe008 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/get-account-info.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/get-account-info.js @@ -1,69 +1,69 @@ -const { - userCollection -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') - -function isUsernameSet (userRecord) { - return !!userRecord.username -} -function isNicknameSet (userRecord) { - return !!userRecord.nickname -} -function isPasswordSet (userRecord) { - return !!userRecord.password -} -function isMobileBound (userRecord) { - return !!(userRecord.mobile && userRecord.mobile_confirmed) -} -function isEmailBound (userRecord) { - return !!(userRecord.email && userRecord.email_confirmed) -} -function isWeixinBound (userRecord) { - return !!( - userRecord.wx_unionid || - Object.keys(userRecord.wx_openid || {}).length - ) -} -function isQQBound (userRecord) { - return !!( - userRecord.qq_unionid || - Object.keys(userRecord.qq_openid || {}).length - ) -} -function isAlipayBound (userRecord) { - return !!userRecord.ali_openid -} -function isAppleBound (userRecord) { - return !!userRecord.apple_openid -} - -/** - * 获取账户账户简略信息 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-account-info - */ -module.exports = async function () { - const { - uid - } = this.authInfo - const getUserRes = await userCollection.doc(uid).get() - const userRecord = getUserRes && getUserRes.data && getUserRes.data[0] - if (!userRecord) { - throw { - errCode: ERROR.ACCOUNT_NOT_EXISTS - } - } - return { - errCode: 0, - isUsernameSet: isUsernameSet(userRecord), - isNicknameSet: isNicknameSet(userRecord), - isPasswordSet: isPasswordSet(userRecord), - isMobileBound: isMobileBound(userRecord), - isEmailBound: isEmailBound(userRecord), - isWeixinBound: isWeixinBound(userRecord), - isQQBound: isQQBound(userRecord), - isAlipayBound: isAlipayBound(userRecord), - isAppleBound: isAppleBound(userRecord) - } -} +const { + userCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +function isUsernameSet (userRecord) { + return !!userRecord.username +} +function isNicknameSet (userRecord) { + return !!userRecord.nickname +} +function isPasswordSet (userRecord) { + return !!userRecord.password +} +function isMobileBound (userRecord) { + return !!(userRecord.mobile && userRecord.mobile_confirmed) +} +function isEmailBound (userRecord) { + return !!(userRecord.email && userRecord.email_confirmed) +} +function isWeixinBound (userRecord) { + return !!( + userRecord.wx_unionid || + Object.keys(userRecord.wx_openid || {}).length + ) +} +function isQQBound (userRecord) { + return !!( + userRecord.qq_unionid || + Object.keys(userRecord.qq_openid || {}).length + ) +} +function isAlipayBound (userRecord) { + return !!userRecord.ali_openid +} +function isAppleBound (userRecord) { + return !!userRecord.apple_openid +} + +/** + * 获取账户账户简略信息 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-account-info + */ +module.exports = async function () { + const { + uid + } = this.authInfo + const getUserRes = await userCollection.doc(uid).get() + const userRecord = getUserRes && getUserRes.data && getUserRes.data[0] + if (!userRecord) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + return { + errCode: 0, + isUsernameSet: isUsernameSet(userRecord), + isNicknameSet: isNicknameSet(userRecord), + isPasswordSet: isPasswordSet(userRecord), + isMobileBound: isMobileBound(userRecord), + isEmailBound: isEmailBound(userRecord), + isWeixinBound: isWeixinBound(userRecord), + isQQBound: isQQBound(userRecord), + isAlipayBound: isAlipayBound(userRecord), + isAppleBound: isAppleBound(userRecord) + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/index.js index f43cd273..7a3a849c 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/index.js @@ -1,7 +1,7 @@ -module.exports = { - updatePwd: require('./update-pwd'), - resetPwdBySms: require('./reset-pwd-by-sms'), - resetPwdByEmail: require('./reset-pwd-by-email'), - closeAccount: require('./close-account'), - getAccountInfo: require('./get-account-info') -} +module.exports = { + updatePwd: require('./update-pwd'), + resetPwdBySms: require('./reset-pwd-by-sms'), + resetPwdByEmail: require('./reset-pwd-by-email'), + closeAccount: require('./close-account'), + getAccountInfo: require('./get-account-info') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-email.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-email.js index 914a05ee..63611b3d 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-email.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-email.js @@ -1,119 +1,119 @@ -const { - ERROR -} = require('../../common/error') -const { - getNeedCaptcha, - verifyCaptcha -} = require('../../lib/utils/captcha') -const { - verifyEmailCode -} = require('../../lib/utils/verify-code') -const { - userCollection, - EMAIL_SCENE, - CAPTCHA_SCENE, - LOG_TYPE -} = require('../../common/constants') -const { - findUser -} = require('../../lib/utils/account') -const PasswordUtils = require('../../lib/utils/password') - -/** - * 通过邮箱验证码重置密码 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#reset-pwd-by-email - * @param {object} params - * @param {string} params.email 邮箱 - * @param {string} params.code 邮箱验证码 - * @param {string} params.password 密码 - * @param {string} params.captcha 图形验证码 - * @returns {object} - */ -module.exports = async function (params = {}) { - const schema = { - email: 'email', - code: 'string', - password: 'password', - captcha: { - required: false, - type: 'string' - } - } - this.middleware.validate(params, schema) - const { - email, - code, - password, - captcha - } = params - - const needCaptcha = await getNeedCaptcha.call(this, { - email, - type: LOG_TYPE.RESET_PWD_BY_EMAIL - }) - if (needCaptcha) { - await verifyCaptcha.call(this, { - captcha, - scene: CAPTCHA_SCENE.RESET_PWD_BY_EMAIL - }) - } - try { - // 验证手机号验证码,验证不通过时写入失败日志 - await verifyEmailCode({ - email, - code, - scene: EMAIL_SCENE.RESET_PWD_BY_EMAIL - }) - } catch (error) { - await this.middleware.uniIdLog({ - data: { - email - }, - type: LOG_TYPE.RESET_PWD_BY_EMAIL, - success: false - }) - throw error - } - // 根据手机号查找匹配的用户 - const userMatched = await findUser.call(this, { - userQuery: { - email - }, - authorizedApp: [this.getClientInfo().appId] - }) - if (userMatched.length === 0) { - throw { - errCode: ERROR.ACCOUNT_NOT_EXISTS - } - } else if (userMatched.length > 1) { - throw { - errCode: ERROR.ACCOUNT_CONFLICT - } - } - const { _id: uid } = userMatched[0] - const { - passwordHash, - version - } = new PasswordUtils({ - passwordSecret: this.config.passwordSecret - }).generatePasswordHash({ - password - }) - // 更新用户密码 - await userCollection.doc(uid).update({ - password: passwordHash, - password_secret_version: version, - valid_token_date: Date.now() - }) - - // 写入成功日志 - await this.middleware.uniIdLog({ - data: { - email - }, - type: LOG_TYPE.RESET_PWD_BY_SMS - }) - return { - errCode: 0 - } -} +const { + ERROR +} = require('../../common/error') +const { + getNeedCaptcha, + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + verifyEmailCode +} = require('../../lib/utils/verify-code') +const { + userCollection, + EMAIL_SCENE, + CAPTCHA_SCENE, + LOG_TYPE +} = require('../../common/constants') +const { + findUser +} = require('../../lib/utils/account') +const PasswordUtils = require('../../lib/utils/password') + +/** + * 通过邮箱验证码重置密码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#reset-pwd-by-email + * @param {object} params + * @param {string} params.email 邮箱 + * @param {string} params.code 邮箱验证码 + * @param {string} params.password 密码 + * @param {string} params.captcha 图形验证码 + * @returns {object} + */ +module.exports = async function (params = {}) { + const schema = { + email: 'email', + code: 'string', + password: 'password', + captcha: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + const { + email, + code, + password, + captcha + } = params + + const needCaptcha = await getNeedCaptcha.call(this, { + email, + type: LOG_TYPE.RESET_PWD_BY_EMAIL + }) + if (needCaptcha) { + await verifyCaptcha.call(this, { + captcha, + scene: CAPTCHA_SCENE.RESET_PWD_BY_EMAIL + }) + } + try { + // 验证手机号验证码,验证不通过时写入失败日志 + await verifyEmailCode({ + email, + code, + scene: EMAIL_SCENE.RESET_PWD_BY_EMAIL + }) + } catch (error) { + await this.middleware.uniIdLog({ + data: { + email + }, + type: LOG_TYPE.RESET_PWD_BY_EMAIL, + success: false + }) + throw error + } + // 根据手机号查找匹配的用户 + const userMatched = await findUser.call(this, { + userQuery: { + email + }, + authorizedApp: [this.getClientInfo().appId] + }) + if (userMatched.length === 0) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } else if (userMatched.length > 1) { + throw { + errCode: ERROR.ACCOUNT_CONFLICT + } + } + const { _id: uid } = userMatched[0] + const { + passwordHash, + version + } = new PasswordUtils({ + passwordSecret: this.config.passwordSecret + }).generatePasswordHash({ + password + }) + // 更新用户密码 + await userCollection.doc(uid).update({ + password: passwordHash, + password_secret_version: version, + valid_token_date: Date.now() + }) + + // 写入成功日志 + await this.middleware.uniIdLog({ + data: { + email + }, + type: LOG_TYPE.RESET_PWD_BY_SMS + }) + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/add-user.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/add-user.js index 6baa5752..5b494e2d 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/add-user.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/add-user.js @@ -1,118 +1,118 @@ -const { - findUser -} = require('../../lib/utils/account') -const { - ERROR -} = require('../../common/error') -const { - userCollection -} = require('../../common/constants') -const PasswordUtils = require('../../lib/utils/password') - -/** - * 新增用户 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#add-user - * @param {Object} params - * @param {String} params.username 用户名 - * @param {String} params.password 密码 - * @param {String} params.nickname 昵称 - * @param {Array} params.authorizedApp 允许登录的AppID列表 - * @param {Array} params.role 用户角色列表 - * @param {String} params.mobile 手机号 - * @param {String} params.email 邮箱 - * @param {Array} params.tags 用户标签 - * @param {Number} params.status 用户状态 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - username: 'username', - password: 'password', - authorizedApp: { - required: false, - type: 'array' - }, // 指定允许登录的app,传空数组或不传时表示可以不可以在任何端登录 - nickname: { - required: false, - type: 'nickname' - }, - role: { - require: false, - type: 'array' - }, - mobile: { - required: false, - type: 'mobile' - }, - email: { - required: false, - type: 'email' - }, - tags: { - required: false, - type: 'array' - }, - status: { - required: false, - type: 'number' - } - } - this.middleware.validate(params, schema) - const { - username, - password, - authorizedApp, - nickname, - role, - mobile, - email, - tags, - status - } = params - const userMatched = await findUser({ - userQuery: { - username, - mobile, - email - }, - authorizedApp - }) - if (userMatched.length) { - throw { - errCode: ERROR.ACCOUNT_EXISTS - } - } - const passwordUtils = new PasswordUtils({ - passwordSecret: this.config.passwordSecret - }) - const { - passwordHash, - version - } = passwordUtils.generatePasswordHash({ - password - }) - const data = { - username, - password: passwordHash, - password_secret_version: version, - dcloud_appid: authorizedApp || [], - nickname, - role: role || [], - mobile, - email, - tags: tags || [], - status - } - if (email) { - data.email_confirmed = 1 - } - if (mobile) { - data.mobile_confirmed = 1 - } - - await userCollection.add(data) - return { - errCode: 0, - errMsg: '' - } -} +const { + findUser +} = require('../../lib/utils/account') +const { + ERROR +} = require('../../common/error') +const { + userCollection +} = require('../../common/constants') +const PasswordUtils = require('../../lib/utils/password') + +/** + * 新增用户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#add-user + * @param {Object} params + * @param {String} params.username 用户名 + * @param {String} params.password 密码 + * @param {String} params.nickname 昵称 + * @param {Array} params.authorizedApp 允许登录的AppID列表 + * @param {Array} params.role 用户角色列表 + * @param {String} params.mobile 手机号 + * @param {String} params.email 邮箱 + * @param {Array} params.tags 用户标签 + * @param {Number} params.status 用户状态 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + username: 'username', + password: 'password', + authorizedApp: { + required: false, + type: 'array' + }, // 指定允许登录的app,传空数组或不传时表示可以不可以在任何端登录 + nickname: { + required: false, + type: 'nickname' + }, + role: { + require: false, + type: 'array' + }, + mobile: { + required: false, + type: 'mobile' + }, + email: { + required: false, + type: 'email' + }, + tags: { + required: false, + type: 'array' + }, + status: { + required: false, + type: 'number' + } + } + this.middleware.validate(params, schema) + const { + username, + password, + authorizedApp, + nickname, + role, + mobile, + email, + tags, + status + } = params + const userMatched = await findUser({ + userQuery: { + username, + mobile, + email + }, + authorizedApp + }) + if (userMatched.length) { + throw { + errCode: ERROR.ACCOUNT_EXISTS + } + } + const passwordUtils = new PasswordUtils({ + passwordSecret: this.config.passwordSecret + }) + const { + passwordHash, + version + } = passwordUtils.generatePasswordHash({ + password + }) + const data = { + username, + password: passwordHash, + password_secret_version: version, + dcloud_appid: authorizedApp || [], + nickname, + role: role || [], + mobile, + email, + tags: tags || [], + status + } + if (email) { + data.email_confirmed = 1 + } + if (mobile) { + data.mobile_confirmed = 1 + } + + await userCollection.add(data) + return { + errCode: 0, + errMsg: '' + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/index.js index c8830f54..6baff536 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/index.js @@ -1,4 +1,4 @@ -module.exports = { - addUser: require('./add-user'), - updateUser: require('./update-user') -} +module.exports = { + addUser: require('./add-user'), + updateUser: require('./update-user') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/get-supported-login-type.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/get-supported-login-type.js index 476e2342..7d235fed 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/get-supported-login-type.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/get-supported-login-type.js @@ -1,71 +1,71 @@ -function isMobileCodeSupported () { - const config = this.config - return !!(config.service && config.service.sms && config.service.sms.smsKey) -} - -function isUniverifySupport () { - const config = this.config - return !!(config.service && config.service.univerify && config.service.univerify.apiKey) -} - -function isWeixinSupported () { - this.configUtils.getOauthConfig({ - provider: 'weixin' - }) - return true -} - -function isQQSupported () { - this.configUtils.getOauthConfig({ - provider: 'qq' - }) - return true -} - -function isAppleSupported () { - this.configUtils.getOauthConfig({ - provider: 'apple' - }) - return true -} - -function isAlipaySupported () { - this.configUtils.getOauthConfig({ - provider: 'alipay' - }) - return true -} - -const loginTypeTester = { - 'mobile-code': isMobileCodeSupported, - univerify: isUniverifySupport, - weixin: isWeixinSupported, - qq: isQQSupported, - apple: isAppleSupported, - alipay: isAlipaySupported -} - -/** - * 获取支持的登录方式 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-supported-login-type - * @returns - */ -module.exports = async function () { - const supportedLoginType = [ - 'username-password', - 'mobile-password', - 'email-password' - ] - for (const type in loginTypeTester) { - try { - if (loginTypeTester[type].call(this)) { - supportedLoginType.push(type) - } - } catch (error) { } - } - return { - errCode: 0, - errMsg: '', - supportedLoginType - } -} +function isMobileCodeSupported () { + const config = this.config + return !!(config.service && config.service.sms && config.service.sms.smsKey) +} + +function isUniverifySupport () { + const config = this.config + return !!(config.service && config.service.univerify && config.service.univerify.apiKey) +} + +function isWeixinSupported () { + this.configUtils.getOauthConfig({ + provider: 'weixin' + }) + return true +} + +function isQQSupported () { + this.configUtils.getOauthConfig({ + provider: 'qq' + }) + return true +} + +function isAppleSupported () { + this.configUtils.getOauthConfig({ + provider: 'apple' + }) + return true +} + +function isAlipaySupported () { + this.configUtils.getOauthConfig({ + provider: 'alipay' + }) + return true +} + +const loginTypeTester = { + 'mobile-code': isMobileCodeSupported, + univerify: isUniverifySupport, + weixin: isWeixinSupported, + qq: isQQSupported, + apple: isAppleSupported, + alipay: isAlipaySupported +} + +/** + * 获取支持的登录方式 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-supported-login-type + * @returns + */ +module.exports = async function () { + const supportedLoginType = [ + 'username-password', + 'mobile-password', + 'email-password' + ] + for (const type in loginTypeTester) { + try { + if (loginTypeTester[type].call(this)) { + supportedLoginType.push(type) + } + } catch (error) { } + } + return { + errCode: 0, + errMsg: '', + supportedLoginType + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/index.js index e22f9f2c..d6c28ccf 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/index.js @@ -1,3 +1,3 @@ -module.exports = { - getSupportedLoginType: require('./get-supported-login-type') -} +module.exports = { + getSupportedLoginType: require('./get-supported-login-type') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/accept-invite.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/accept-invite.js index 2461e061..c1d3ba97 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/accept-invite.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/accept-invite.js @@ -1,25 +1,25 @@ -const { - acceptInvite -} = require('../../lib/utils/fission') - -/** - * 接受邀请 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#accept-invite - * @param {Object} params - * @param {String} params.inviteCode 邀请码 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - inviteCode: 'string' - } - this.middleware.validate(params, schema) - const { - inviteCode - } = params - const uid = this.authInfo.uid - return acceptInvite({ - uid, - inviteCode - }) -} +const { + acceptInvite +} = require('../../lib/utils/fission') + +/** + * 接受邀请 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#accept-invite + * @param {Object} params + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + inviteCode: 'string' + } + this.middleware.validate(params, schema) + const { + inviteCode + } = params + const uid = this.authInfo.uid + return acceptInvite({ + uid, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/get-invited-user.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/get-invited-user.js index 93d46719..d232977d 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/get-invited-user.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/get-invited-user.js @@ -1,80 +1,80 @@ -const { - userCollection -} = require('../../common/constants') -const { - coverMobile -} = require('../../common/utils') - -/** - * 获取受邀用户 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-invited-user - * @param {Object} params - * @param {Number} params.level 获取受邀用户的级数,1表示直接邀请的用户 - * @param {Number} params.limit 返回数据大小 - * @param {Number} params.offset 返回数据偏移 - * @param {Boolean} params.needTotal 是否需要返回总数 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - level: 'number', - limit: { - required: false, - type: 'number' - }, - offset: { - required: false, - type: 'number' - }, - needTotal: { - required: false, - type: 'boolean' - } - } - this.middleware.validate(params, schema) - const { - level, - limit = 20, - offset = 0, - needTotal = false - } = params - const uid = this.authInfo.uid - const query = { - [`inviter_uid.${level - 1}`]: uid - } - const getUserRes = await userCollection.where(query) - .field({ - _id: true, - avatar: true, - avatar_file: true, - username: true, - nickname: true, - mobile: true, - invite_time: true - }) - .orderBy('invite_time', 'desc') - .skip(offset) - .limit(limit) - .get() - - const invitedUser = getUserRes.data.map(item => { - return { - uid: item._id, - username: item.username, - nickname: item.nickname, - mobile: coverMobile(item.mobile), - inviteTime: item.invite_time, - avatar: item.avatar, - avatarFile: item.avatar_file - } - }) - const result = { - errCode: 0, - invitedUser - } - if (needTotal) { - const getTotalRes = await userCollection.where(query).count() - result.total = getTotalRes.total - } - return result -} +const { + userCollection +} = require('../../common/constants') +const { + coverMobile +} = require('../../common/utils') + +/** + * 获取受邀用户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-invited-user + * @param {Object} params + * @param {Number} params.level 获取受邀用户的级数,1表示直接邀请的用户 + * @param {Number} params.limit 返回数据大小 + * @param {Number} params.offset 返回数据偏移 + * @param {Boolean} params.needTotal 是否需要返回总数 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + level: 'number', + limit: { + required: false, + type: 'number' + }, + offset: { + required: false, + type: 'number' + }, + needTotal: { + required: false, + type: 'boolean' + } + } + this.middleware.validate(params, schema) + const { + level, + limit = 20, + offset = 0, + needTotal = false + } = params + const uid = this.authInfo.uid + const query = { + [`inviter_uid.${level - 1}`]: uid + } + const getUserRes = await userCollection.where(query) + .field({ + _id: true, + avatar: true, + avatar_file: true, + username: true, + nickname: true, + mobile: true, + invite_time: true + }) + .orderBy('invite_time', 'desc') + .skip(offset) + .limit(limit) + .get() + + const invitedUser = getUserRes.data.map(item => { + return { + uid: item._id, + username: item.username, + nickname: item.nickname, + mobile: coverMobile(item.mobile), + inviteTime: item.invite_time, + avatar: item.avatar, + avatarFile: item.avatar_file + } + }) + const result = { + errCode: 0, + invitedUser + } + if (needTotal) { + const getTotalRes = await userCollection.where(query).count() + result.total = getTotalRes.total + } + return result +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/index.js index 4a9bee11..dcca9a34 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/index.js @@ -1,4 +1,4 @@ -module.exports = { - acceptInvite: require('./accept-invite'), - getInvitedUser: require('./get-invited-user') -} +module.exports = { + acceptInvite: require('./accept-invite'), + getInvitedUser: require('./get-invited-user') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/index.js index e1d8593b..7fbd9644 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/index.js @@ -1,19 +1,20 @@ -module.exports = { - login: require('./login'), - loginBySms: require('./login-by-sms'), - loginByUniverify: require('./login-by-univerify'), - loginByWeixin: require('./login-by-weixin'), - loginByAlipay: require('./login-by-alipay'), - loginByQQ: require('./login-by-qq'), - loginByApple: require('./login-by-apple'), - loginByBaidu: require('./login-by-baidu'), - loginByDingtalk: require('./login-by-dingtalk'), - loginByToutiao: require('./login-by-toutiao'), - loginByDouyin: require('./login-by-douyin'), - loginByWeibo: require('./login-by-weibo'), - loginByTaobao: require('./login-by-taobao'), - loginByEmailLink: require('./login-by-email-link'), - loginByEmailCode: require('./login-by-email-code'), - loginByFacebook: require('./login-by-facebook'), - loginByGoogle: require('./login-by-google') -} +module.exports = { + login: require('./login'), + loginBySms: require('./login-by-sms'), + loginByUniverify: require('./login-by-univerify'), + loginByWeixin: require('./login-by-weixin'), + loginByAlipay: require('./login-by-alipay'), + loginByQQ: require('./login-by-qq'), + loginByApple: require('./login-by-apple'), + loginByBaidu: require('./login-by-baidu'), + loginByDingtalk: require('./login-by-dingtalk'), + loginByToutiao: require('./login-by-toutiao'), + loginByDouyin: require('./login-by-douyin'), + loginByWeibo: require('./login-by-weibo'), + loginByTaobao: require('./login-by-taobao'), + loginByEmailLink: require('./login-by-email-link'), + loginByEmailCode: require('./login-by-email-code'), + loginByFacebook: require('./login-by-facebook'), + loginByGoogle: require('./login-by-google'), + loginByWeixinMobile: require('./login-by-weixin-mobile') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-alipay.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-alipay.js index d5d46314..4611b0cb 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-alipay.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-alipay.js @@ -1,70 +1,70 @@ -const { - initAlipay -} = require('../../lib/third-party/index') -const { - ERROR -} = require('../../common/error') -const { - preUnifiedLogin, - postUnifiedLogin -} = require('../../lib/utils/unified-login') -const { - LOG_TYPE -} = require('../../common/constants') - -/** - * 支付宝登录 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-alipay - * @param {Object} params - * @param {String} params.code 支付宝小程序客户端登录返回的code - * @param {String} params.inviteCode 邀请码 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - code: 'string', - inviteCode: { - type: 'string', - required: false - } - } - this.middleware.validate(params, schema) - const { - code, - inviteCode - } = params - const alipayApi = initAlipay.call(this) - let getAlipayAccountResult - try { - getAlipayAccountResult = await alipayApi.code2Session(code) - } catch (error) { - console.error(error) - await this.middleware.uniIdLog({ - success: false, - type: LOG_TYPE.LOGIN - }) - throw { - errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED - } - } - - const { - openid - } = getAlipayAccountResult - - const { - type, - user - } = await preUnifiedLogin.call(this, { - user: { - ali_openid: openid - } - }) - return postUnifiedLogin.call(this, { - user, - extraData: {}, - isThirdParty: true, - type, - inviteCode - }) -} +const { + initAlipay +} = require('../../lib/third-party/index') +const { + ERROR +} = require('../../common/error') +const { + preUnifiedLogin, + postUnifiedLogin +} = require('../../lib/utils/unified-login') +const { + LOG_TYPE +} = require('../../common/constants') + +/** + * 支付宝登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-alipay + * @param {Object} params + * @param {String} params.code 支付宝小程序客户端登录返回的code + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + code: 'string', + inviteCode: { + type: 'string', + required: false + } + } + this.middleware.validate(params, schema) + const { + code, + inviteCode + } = params + const alipayApi = initAlipay.call(this) + let getAlipayAccountResult + try { + getAlipayAccountResult = await alipayApi.code2Session(code) + } catch (error) { + console.error(error) + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.LOGIN + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + + const { + openid + } = getAlipayAccountResult + + const { + type, + user + } = await preUnifiedLogin.call(this, { + user: { + ali_openid: openid + } + }) + return postUnifiedLogin.call(this, { + user, + extraData: {}, + isThirdParty: true, + type, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-apple.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-apple.js index 5f39e623..5a1e2fef 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-apple.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-apple.js @@ -1,77 +1,77 @@ -const { - initApple -} = require('../../lib/third-party/index') -const { - ERROR -} = require('../../common/error') -const { - preUnifiedLogin, - postUnifiedLogin -} = require('../../lib/utils/unified-login') -const { - LOG_TYPE -} = require('../../common/constants') - -/** - * 苹果登录 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-apple - * @param {Object} params - * @param {String} params.identityToken 苹果登录返回的identityToken - * @param {String} params.nickname 用户昵称 - * @param {String} params.inviteCode 邀请码 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - identityToken: 'string', - nickname: { - required: false, - type: 'nickname' - }, - inviteCode: { - required: false, - type: 'string' - } - } - this.middleware.validate(params, schema) - const { - identityToken, - nickname, - inviteCode - } = params - const appleApi = initApple.call(this) - let verifyResult - try { - verifyResult = await appleApi.verifyIdentityToken(identityToken) - } catch (error) { - console.error(error) - await this.middleware.uniIdLog({ - success: false, - type: LOG_TYPE.LOGIN - }) - throw { - errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED - } - } - const { - openid - } = verifyResult - - const { - type, - user - } = await preUnifiedLogin.call(this, { - user: { - apple_openid: openid - } - }) - return postUnifiedLogin.call(this, { - user, - extraData: { - nickname - }, - isThirdParty: true, - type, - inviteCode - }) -} +const { + initApple +} = require('../../lib/third-party/index') +const { + ERROR +} = require('../../common/error') +const { + preUnifiedLogin, + postUnifiedLogin +} = require('../../lib/utils/unified-login') +const { + LOG_TYPE +} = require('../../common/constants') + +/** + * 苹果登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-apple + * @param {Object} params + * @param {String} params.identityToken 苹果登录返回的identityToken + * @param {String} params.nickname 用户昵称 + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + identityToken: 'string', + nickname: { + required: false, + type: 'nickname' + }, + inviteCode: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + const { + identityToken, + nickname, + inviteCode + } = params + const appleApi = initApple.call(this) + let verifyResult + try { + verifyResult = await appleApi.verifyIdentityToken(identityToken) + } catch (error) { + console.error(error) + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.LOGIN + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + const { + openid + } = verifyResult + + const { + type, + user + } = await preUnifiedLogin.call(this, { + user: { + apple_openid: openid + } + }) + return postUnifiedLogin.call(this, { + user, + extraData: { + nickname + }, + isThirdParty: true, + type, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-baidu.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-baidu.js index 856449dc..9d4b4539 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-baidu.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-baidu.js @@ -1,9 +1,9 @@ -/** - * 百度登录 - * @param {Object} params - * @returns - */ -module.exports = async function (params = {}) { - // 此接口暂未实现,欢迎向我们提交pr - throw new Error('api[loginByBaidu] is not yet implemented') -} +/** + * 百度登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByBaidu] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-dingtalk.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-dingtalk.js index afe1f016..22c2f8b6 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-dingtalk.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-dingtalk.js @@ -1,9 +1,9 @@ -/** - * 钉钉登录 - * @param {Object} params - * @returns - */ -module.exports = async function (params = {}) { - // 此接口暂未实现,欢迎向我们提交pr - throw new Error('api[loginByDingtalk] is not yet implemented') -} +/** + * 钉钉登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByDingtalk] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-douyin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-douyin.js index 8cd4ab56..cecf581a 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-douyin.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-douyin.js @@ -1,9 +1,9 @@ -/** - * 抖音登录 - * @param {Object} params - * @returns - */ -module.exports = async function (params = {}) { - // 此接口暂未实现,欢迎向我们提交pr - throw new Error('api[loginByDouyin] is not yet implemented') -} +/** + * 抖音登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByDouyin] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-code.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-code.js index c3af08f0..1f3c3a66 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-code.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-code.js @@ -1,9 +1,9 @@ -/** - * 邮箱验证码登录 - * @param {Object} params - * @returns - */ -module.exports = async function (params = {}) { - // 此接口暂未实现,欢迎向我们提交pr - throw new Error('api[loginByEmailCode] is not yet implemented') -} +/** + * 邮箱验证码登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByEmailCode] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-link.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-link.js index 0ebbf3ac..a8f9e6ff 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-link.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-link.js @@ -1,9 +1,9 @@ -/** - * 邮箱点击链接登录 - * @param {Object} params - * @returns - */ -module.exports = async function (params = {}) { - // 此接口暂未实现,欢迎向我们提交pr - throw new Error('api[loginByEmailLink] is not yet implemented') -} +/** + * 邮箱点击链接登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByEmailLink] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-facebook.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-facebook.js index 5c93bd4d..1a5eab89 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-facebook.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-facebook.js @@ -1,9 +1,9 @@ -/** - * Facebook登录 - * @param {Object} params - * @returns - */ -module.exports = async function (params = {}) { - // 此接口暂未实现,欢迎向我们提交pr - throw new Error('api[loginByFacebook] is not yet implemented') -} +/** + * Facebook登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByFacebook] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-google.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-google.js index 8054ece6..c12efe3e 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-google.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-google.js @@ -1,9 +1,9 @@ -/** - * Google登录 - * @param {Object} params - * @returns - */ -module.exports = async function (params = {}) { - // 此接口暂未实现,欢迎向我们提交pr - throw new Error('api[loginByGoogle] is not yet implemented') -} +/** + * Google登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByGoogle] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-qq.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-qq.js index 13379d72..9f7b0cea 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-qq.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-qq.js @@ -1,164 +1,164 @@ -const { - initQQ -} = require('../../lib/third-party/index') -const { - ERROR -} = require('../../common/error') -const { - preUnifiedLogin, - postUnifiedLogin -} = require('../../lib/utils/unified-login') -const { - LOG_TYPE -} = require('../../common/constants') -const { - getQQPlatform, - generateQQCache, - saveQQUserKey -} = require('../../lib/utils/qq') -const url = require('url') - -/** - * QQ登录 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-qq - * @param {Object} params - * @param {String} params.code QQ小程序登录返回的code参数 - * @param {String} params.accessToken App端QQ登录返回的accessToken参数 - * @param {String} params.accessTokenExpired accessToken过期时间,由App端QQ登录返回的expires_in参数计算而来,单位:毫秒 - * @param {String} params.inviteCode 邀请码 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - code: { - type: 'string', - required: false - }, - accessToken: { - type: 'string', - required: false - }, - accessTokenExpired: { - type: 'number', - required: false - }, - inviteCode: { - type: 'string', - required: false - } - } - this.middleware.validate(params, schema) - const { - code, - accessToken, - accessTokenExpired, - inviteCode - } = params - const { - appId - } = this.getClientInfo() - const qqApi = initQQ.call(this) - const qqPlatform = getQQPlatform.call(this) - let apiName - switch (qqPlatform) { - case 'mp': - apiName = 'code2Session' - break - case 'app': - apiName = 'getOpenidByToken' - break - default: - throw new Error('Unsupported qq platform') - } - let getQQAccountResult - try { - getQQAccountResult = await qqApi[apiName]({ - code, - accessToken - }) - } catch (error) { - console.error(error) - await this.middleware.uniIdLog({ - success: false, - type: LOG_TYPE.LOGIN - }) - throw { - errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED - } - } - - const { - openid, - unionid, - // 保存下面的字段 - sessionKey // QQ小程序用户sessionKey - } = getQQAccountResult - - const { - type, - user - } = await preUnifiedLogin.call(this, { - user: { - qq_openid: { - [qqPlatform]: openid - }, - qq_unionid: unionid - } - }) - const extraData = { - qq_openid: { - [`${qqPlatform}_${appId}`]: openid - } - } - if (type === 'register' && qqPlatform !== 'mp') { - const { - nickname, - avatar - } = await qqApi.getUserInfo({ - accessToken, - openid - }) - // eslint-disable-next-line n/no-deprecated-api - const extName = url.parse(avatar).pathname.split('.').pop() - const cloudPath = `user/avatar/${openid.slice(-8) + Date.now()}-avatar.${extName}` - const getAvatarRes = await uniCloud.httpclient.request(avatar) - if (getAvatarRes.status >= 400) { - throw { - errCode: ERROR.GET_THIRD_PARTY_USER_INFO_FAILED - } - } - const { - fileID - } = await uniCloud.uploadFile({ - cloudPath, - fileContent: getAvatarRes.data - }) - extraData.nickname = nickname - extraData.avatar_file = { - name: cloudPath, - extname: extName, - url: fileID - } - } - await saveQQUserKey.call(this, { - openid, - sessionKey, - accessToken, - accessTokenExpired - }) - return postUnifiedLogin.call(this, { - user, - extraData: { - ...extraData, - ...generateQQCache.call(this, { - openid, - sessionKey, // QQ小程序用户sessionKey - accessToken, // App端QQ用户accessToken - accessTokenExpired // App端QQ用户accessToken过期时间 - }) - }, - isThirdParty: true, - type, - inviteCode - }) -} +const { + initQQ +} = require('../../lib/third-party/index') +const { + ERROR +} = require('../../common/error') +const { + preUnifiedLogin, + postUnifiedLogin +} = require('../../lib/utils/unified-login') +const { + LOG_TYPE +} = require('../../common/constants') +const { + getQQPlatform, + generateQQCache, + saveQQUserKey +} = require('../../lib/utils/qq') +const url = require('url') + +/** + * QQ登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-qq + * @param {Object} params + * @param {String} params.code QQ小程序登录返回的code参数 + * @param {String} params.accessToken App端QQ登录返回的accessToken参数 + * @param {String} params.accessTokenExpired accessToken过期时间,由App端QQ登录返回的expires_in参数计算而来,单位:毫秒 + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + code: { + type: 'string', + required: false + }, + accessToken: { + type: 'string', + required: false + }, + accessTokenExpired: { + type: 'number', + required: false + }, + inviteCode: { + type: 'string', + required: false + } + } + this.middleware.validate(params, schema) + const { + code, + accessToken, + accessTokenExpired, + inviteCode + } = params + const { + appId + } = this.getClientInfo() + const qqApi = initQQ.call(this) + const qqPlatform = getQQPlatform.call(this) + let apiName + switch (qqPlatform) { + case 'mp': + apiName = 'code2Session' + break + case 'app': + apiName = 'getOpenidByToken' + break + default: + throw new Error('Unsupported qq platform') + } + let getQQAccountResult + try { + getQQAccountResult = await qqApi[apiName]({ + code, + accessToken + }) + } catch (error) { + console.error(error) + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.LOGIN + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + + const { + openid, + unionid, + // 保存下面的字段 + sessionKey // QQ小程序用户sessionKey + } = getQQAccountResult + + const { + type, + user + } = await preUnifiedLogin.call(this, { + user: { + qq_openid: { + [qqPlatform]: openid + }, + qq_unionid: unionid + } + }) + const extraData = { + qq_openid: { + [`${qqPlatform}_${appId}`]: openid + } + } + if (type === 'register' && qqPlatform !== 'mp') { + const { + nickname, + avatar + } = await qqApi.getUserInfo({ + accessToken, + openid + }) + // eslint-disable-next-line n/no-deprecated-api + const extName = url.parse(avatar).pathname.split('.').pop() + const cloudPath = `user/avatar/${openid.slice(-8) + Date.now()}-avatar.${extName}` + const getAvatarRes = await uniCloud.httpclient.request(avatar) + if (getAvatarRes.status >= 400) { + throw { + errCode: ERROR.GET_THIRD_PARTY_USER_INFO_FAILED + } + } + const { + fileID + } = await uniCloud.uploadFile({ + cloudPath, + fileContent: getAvatarRes.data + }) + extraData.nickname = nickname + extraData.avatar_file = { + name: cloudPath, + extname: extName, + url: fileID + } + } + await saveQQUserKey.call(this, { + openid, + sessionKey, + accessToken, + accessTokenExpired + }) + return postUnifiedLogin.call(this, { + user, + extraData: { + ...extraData, + ...generateQQCache.call(this, { + openid, + sessionKey, // QQ小程序用户sessionKey + accessToken, // App端QQ用户accessToken + accessTokenExpired // App端QQ用户accessToken过期时间 + }) + }, + isThirdParty: true, + type, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-taobao.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-taobao.js index 6a6d5994..8234fa07 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-taobao.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-taobao.js @@ -1,9 +1,9 @@ -/** - * 淘宝登录 - * @param {Object} params - * @returns - */ -module.exports = async function (params = {}) { - // 此接口暂未实现,欢迎向我们提交pr - throw new Error('api[loginByTaobao] is not yet implemented') -} +/** + * 淘宝登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByTaobao] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-toutiao.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-toutiao.js index 133aadba..11fda9b4 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-toutiao.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-toutiao.js @@ -1,9 +1,9 @@ -/** - * 头条登录 - * @param {Object} params - * @returns - */ -module.exports = async function (params = {}) { - // 此接口暂未实现,欢迎向我们提交pr - throw new Error('api[loginByToutiao] is not yet implemented') -} +/** + * 头条登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByToutiao] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-univerify.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-univerify.js index 53e681c6..05199b0a 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-univerify.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-univerify.js @@ -1,69 +1,69 @@ -const { - getPhoneNumber -} = require('../../lib/utils/univerify') -const { - preUnifiedLogin, - postUnifiedLogin -} = require('../../lib/utils/unified-login') -const { - LOG_TYPE -} = require('../../common/constants') - -/** - * App端一键登录 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-univerify - * @param {Object} params - * @param {String} params.access_token APP端一键登录返回的access_token - * @param {String} params.openid APP端一键登录返回的openid - * @param {String} params.inviteCode 邀请码 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - access_token: 'string', - openid: 'string', - inviteCode: { - required: false, - type: 'string' - } - } - this.middleware.validate(params, schema) - const { - // eslint-disable-next-line camelcase - access_token, - openid, - inviteCode - } = params - - let mobile - try { - const phoneInfo = await getPhoneNumber.call(this, { - // eslint-disable-next-line camelcase - access_token, - openid - }) - mobile = phoneInfo.phoneNumber - } catch (error) { - await this.middleware.uniIdLog({ - success: false, - type: LOG_TYPE.LOGIN - }) - throw error - } - const { - user, - type - } = await preUnifiedLogin.call(this, { - user: { - mobile - } - }) - return postUnifiedLogin.call(this, { - user, - extraData: { - mobile_confirmed: 1 - }, - type, - inviteCode - }) -} +const { + getPhoneNumber +} = require('../../lib/utils/univerify') +const { + preUnifiedLogin, + postUnifiedLogin +} = require('../../lib/utils/unified-login') +const { + LOG_TYPE +} = require('../../common/constants') + +/** + * App端一键登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-univerify + * @param {Object} params + * @param {String} params.access_token APP端一键登录返回的access_token + * @param {String} params.openid APP端一键登录返回的openid + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + access_token: 'string', + openid: 'string', + inviteCode: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + const { + // eslint-disable-next-line camelcase + access_token, + openid, + inviteCode + } = params + + let mobile + try { + const phoneInfo = await getPhoneNumber.call(this, { + // eslint-disable-next-line camelcase + access_token, + openid + }) + mobile = phoneInfo.phoneNumber + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.LOGIN + }) + throw error + } + const { + user, + type + } = await preUnifiedLogin.call(this, { + user: { + mobile + } + }) + return postUnifiedLogin.call(this, { + user, + extraData: { + mobile_confirmed: 1 + }, + type, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weibo.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weibo.js index 496cdb4b..b12a17f2 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weibo.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weibo.js @@ -1,9 +1,9 @@ -/** - * 微博登录 - * @param {Object} params - * @returns - */ -module.exports = async function (params = {}) { - // 此接口暂未实现,欢迎向我们提交pr - throw new Error('api[loginByWeibo] is not yet implemented') -} +/** + * 微博登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByWeibo] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin-mobile.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin-mobile.js new file mode 100644 index 00000000..f26b2b03 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin-mobile.js @@ -0,0 +1,109 @@ +const { + initWeixin +} = require('../../lib/third-party/index') +const { + getWeixinPlatform, + getWeixinAccessToken, + generateWeixinCache, + saveWeixinUserKey +} = require('../../lib/utils/weixin') +const { + ERROR +} = require('../../common/error') +const { + preUnifiedLogin, + postUnifiedLogin +} = require('../../lib/utils/unified-login') +const { + LOG_TYPE +} = require('../../common/constants') +const { + preBind, + postBind +} = require('../../lib/utils/relate') + +/** + * 微信授权手机号登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-weixin-mobile + * @param {Object} params + * @param {String} params.phoneCode 微信手机号返回的code + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + phoneCode: 'string', + inviteCode: { + type: 'string', + required: false + } + } + + this.middleware.validate(params, schema) + + const { phoneCode, inviteCode } = params + + const weixinApi = initWeixin.call(this) + let mobile + + try { + const accessToken = await getWeixinAccessToken.call(this) + const mobileRes = await weixinApi.getPhoneNumber(accessToken, phoneCode) + mobile = mobileRes.purePhoneNumber + } catch (error) { + console.error(error) + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.LOGIN + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + + const { type, user } = await preUnifiedLogin.call(this, { + user: { + mobile + } + }) + + let extraData = { + mobile_confirmed: 1 + } + + if (type === 'login') { + // 绑定手机号 + if (!user.mobile_confirmed) { + const bindAccount = { + mobile + } + await preBind.call(this, { + uid: user._id, + bindAccount, + logType: LOG_TYPE.BIND_MOBILE + }) + await postBind.call(this, { + uid: user._id, + bindAccount, + extraData: { + mobile_confirmed: 1 + }, + logType: LOG_TYPE.BIND_MOBILE + }) + extraData = { + ...extraData, + ...bindAccount + } + } + } + + return postUnifiedLogin.call(this, { + user, + extraData: { + ...extraData + }, + isThirdParty: false, + type, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin.js index 84c7ddc1..d2a4bcf5 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin.js @@ -1,154 +1,154 @@ -const { - initWeixin -} = require('../../lib/third-party/index') -const { - ERROR -} = require('../../common/error') -const { - preUnifiedLogin, - postUnifiedLogin -} = require('../../lib/utils/unified-login') -const { - generateWeixinCache, - getWeixinPlatform, - saveWeixinUserKey -} = require('../../lib/utils/weixin') -const { - LOG_TYPE -} = require('../../common/constants') -const url = require('url') - -/** - * 微信登录 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-weixin - * @param {Object} params - * @param {String} params.code 微信登录返回的code - * @param {String} params.inviteCode 邀请码 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - code: 'string', - inviteCode: { - type: 'string', - required: false - } - } - this.middleware.validate(params, schema) - const { - code, - inviteCode - } = params - const { - appId - } = this.getClientInfo() - const weixinApi = initWeixin.call(this) - const weixinPlatform = getWeixinPlatform.call(this) - let apiName - switch (weixinPlatform) { - case 'mp': - apiName = 'code2Session' - break - case 'app': - case 'h5': - case 'web': - apiName = 'getOauthAccessToken' - break - default: - throw new Error('Unsupported weixin platform') - } - let getWeixinAccountResult - try { - getWeixinAccountResult = await weixinApi[apiName](code) - } catch (error) { - console.error(error) - await this.middleware.uniIdLog({ - success: false, - type: LOG_TYPE.LOGIN - }) - throw { - errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED - } - } - - const { - openid, - unionid, - // 保存下面四个字段 - sessionKey, // 微信小程序用户sessionKey - accessToken, // App端微信用户accessToken - refreshToken, // App端微信用户refreshToken - expired: accessTokenExpired // App端微信用户accessToken过期时间 - } = getWeixinAccountResult - - const { - type, - user - } = await preUnifiedLogin.call(this, { - user: { - wx_openid: { - [weixinPlatform]: openid - }, - wx_unionid: unionid - } - }) - const extraData = { - wx_openid: { - [`${weixinPlatform}_${appId}`]: openid - } - } - if (type === 'register' && weixinPlatform !== 'mp') { - const { - nickname, - avatar - } = await weixinApi.getUserInfo({ - accessToken, - openid - }) - // eslint-disable-next-line n/no-deprecated-api - const avatarPath = url.parse(avatar).pathname - const extName = avatarPath.indexOf('.') > -1 ? url.parse(avatar).pathname.split('.').pop() : 'jpg' - const cloudPath = `user/avatar/${openid.slice(-8) + Date.now()}-avatar.${extName}` - const getAvatarRes = await uniCloud.httpclient.request(avatar) - if (getAvatarRes.status >= 400) { - throw { - errCode: ERROR.GET_THIRD_PARTY_USER_INFO_FAILED - } - } - const { - fileID - } = await uniCloud.uploadFile({ - cloudPath, - fileContent: getAvatarRes.data - }) - extraData.nickname = nickname - extraData.avatar_file = { - name: cloudPath, - extname: extName, - url: fileID - } - } - await saveWeixinUserKey.call(this, { - openid, - sessionKey, - accessToken, - refreshToken, - accessTokenExpired - }) - return postUnifiedLogin.call(this, { - user, - extraData: { - ...extraData, - ...generateWeixinCache.call(this, { - openid, - sessionKey, // 微信小程序用户sessionKey - accessToken, // App端微信用户accessToken - refreshToken, // App端微信用户refreshToken - accessTokenExpired // App端微信用户accessToken过期时间 - }) - }, - isThirdParty: true, - type, - inviteCode - }) -} +const { + initWeixin +} = require('../../lib/third-party/index') +const { + ERROR +} = require('../../common/error') +const { + preUnifiedLogin, + postUnifiedLogin +} = require('../../lib/utils/unified-login') +const { + generateWeixinCache, + getWeixinPlatform, + saveWeixinUserKey +} = require('../../lib/utils/weixin') +const { + LOG_TYPE +} = require('../../common/constants') +const url = require('url') + +/** + * 微信登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-weixin + * @param {Object} params + * @param {String} params.code 微信登录返回的code + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + code: 'string', + inviteCode: { + type: 'string', + required: false + } + } + this.middleware.validate(params, schema) + const { + code, + inviteCode + } = params + const { + appId + } = this.getClientInfo() + const weixinApi = initWeixin.call(this) + const weixinPlatform = getWeixinPlatform.call(this) + let apiName + switch (weixinPlatform) { + case 'mp': + apiName = 'code2Session' + break + case 'app': + case 'h5': + case 'web': + apiName = 'getOauthAccessToken' + break + default: + throw new Error('Unsupported weixin platform') + } + let getWeixinAccountResult + try { + getWeixinAccountResult = await weixinApi[apiName](code) + } catch (error) { + console.error(error) + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.LOGIN + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + + const { + openid, + unionid, + // 保存下面四个字段 + sessionKey, // 微信小程序用户sessionKey + accessToken, // App端微信用户accessToken + refreshToken, // App端微信用户refreshToken + expired: accessTokenExpired // App端微信用户accessToken过期时间 + } = getWeixinAccountResult + + const { + type, + user + } = await preUnifiedLogin.call(this, { + user: { + wx_openid: { + [weixinPlatform]: openid + }, + wx_unionid: unionid + } + }) + const extraData = { + wx_openid: { + [`${weixinPlatform}_${appId}`]: openid + } + } + if (type === 'register' && weixinPlatform !== 'mp') { + const { + nickname, + avatar + } = await weixinApi.getUserInfo({ + accessToken, + openid + }) + // eslint-disable-next-line n/no-deprecated-api + const avatarPath = url.parse(avatar).pathname + const extName = avatarPath.indexOf('.') > -1 ? url.parse(avatar).pathname.split('.').pop() : 'jpg' + const cloudPath = `user/avatar/${openid.slice(-8) + Date.now()}-avatar.${extName}` + const getAvatarRes = await uniCloud.httpclient.request(avatar) + if (getAvatarRes.status >= 400) { + throw { + errCode: ERROR.GET_THIRD_PARTY_USER_INFO_FAILED + } + } + const { + fileID + } = await uniCloud.uploadFile({ + cloudPath, + fileContent: getAvatarRes.data + }) + extraData.nickname = nickname + extraData.avatar_file = { + name: cloudPath, + extname: extName, + url: fileID + } + } + await saveWeixinUserKey.call(this, { + openid, + sessionKey, + accessToken, + refreshToken, + accessTokenExpired + }) + return postUnifiedLogin.call(this, { + user, + extraData: { + ...extraData, + ...generateWeixinCache.call(this, { + openid, + sessionKey, // 微信小程序用户sessionKey + accessToken, // App端微信用户accessToken + refreshToken, // App端微信用户refreshToken + accessTokenExpired // App端微信用户accessToken过期时间 + }) + }, + isThirdParty: true, + type, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login.js index 97e9cfea..8419ee8b 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login.js @@ -1,94 +1,94 @@ -const { - preLoginWithPassword, - postLogin -} = require('../../lib/utils/login') -const { - getNeedCaptcha, - verifyCaptcha -} = require('../../lib/utils/captcha') -const { - CAPTCHA_SCENE -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') - -/** - * 用户名密码登录 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login - * @param {Object} params - * @param {String} params.username 用户名 - * @param {String} params.mobile 手机号 - * @param {String} params.email 邮箱 - * @param {String} params.password 密码 - * @param {String} params.captcha 图形验证码 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - username: { - required: false, - type: 'username' - }, - mobile: { - required: false, - type: 'mobile' - }, - email: { - required: false, - type: 'email' - }, - password: 'password', - captcha: { - required: false, - type: 'string' - } - } - this.middleware.validate(params, schema) - const { - username, - mobile, - email, - password, - captcha - } = params - if (!username && !mobile && !email) { - throw { - errCode: ERROR.INVALID_USERNAME - } - } else if ( - (username && email) || - (username && mobile) || - (email && mobile) - ) { - throw { - errCode: ERROR.INVALID_PARAM - } - } - const needCaptcha = await getNeedCaptcha.call(this, { - username, - mobile, - email - }) - if (needCaptcha) { - await verifyCaptcha.call(this, { - captcha, - scene: CAPTCHA_SCENE.LOGIN_BY_PWD - }) - } - const { - user, - extraData - } = await preLoginWithPassword.call(this, { - user: { - username, - mobile, - email - }, - password - }) - return postLogin.call(this, { - user, - extraData - }) -} +const { + preLoginWithPassword, + postLogin +} = require('../../lib/utils/login') +const { + getNeedCaptcha, + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + CAPTCHA_SCENE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +/** + * 用户名密码登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login + * @param {Object} params + * @param {String} params.username 用户名 + * @param {String} params.mobile 手机号 + * @param {String} params.email 邮箱 + * @param {String} params.password 密码 + * @param {String} params.captcha 图形验证码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + username: { + required: false, + type: 'username' + }, + mobile: { + required: false, + type: 'mobile' + }, + email: { + required: false, + type: 'email' + }, + password: 'password', + captcha: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + const { + username, + mobile, + email, + password, + captcha + } = params + if (!username && !mobile && !email) { + throw { + errCode: ERROR.INVALID_USERNAME + } + } else if ( + (username && email) || + (username && mobile) || + (email && mobile) + ) { + throw { + errCode: ERROR.INVALID_PARAM + } + } + const needCaptcha = await getNeedCaptcha.call(this, { + username, + mobile, + email + }) + if (needCaptcha) { + await verifyCaptcha.call(this, { + captcha, + scene: CAPTCHA_SCENE.LOGIN_BY_PWD + }) + } + const { + user, + extraData + } = await preLoginWithPassword.call(this, { + user: { + username, + mobile, + email + }, + password + }) + return postLogin.call(this, { + user, + extraData + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/index.js index 544be2b7..897cc1c6 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/index.js @@ -1,3 +1,3 @@ -module.exports = { - logout: require('./logout') -} +module.exports = { + logout: require('./logout') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/logout.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/logout.js index 7d491c61..f11b4374 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/logout.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/logout.js @@ -1,15 +1,15 @@ -const { - logout -} = require('../../lib/utils/logout') - -/** - * 用户退出登录 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#logout - * @returns - */ -module.exports = async function () { - await logout.call(this) - return { - errCode: 0 - } -} +const { + logout +} = require('../../lib/utils/logout') + +/** + * 用户退出登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#logout + * @returns + */ +module.exports = async function () { + await logout.call(this) + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/authorize-app-login.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/authorize-app-login.js index 8f8a167b..c6861381 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/authorize-app-login.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/authorize-app-login.js @@ -1,37 +1,37 @@ -const { - isAuthorizeApproved -} = require('./utils') -const { - dbCmd, - userCollection -} = require('../../common/constants') - -/** - * 授权用户登录应用 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#authorize-app-login - * @param {Object} params - * @param {String} params.uid 用户id - * @param {String} params.appId 授权的应用的AppId - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - uid: 'string', - appId: 'string' - } - this.middleware.validate(params, schema) - const { - uid, - appId - } = params - await isAuthorizeApproved({ - uid, - appIdList: [appId] - }) - await userCollection.doc(uid).update({ - dcloud_appid: dbCmd.push(appId) - }) - return { - errCode: 0 - } -} +const { + isAuthorizeApproved +} = require('./utils') +const { + dbCmd, + userCollection +} = require('../../common/constants') + +/** + * 授权用户登录应用 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#authorize-app-login + * @param {Object} params + * @param {String} params.uid 用户id + * @param {String} params.appId 授权的应用的AppId + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + uid: 'string', + appId: 'string' + } + this.middleware.validate(params, schema) + const { + uid, + appId + } = params + await isAuthorizeApproved({ + uid, + appIdList: [appId] + }) + await userCollection.doc(uid).update({ + dcloud_appid: dbCmd.push(appId) + }) + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/index.js index ce9cc7b0..ee4dd44b 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/index.js @@ -1,5 +1,5 @@ -module.exports = { - authorizeAppLogin: require('./authorize-app-login'), - removeAuthorizedApp: require('./remove-authorized-app'), - setAuthorizedApp: require('./set-authorized-app') -} +module.exports = { + authorizeAppLogin: require('./authorize-app-login'), + removeAuthorizedApp: require('./remove-authorized-app'), + setAuthorizedApp: require('./set-authorized-app') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/remove-authorized-app.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/remove-authorized-app.js index df82184f..4fa69dc6 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/remove-authorized-app.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/remove-authorized-app.js @@ -1,30 +1,30 @@ -const { - dbCmd, - userCollection -} = require('../../common/constants') - -/** - * 移除用户登录授权 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#remove-authorized-app - * @param {Object} params - * @param {String} params.uid 用户id - * @param {String} params.appId 取消授权的应用的AppId - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - uid: 'string', - appId: 'string' - } - this.middleware.validate(params, schema) - const { - uid, - appId - } = params - await userCollection.doc(uid).update({ - dcloud_appid: dbCmd.pull(appId) - }) - return { - errCode: 0 - } -} +const { + dbCmd, + userCollection +} = require('../../common/constants') + +/** + * 移除用户登录授权 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#remove-authorized-app + * @param {Object} params + * @param {String} params.uid 用户id + * @param {String} params.appId 取消授权的应用的AppId + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + uid: 'string', + appId: 'string' + } + this.middleware.validate(params, schema) + const { + uid, + appId + } = params + await userCollection.doc(uid).update({ + dcloud_appid: dbCmd.pull(appId) + }) + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/set-authorized-app.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/set-authorized-app.js index a438ef99..774ececf 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/set-authorized-app.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/set-authorized-app.js @@ -1,36 +1,36 @@ -const { - isAuthorizeApproved -} = require('./utils') -const { - userCollection -} = require('../../common/constants') - -/** - * 设置用户允许登录的应用列表 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-authorized-app - * @param {Object} params - * @param {String} params.uid 用户id - * @param {Array} params.appIdList 允许登录的应用AppId列表 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - uid: 'string', - appIdList: 'array' - } - this.middleware.validate(params, schema) - const { - uid, - appIdList - } = params - await isAuthorizeApproved({ - uid, - appIdList - }) - await userCollection.doc(uid).update({ - dcloud_appid: appIdList - }) - return { - errCode: 0 - } -} +const { + isAuthorizeApproved +} = require('./utils') +const { + userCollection +} = require('../../common/constants') + +/** + * 设置用户允许登录的应用列表 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-authorized-app + * @param {Object} params + * @param {String} params.uid 用户id + * @param {Array} params.appIdList 允许登录的应用AppId列表 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + uid: 'string', + appIdList: 'array' + } + this.middleware.validate(params, schema) + const { + uid, + appIdList + } = params + await isAuthorizeApproved({ + uid, + appIdList + }) + await userCollection.doc(uid).update({ + dcloud_appid: appIdList + }) + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/utils.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/utils.js index 0c0eb859..364304d8 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/utils.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/utils.js @@ -1,36 +1,36 @@ -const { - userCollection -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') -const { - findUser -} = require('../../lib/utils/account') - -async function isAuthorizeApproved ({ - uid, - appIdList -} = {}) { - const getUserRes = await userCollection.doc(uid).get() - const userRecord = getUserRes.data[0] - if (!userRecord) { - throw { - errCode: ERROR.ACCOUNT_NOT_EXISTS - } - } - const userMatched = await findUser({ - userQuery: userRecord, - authorizedApp: appIdList - }) - - if (userMatched.some(item => item._id !== uid)) { - throw { - errCode: ERROR.ACCOUNT_CONFLICT - } - } -} - -module.exports = { - isAuthorizeApproved -} +const { + userCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + findUser +} = require('../../lib/utils/account') + +async function isAuthorizeApproved ({ + uid, + appIdList +} = {}) { + const getUserRes = await userCollection.doc(uid).get() + const userRecord = getUserRes.data[0] + if (!userRecord) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + const userMatched = await findUser({ + userQuery: userRecord, + authorizedApp: appIdList + }) + + if (userMatched.some(item => item._id !== uid)) { + throw { + errCode: ERROR.ACCOUNT_CONFLICT + } + } +} + +module.exports = { + isAuthorizeApproved +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/index.js index 64ff603c..319210fa 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/index.js @@ -1,5 +1,5 @@ -module.exports = { - registerUser: require('./register-user'), - registerAdmin: require('./register-admin'), - registerUserByEmail: require('./register-user-by-email') -} +module.exports = { + registerUser: require('./register-user'), + registerAdmin: require('./register-admin'), + registerUserByEmail: require('./register-user-by-email') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-admin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-admin.js index d9b8f330..21ca0913 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-admin.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-admin.js @@ -1,62 +1,72 @@ -const { - userCollection -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') -const { - preRegisterWithPassword, - postRegister -} = require('../../lib/utils/register') - -/** - * 注册管理员 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#register-admin - * @param {Object} params - * @param {String} params.username 用户名 - * @param {String} params.password 密码 - * @param {String} params.nickname 昵称 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - username: 'username', - password: 'password', - nickname: { - type: 'nickname', - required: false - } - } - this.middleware.validate(params, schema) - const { - username, - password, - nickname - } = params - const getAdminRes = await userCollection.where({ - role: 'admin' - }).limit(1).get() - if (getAdminRes.data.length > 0) { - return { - errCode: ERROR.ADMIN_EXISTS, - errMsg: this.t('uni-id-admin-exists') - } - } - const { - user, - extraData - } = await preRegisterWithPassword.call(this, { - user: { - username - }, - password - }) - return postRegister.call(this, { - user, - extraData: { - ...extraData, - nickname, - role: ['admin'] - } - }) -} +const { + userCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + preRegisterWithPassword, + postRegister +} = require('../../lib/utils/register') + +/** + * 注册管理员 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#register-admin + * @param {Object} params + * @param {String} params.username 用户名 + * @param {String} params.password 密码 + * @param {String} params.nickname 昵称 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + username: 'username', + password: 'password', + nickname: { + type: 'nickname', + required: false + } + } + this.middleware.validate(params, schema) + const { + username, + password, + nickname + } = params + const getAdminRes = await userCollection.where({ + role: 'admin' + }).limit(1).get() + if (getAdminRes.data.length > 0) { + const [admin] = getAdminRes.data + const appId = this.getClientInfo().appId + + if (!admin.dcloud_appid || (admin.dcloud_appid && admin.dcloud_appid.includes(appId))) { + return { + errCode: ERROR.ADMIN_EXISTS, + errMsg: this.t('uni-id-admin-exists') + } + } else { + return { + errCode: ERROR.ADMIN_EXISTS, + errMsg: this.t('uni-id-admin-exist-in-other-apps') + } + } + } + const { + user, + extraData + } = await preRegisterWithPassword.call(this, { + user: { + username + }, + password + }) + return postRegister.call(this, { + user, + extraData: { + ...extraData, + nickname, + role: ['admin'] + } + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user-by-email.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user-by-email.js index b52c1d25..f5a54c53 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user-by-email.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user-by-email.js @@ -1,87 +1,87 @@ -const { - postRegister, - preRegisterWithPassword -} = require('../../lib/utils/register') -const { - verifyCaptcha -} = require('../../lib/utils/captcha') -const { - CAPTCHA_SCENE, - EMAIL_SCENE, - LOG_TYPE -} = require('../../common/constants') -const { - verifyEmailCode -} = require('../../lib/utils/verify-code') - -/** - * 通过邮箱+验证码注册普通用户 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#register-user-by-email - * @param {Object} params - * @param {String} params.email 邮箱 - * @param {String} params.password 密码 - * @param {String} params.nickname 昵称 - * @param {String} params.code 邮箱验证码 - * @param {String} params.inviteCode 邀请码 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - email: 'email', - password: 'password', - nickname: { - required: false, - type: 'nickname' - }, - code: 'string', - inviteCode: { - required: false, - type: 'string' - } - } - this.middleware.validate(params, schema) - const { - email, - password, - nickname, - code, - inviteCode - } = params - - try { - // 验证邮箱验证码,验证不通过时写入失败日志 - await verifyEmailCode({ - email, - code, - scene: EMAIL_SCENE.REGISTER - }) - } catch (error) { - await this.middleware.uniIdLog({ - data: { - email - }, - type: LOG_TYPE.REGISTER, - success: false - }) - throw error - } - - const { - user, - extraData - } = await preRegisterWithPassword.call(this, { - user: { - email - }, - password - }) - return postRegister.call(this, { - user, - extraData: { - ...extraData, - nickname, - email_confirmed: 1 - }, - inviteCode - }) -} +const { + postRegister, + preRegisterWithPassword +} = require('../../lib/utils/register') +const { + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + CAPTCHA_SCENE, + EMAIL_SCENE, + LOG_TYPE +} = require('../../common/constants') +const { + verifyEmailCode +} = require('../../lib/utils/verify-code') + +/** + * 通过邮箱+验证码注册普通用户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#register-user-by-email + * @param {Object} params + * @param {String} params.email 邮箱 + * @param {String} params.password 密码 + * @param {String} params.nickname 昵称 + * @param {String} params.code 邮箱验证码 + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + email: 'email', + password: 'password', + nickname: { + required: false, + type: 'nickname' + }, + code: 'string', + inviteCode: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + const { + email, + password, + nickname, + code, + inviteCode + } = params + + try { + // 验证邮箱验证码,验证不通过时写入失败日志 + await verifyEmailCode({ + email, + code, + scene: EMAIL_SCENE.REGISTER + }) + } catch (error) { + await this.middleware.uniIdLog({ + data: { + email + }, + type: LOG_TYPE.REGISTER, + success: false + }) + throw error + } + + const { + user, + extraData + } = await preRegisterWithPassword.call(this, { + user: { + email + }, + password + }) + return postRegister.call(this, { + user, + extraData: { + ...extraData, + nickname, + email_confirmed: 1 + }, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-alipay.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-alipay.js index 7c0c399b..76e12477 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-alipay.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-alipay.js @@ -1,63 +1,63 @@ -const { - preBind, - postBind -} = require('../../lib/utils/relate') -const { - LOG_TYPE -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') -const { - initAlipay -} = require('../../lib/third-party/index') - -/** - * 绑定支付宝账号 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-alipay - * @param {Object} params - * @param {String} params.code 支付宝小程序登录返回的code参数 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - code: 'string' - } - this.middleware.validate(params, schema) - const uid = this.authInfo.uid - const { - code - } = params - const alipayApi = initAlipay.call(this) - let getAlipayAccountResult - try { - getAlipayAccountResult = await alipayApi().code2Session(code) - } catch (error) { - await this.middleware.uniIdLog({ - success: false, - type: LOG_TYPE.BIND_ALIPAY - }) - throw { - errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED - } - } - - const { - openid - } = getAlipayAccountResult - - const bindAccount = { - apple_openid: openid - } - await preBind.call(this, { - uid, - bindAccount, - logType: LOG_TYPE.BIND_APPLE - }) - return postBind.call(this, { - uid, - bindAccount, - extraData: {}, - logType: LOG_TYPE.BIND_APPLE - }) -} +const { + preBind, + postBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + initAlipay +} = require('../../lib/third-party/index') + +/** + * 绑定支付宝账号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-alipay + * @param {Object} params + * @param {String} params.code 支付宝小程序登录返回的code参数 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + code: 'string' + } + this.middleware.validate(params, schema) + const uid = this.authInfo.uid + const { + code + } = params + const alipayApi = initAlipay.call(this) + let getAlipayAccountResult + try { + getAlipayAccountResult = await alipayApi().code2Session(code) + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.BIND_ALIPAY + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + + const { + openid + } = getAlipayAccountResult + + const bindAccount = { + ali_openid: openid + } + await preBind.call(this, { + uid, + bindAccount, + logType: LOG_TYPE.BIND_APPLE + }) + return postBind.call(this, { + uid, + bindAccount, + extraData: {}, + logType: LOG_TYPE.BIND_APPLE + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-apple.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-apple.js index eb87f8b7..b87ac804 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-apple.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-apple.js @@ -1,62 +1,62 @@ -const { - preBind, - postBind -} = require('../../lib/utils/relate') -const { - LOG_TYPE -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') -const { - initApple -} = require('../../lib/third-party/index') - -/** - * 绑定苹果账号 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-apple - * @param {Object} params - * @param {String} params.identityToken 苹果登录返回identityToken - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - identityToken: 'string' - } - this.middleware.validate(params, schema) - const uid = this.authInfo.uid - const { - identityToken - } = params - const appleApi = initApple.call(this) - let verifyResult - try { - verifyResult = await appleApi.verifyIdentityToken(identityToken) - } catch (error) { - await this.middleware.uniIdLog({ - success: false, - type: LOG_TYPE.BIND_APPLE - }) - throw { - errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED - } - } - const { - openid - } = verifyResult - - const bindAccount = { - apple_openid: openid - } - await preBind.call(this, { - uid, - bindAccount, - logType: LOG_TYPE.BIND_APPLE - }) - return postBind.call(this, { - uid, - bindAccount, - extraData: {}, - logType: LOG_TYPE.BIND_APPLE - }) -} +const { + preBind, + postBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + initApple +} = require('../../lib/third-party/index') + +/** + * 绑定苹果账号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-apple + * @param {Object} params + * @param {String} params.identityToken 苹果登录返回identityToken + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + identityToken: 'string' + } + this.middleware.validate(params, schema) + const uid = this.authInfo.uid + const { + identityToken + } = params + const appleApi = initApple.call(this) + let verifyResult + try { + verifyResult = await appleApi.verifyIdentityToken(identityToken) + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.BIND_APPLE + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + const { + openid + } = verifyResult + + const bindAccount = { + apple_openid: openid + } + await preBind.call(this, { + uid, + bindAccount, + logType: LOG_TYPE.BIND_APPLE + }) + return postBind.call(this, { + uid, + bindAccount, + extraData: {}, + logType: LOG_TYPE.BIND_APPLE + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-mp-weixin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-mp-weixin.js index 5da72590..2e9a9915 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-mp-weixin.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-mp-weixin.js @@ -7,8 +7,10 @@ const { } = require('../../common/constants') const { decryptWeixinData, - getWeixinCache + getWeixinCache, getWeixinAccessToken } = require('../../lib/utils/weixin') +const { initWeixin } = require('../../lib/third-party') +const { ERROR } = require('../../common/error') /** * 通过微信绑定手机号 @@ -16,6 +18,7 @@ const { * @param {Object} params * @param {String} params.encryptedData 微信获取手机号返回的加密信息 * @param {String} params.iv 微信获取手机号返回的初始向量 + * @param {String} params.code 微信获取手机号返回的code * @returns */ module.exports = async function (params = {}) { @@ -26,30 +29,58 @@ module.exports = async function (params = {}) { * 因此此接口不应直接使用客户端login获取的code,只能使用缓存的sessionKey */ const schema = { - encryptedData: 'string', - iv: 'string' + encryptedData: { + required: false, + type: 'string' + }, + iv: { + required: false, + type: 'string' + }, + code: { + required: false, + type: 'string' + } } const { encryptedData, - iv + iv, + code } = params this.middleware.validate(params, schema) + + if ((!encryptedData && !iv) && !code) { + return { + errCode: ERROR.INVALID_PARAM + } + } + const uid = this.authInfo.uid - const sessionKey = await getWeixinCache.call(this, { - uid, - key: 'session_key' - }) - if (!sessionKey) { - throw new Error('Session key not found') + let mobile + if (code) { + // 区分客户端类型 小程序还是App + const accessToken = await getWeixinAccessToken.call(this) + const weixinApi = initWeixin.call(this) + const res = await weixinApi.getPhoneNumber(accessToken, code) + + mobile = res.purePhoneNumber + } else { + const sessionKey = await getWeixinCache.call(this, { + uid, + key: 'session_key' + }) + if (!sessionKey) { + throw new Error('Session key not found') + } + const res = decryptWeixinData.call(this, { + encryptedData, + sessionKey, + iv + }) + + mobile = res.purePhoneNumber } - const { - purePhoneNumber: mobile - } = decryptWeixinData.call(this, { - encryptedData, - sessionKey, - iv - }) const bindAccount = { mobile diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-univerify.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-univerify.js index 2970c61c..b38d1bc8 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-univerify.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-univerify.js @@ -1,70 +1,70 @@ -const { - getPhoneNumber -} = require('../../lib/utils/univerify') -const { - LOG_TYPE -} = require('../../common/constants') -const { - preBind, - postBind -} = require('../../lib/utils/relate') - -/** - * 通过一键登录绑定手机号 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-univerify - * @param {Object} params - * @param {String} params.openid APP端一键登录返回的openid - * @param {String} params.access_token APP端一键登录返回的access_token - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - openid: 'string', - access_token: 'string' - } - const { - openid, - // eslint-disable-next-line camelcase - access_token - } = params - this.middleware.validate(params, schema) - const uid = this.authInfo.uid - let mobile - try { - const phoneInfo = await getPhoneNumber.call(this, { - // eslint-disable-next-line camelcase - access_token, - openid - }) - mobile = phoneInfo.phoneNumber - } catch (error) { - await this.middleware.uniIdLog({ - success: false, - data: { - user_id: uid - }, - type: LOG_TYPE.BIND_MOBILE - }) - throw error - } - - const bindAccount = { - mobile - } - await preBind.call(this, { - uid, - bindAccount, - logType: LOG_TYPE.BIND_MOBILE - }) - await postBind.call(this, { - uid, - bindAccount, - extraData: { - mobile_confirmed: 1 - }, - logType: LOG_TYPE.BIND_MOBILE - }) - return { - errCode: 0 - } -} +const { + getPhoneNumber +} = require('../../lib/utils/univerify') +const { + LOG_TYPE +} = require('../../common/constants') +const { + preBind, + postBind +} = require('../../lib/utils/relate') + +/** + * 通过一键登录绑定手机号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-univerify + * @param {Object} params + * @param {String} params.openid APP端一键登录返回的openid + * @param {String} params.access_token APP端一键登录返回的access_token + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + openid: 'string', + access_token: 'string' + } + const { + openid, + // eslint-disable-next-line camelcase + access_token + } = params + this.middleware.validate(params, schema) + const uid = this.authInfo.uid + let mobile + try { + const phoneInfo = await getPhoneNumber.call(this, { + // eslint-disable-next-line camelcase + access_token, + openid + }) + mobile = phoneInfo.phoneNumber + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + data: { + user_id: uid + }, + type: LOG_TYPE.BIND_MOBILE + }) + throw error + } + + const bindAccount = { + mobile + } + await preBind.call(this, { + uid, + bindAccount, + logType: LOG_TYPE.BIND_MOBILE + }) + await postBind.call(this, { + uid, + bindAccount, + extraData: { + mobile_confirmed: 1 + }, + logType: LOG_TYPE.BIND_MOBILE + }) + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-qq.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-qq.js index ef801a23..370eefb9 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-qq.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-qq.js @@ -1,110 +1,110 @@ -const { - preBind, - postBind -} = require('../../lib/utils/relate') -const { - LOG_TYPE -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') -const { - initQQ -} = require('../../lib/third-party/index') -const { - generateQQCache, - getQQPlatform, - saveQQUserKey -} = require('../../lib/utils/qq') - -/** - * 绑定QQ - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-qq - * @param {Object} params - * @param {String} params.code 小程序端QQ登录返回的code - * @param {String} params.accessToken APP端QQ登录返回的accessToken - * @param {String} params.accessTokenExpired accessToken过期时间,由App端QQ登录返回的expires_in参数计算而来,单位:毫秒 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - code: { - type: 'string', - required: false - }, - accessToken: { - type: 'string', - required: false - }, - accessTokenExpired: { - type: 'number', - required: false - } - } - this.middleware.validate(params, schema) - const uid = this.authInfo.uid - const { - code, - accessToken, - accessTokenExpired - } = params - const qqPlatform = getQQPlatform.call(this) - const appId = this.getClientInfo().appId - const qqApi = initQQ.call(this) - const clientPlatform = this.clientPlatform - const apiName = clientPlatform === 'mp-qq' ? 'code2Session' : 'getOpenidByToken' - let getQQAccountResult - try { - getQQAccountResult = await qqApi[apiName]({ - code, - accessToken - }) - } catch (error) { - await this.middleware.uniIdLog({ - success: false, - type: LOG_TYPE.BIND_QQ - }) - throw { - errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED - } - } - - const { - openid, - unionid, - // 保存下面四个字段 - sessionKey // 微信小程序用户sessionKey - } = getQQAccountResult - - const bindAccount = { - qq_openid: { - [clientPlatform]: openid - }, - qq_unionid: unionid - } - await preBind.call(this, { - uid, - bindAccount, - logType: LOG_TYPE.BIND_QQ - }) - await saveQQUserKey.call(this, { - openid, - sessionKey, - accessToken, - accessTokenExpired - }) - return postBind.call(this, { - uid, - bindAccount, - extraData: { - qq_openid: { - [`${qqPlatform}_${appId}`]: openid - }, - ...generateQQCache.call(this, { - openid, - sessionKey - }) - }, - logType: LOG_TYPE.BIND_QQ - }) -} +const { + preBind, + postBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + initQQ +} = require('../../lib/third-party/index') +const { + generateQQCache, + getQQPlatform, + saveQQUserKey +} = require('../../lib/utils/qq') + +/** + * 绑定QQ + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-qq + * @param {Object} params + * @param {String} params.code 小程序端QQ登录返回的code + * @param {String} params.accessToken APP端QQ登录返回的accessToken + * @param {String} params.accessTokenExpired accessToken过期时间,由App端QQ登录返回的expires_in参数计算而来,单位:毫秒 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + code: { + type: 'string', + required: false + }, + accessToken: { + type: 'string', + required: false + }, + accessTokenExpired: { + type: 'number', + required: false + } + } + this.middleware.validate(params, schema) + const uid = this.authInfo.uid + const { + code, + accessToken, + accessTokenExpired + } = params + const qqPlatform = getQQPlatform.call(this) + const appId = this.getClientInfo().appId + const qqApi = initQQ.call(this) + const clientPlatform = this.clientPlatform + const apiName = clientPlatform === 'mp-qq' ? 'code2Session' : 'getOpenidByToken' + let getQQAccountResult + try { + getQQAccountResult = await qqApi[apiName]({ + code, + accessToken + }) + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.BIND_QQ + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + + const { + openid, + unionid, + // 保存下面四个字段 + sessionKey // 微信小程序用户sessionKey + } = getQQAccountResult + + const bindAccount = { + qq_openid: { + [clientPlatform]: openid + }, + qq_unionid: unionid + } + await preBind.call(this, { + uid, + bindAccount, + logType: LOG_TYPE.BIND_QQ + }) + await saveQQUserKey.call(this, { + openid, + sessionKey, + accessToken, + accessTokenExpired + }) + return postBind.call(this, { + uid, + bindAccount, + extraData: { + qq_openid: { + [`${qqPlatform}_${appId}`]: openid + }, + ...generateQQCache.call(this, { + openid, + sessionKey + }) + }, + logType: LOG_TYPE.BIND_QQ + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-weixin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-weixin.js index b0165077..f94f6dcd 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-weixin.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-weixin.js @@ -1,100 +1,100 @@ -const { - preBind, - postBind -} = require('../../lib/utils/relate') -const { - LOG_TYPE -} = require('../../common/constants') -const { - generateWeixinCache, - saveWeixinUserKey, - getWeixinPlatform -} = require('../../lib/utils/weixin') -const { - initWeixin -} = require('../../lib/third-party/index') -const { - ERROR -} = require('../../common/error') - -/** - * 绑定微信 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-weixin - * @param {Object} params - * @param {String} params.code 微信登录返回的code - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - code: 'string' - } - this.middleware.validate(params, schema) - const uid = this.authInfo.uid - const { - code - } = params - const weixinPlatform = getWeixinPlatform.call(this) - const appId = this.getClientInfo().appId - - const weixinApi = initWeixin.call(this) - const clientPlatform = this.clientPlatform - const apiName = clientPlatform === 'mp-weixin' ? 'code2Session' : 'getOauthAccessToken' - let getWeixinAccountResult - try { - getWeixinAccountResult = await weixinApi[apiName](code) - } catch (error) { - await this.middleware.uniIdLog({ - success: false, - type: LOG_TYPE.BIND_WEIXIN - }) - throw { - errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED - } - } - - const { - openid, - unionid, - // 保存下面四个字段 - sessionKey, // 微信小程序用户sessionKey - accessToken, // App端微信用户accessToken - refreshToken, // App端微信用户refreshToken - expired: accessTokenExpired // App端微信用户accessToken过期时间 - } = getWeixinAccountResult - - const bindAccount = { - wx_openid: { - [clientPlatform]: openid - }, - wx_unionid: unionid - } - await preBind.call(this, { - uid, - bindAccount, - logType: LOG_TYPE.BIND_WEIXIN - }) - await saveWeixinUserKey.call(this, { - openid, - sessionKey, - accessToken, - refreshToken, - accessTokenExpired - }) - return postBind.call(this, { - uid, - bindAccount, - extraData: { - wx_openid: { - [`${weixinPlatform}_${appId}`]: openid - }, - ...generateWeixinCache.call(this, { - openid, - sessionKey, // 微信小程序用户sessionKey - accessToken, // App端微信用户accessToken - refreshToken, // App端微信用户refreshToken - accessTokenExpired // App端微信用户accessToken过期时间 - }) - }, - logType: LOG_TYPE.BIND_WEIXIN - }) -} +const { + preBind, + postBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE +} = require('../../common/constants') +const { + generateWeixinCache, + saveWeixinUserKey, + getWeixinPlatform +} = require('../../lib/utils/weixin') +const { + initWeixin +} = require('../../lib/third-party/index') +const { + ERROR +} = require('../../common/error') + +/** + * 绑定微信 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-weixin + * @param {Object} params + * @param {String} params.code 微信登录返回的code + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + code: 'string' + } + this.middleware.validate(params, schema) + const uid = this.authInfo.uid + const { + code + } = params + const weixinPlatform = getWeixinPlatform.call(this) + const appId = this.getClientInfo().appId + + const weixinApi = initWeixin.call(this) + const clientPlatform = this.clientPlatform + const apiName = clientPlatform === 'mp-weixin' ? 'code2Session' : 'getOauthAccessToken' + let getWeixinAccountResult + try { + getWeixinAccountResult = await weixinApi[apiName](code) + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.BIND_WEIXIN + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + + const { + openid, + unionid, + // 保存下面四个字段 + sessionKey, // 微信小程序用户sessionKey + accessToken, // App端微信用户accessToken + refreshToken, // App端微信用户refreshToken + expired: accessTokenExpired // App端微信用户accessToken过期时间 + } = getWeixinAccountResult + + const bindAccount = { + wx_openid: { + [clientPlatform]: openid + }, + wx_unionid: unionid + } + await preBind.call(this, { + uid, + bindAccount, + logType: LOG_TYPE.BIND_WEIXIN + }) + await saveWeixinUserKey.call(this, { + openid, + sessionKey, + accessToken, + refreshToken, + accessTokenExpired + }) + return postBind.call(this, { + uid, + bindAccount, + extraData: { + wx_openid: { + [`${weixinPlatform}_${appId}`]: openid + }, + ...generateWeixinCache.call(this, { + openid, + sessionKey, // 微信小程序用户sessionKey + accessToken, // App端微信用户accessToken + refreshToken, // App端微信用户refreshToken + accessTokenExpired // App端微信用户accessToken过期时间 + }) + }, + logType: LOG_TYPE.BIND_WEIXIN + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/index.js index 53527920..a587e76f 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/index.js @@ -1,9 +1,13 @@ -module.exports = { - bindMobileBySms: require('./bind-mobile-by-sms'), - bindMobileByUniverify: require('./bind-mobile-by-univerify'), - bindMobileByMpWeixin: require('./bind-mobile-by-mp-weixin'), - bindAlipay: require('./bind-alipay'), - bindApple: require('./bind-apple'), - bindQQ: require('./bind-qq'), - bindWeixin: require('./bind-weixin') -} +module.exports = { + bindMobileBySms: require('./bind-mobile-by-sms'), + bindMobileByUniverify: require('./bind-mobile-by-univerify'), + bindMobileByMpWeixin: require('./bind-mobile-by-mp-weixin'), + bindAlipay: require('./bind-alipay'), + bindApple: require('./bind-apple'), + bindQQ: require('./bind-qq'), + bindWeixin: require('./bind-weixin'), + unbindWeixin: require('./unbind-weixin'), + unbindAlipay: require('./unbind-alipay'), + unbindQQ: require('./unbind-qq'), + unbindApple: require('./unbind-apple') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-alipay.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-alipay.js new file mode 100644 index 00000000..db7b1a64 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-alipay.js @@ -0,0 +1,32 @@ +const { + preUnBind, + postUnBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE, dbCmd +} = require('../../common/constants') + +/** + * 解绑支付宝 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-alipay + * @returns + */ +module.exports = async function () { + const { uid } = this.authInfo + + await preUnBind.call(this, { + uid, + unBindAccount: { + ali_openid: dbCmd.exists(true) + }, + logType: LOG_TYPE.UNBIND_ALIPAY + }) + + return await postUnBind.call(this, { + uid, + unBindAccount: { + ali_openid: dbCmd.remove() + }, + logType: LOG_TYPE.UNBIND_ALIPAY + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-apple.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-apple.js new file mode 100644 index 00000000..c966e3f6 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-apple.js @@ -0,0 +1,32 @@ +const { + preUnBind, + postUnBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE, dbCmd +} = require('../../common/constants') + +/** + * 解绑apple + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-apple + * @returns + */ +module.exports = async function () { + const { uid } = this.authInfo + + await preUnBind.call(this, { + uid, + unBindAccount: { + apple_openid: dbCmd.exists(true) + }, + logType: LOG_TYPE.UNBIND_APPLE + }) + + return await postUnBind.call(this, { + uid, + unBindAccount: { + apple_openid: dbCmd.remove() + }, + logType: LOG_TYPE.UNBIND_APPLE + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-qq.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-qq.js new file mode 100644 index 00000000..372a4f07 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-qq.js @@ -0,0 +1,46 @@ +const { + preUnBind, + postUnBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE, dbCmd +} = require('../../common/constants') +const { + getQQPlatform +} = require('../../lib/utils/qq') + +/** + * 解绑QQ + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-qq + * @returns + */ +module.exports = async function () { + const { uid } = this.authInfo + const { appId } = this.getClientInfo() + const qqPlatform = getQQPlatform.call(this) + + await preUnBind.call(this, { + uid, + unBindAccount: { + qq_openid: dbCmd.or([ + { + [qqPlatform]: dbCmd.exists(true) + }, + { + [`${qqPlatform}_${appId}`]: dbCmd.exists(true) + } + ]), + qq_unionid: dbCmd.exists(true) + }, + logType: LOG_TYPE.UNBIND_QQ + }) + + return await postUnBind.call(this, { + uid, + unBindAccount: { + qq_openid: dbCmd.remove(), + qq_unionid: dbCmd.remove() + }, + logType: LOG_TYPE.UNBIND_QQ + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-weixin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-weixin.js new file mode 100644 index 00000000..9174bef4 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-weixin.js @@ -0,0 +1,40 @@ +const { + preUnBind, + postUnBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE, dbCmd +} = require('../../common/constants') +const { + getWeixinPlatform +} = require('../../lib/utils/weixin') + +/** + * 解绑微信 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-weixin + * @returns + */ +module.exports = async function () { + const { uid } = this.authInfo + const weixinPlatform = getWeixinPlatform.call(this) + + await preUnBind.call(this, { + uid, + unBindAccount: { + wx_openid: { + [weixinPlatform]: dbCmd.exists(true) + }, + wx_unionid: dbCmd.exists(true) + }, + logType: LOG_TYPE.UNBIND_WEIXIN + }) + + return await postUnBind.call(this, { + uid, + unBindAccount: { + wx_openid: dbCmd.remove(), + wx_unionid: dbCmd.remove() + }, + logType: LOG_TYPE.UNBIND_WEIXIN + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/index.js index 11729f6b..de12366f 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/index.js @@ -1,4 +1,4 @@ -module.exports = { - refreshToken: require('./refresh-token'), - setPushCid: require('./set-push-cid') -} +module.exports = { + refreshToken: require('./refresh-token'), + setPushCid: require('./set-push-cid') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/refresh-token.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/refresh-token.js index 0c1837e6..3d50dbde 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/refresh-token.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/refresh-token.js @@ -1,19 +1,19 @@ -/** - * 刷新token - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#refresh-token - */ -module.exports = async function () { - const { - token, - tokenExpired - } = await this.uniIdCommon.refreshToken({ - token: this.getUniIdToken() - }) - return { - errCode: 0, - newToken: { - token, - tokenExpired - } - } -} +/** + * 刷新token + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#refresh-token + */ +module.exports = async function () { + const { + token, + tokenExpired + } = await this.uniIdCommon.refreshToken({ + token: this.getUniIdToken() + }) + return { + errCode: 0, + newToken: { + token, + tokenExpired + } + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/set-push-cid.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/set-push-cid.js index 68c18c62..fbf424b2 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/set-push-cid.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/set-push-cid.js @@ -1,141 +1,141 @@ -const { - deviceCollection -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') - -async function setOpendbDevice ({ - pushClientId -} = {}) { - // 仅新增,如果存在进行更新操作 - const { - appId, - deviceId, - deviceBrand, - deviceModel, - osName, - osVersion, - osLanguage, - osTheme, - devicePixelRatio, - windowWidth, - windowHeight, - screenWidth, - screenHeight, - romName, - romVersion - } = this.getClientInfo() - const platform = this.clientPlatform - const now = Date.now() - - const db = uniCloud.database() - const opendbDeviceCollection = db.collection('opendb-device') - const getDeviceRes = await opendbDeviceCollection.where({ - device_id: deviceId - }).get() - const data = { - appid: appId, - device_id: deviceId, - vendor: deviceBrand, - model: deviceModel, - uni_platform: platform, - os_name: osName, - os_version: osVersion, - os_language: osLanguage, - os_theme: osTheme, - pixel_ratio: devicePixelRatio, - window_width: windowWidth, - window_height: windowHeight, - screen_width: screenWidth, - screen_height: screenHeight, - rom_name: romName, - rom_version: romVersion, - last_update_date: now, - push_clientid: pushClientId - } - if (getDeviceRes.data.length > 0) { - await opendbDeviceCollection.where({ - device_id: deviceId - }).update(data) - return - } - data.create_date = now - await opendbDeviceCollection.add(data) -} - -/** - * 更新device表的push_clien_id - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-push-cid - * @param {object} params - * @param {string} params.pushClientId 客户端pushClientId - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - pushClientId: 'string' - } - this.middleware.validate(params, schema) - const { - deviceId, - appId, - osName - } = this.getClientInfo() - let platform = this.clientPlatform - if (platform === 'app') { - platform += osName - } - - const { - uid, - exp - } = this.authInfo - const { pushClientId } = params - const tokenExpired = exp * 1000 - const getDeviceRes = await deviceCollection.where({ - device_id: deviceId - }).get() - console.log(getDeviceRes) - if (getDeviceRes.data.length > 1) { - return { - errCode: ERROR.SYSTEM_ERROR - } - } - const deviceRecord = getDeviceRes.data[0] - await setOpendbDevice.call(this, { - pushClientId - }) - if (!deviceRecord) { - await deviceCollection.add({ - user_id: uid, - device_id: deviceId, - token_expired: tokenExpired, - push_clientid: pushClientId, - appid: appId - }) - return { - errCode: 0 - } - } - // 同一用户允许更新token_expired,不同用户在token_expired小于Date.now()时允许更新。搭配逻辑:用户退出登录时将token_expired置0 - if ( - deviceRecord.user_id === uid || - (deviceRecord.token_expired < Date.now()) - ) { - await deviceCollection.where({ - device_id: deviceId - }).update({ - user_id: uid, - token_expired: tokenExpired, - push_clientid: pushClientId, - appid: appId - }) - return { - errCode: 0 - } - } - - return { - errCode: ERROR.SYSTEM_ERROR - } -} +const { + deviceCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +async function setOpendbDevice ({ + pushClientId +} = {}) { + // 仅新增,如果存在进行更新操作 + const { + appId, + deviceId, + deviceBrand, + deviceModel, + osName, + osVersion, + osLanguage, + osTheme, + devicePixelRatio, + windowWidth, + windowHeight, + screenWidth, + screenHeight, + romName, + romVersion + } = this.getClientInfo() + const platform = this.clientPlatform + const now = Date.now() + + const db = uniCloud.database() + const opendbDeviceCollection = db.collection('opendb-device') + const getDeviceRes = await opendbDeviceCollection.where({ + device_id: deviceId + }).get() + const data = { + appid: appId, + device_id: deviceId, + vendor: deviceBrand, + model: deviceModel, + uni_platform: platform, + os_name: osName, + os_version: osVersion, + os_language: osLanguage, + os_theme: osTheme, + pixel_ratio: devicePixelRatio, + window_width: windowWidth, + window_height: windowHeight, + screen_width: screenWidth, + screen_height: screenHeight, + rom_name: romName, + rom_version: romVersion, + last_update_date: now, + push_clientid: pushClientId + } + if (getDeviceRes.data.length > 0) { + await opendbDeviceCollection.where({ + device_id: deviceId + }).update(data) + return + } + data.create_date = now + await opendbDeviceCollection.add(data) +} + +/** + * 更新device表的push_clien_id + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-push-cid + * @param {object} params + * @param {string} params.pushClientId 客户端pushClientId + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + pushClientId: 'string' + } + this.middleware.validate(params, schema) + const { + deviceId, + appId, + osName + } = this.getClientInfo() + let platform = this.clientPlatform + if (platform === 'app') { + platform += osName + } + + const { + uid, + exp + } = this.authInfo + const { pushClientId } = params + const tokenExpired = exp * 1000 + const getDeviceRes = await deviceCollection.where({ + device_id: deviceId + }).get() + console.log(getDeviceRes) + if (getDeviceRes.data.length > 1) { + return { + errCode: ERROR.SYSTEM_ERROR + } + } + const deviceRecord = getDeviceRes.data[0] + await setOpendbDevice.call(this, { + pushClientId + }) + if (!deviceRecord) { + await deviceCollection.add({ + user_id: uid, + device_id: deviceId, + token_expired: tokenExpired, + push_clientid: pushClientId, + appid: appId + }) + return { + errCode: 0 + } + } + // 同一用户允许更新token_expired,不同用户在token_expired小于Date.now()时允许更新。搭配逻辑:用户退出登录时将token_expired置0 + if ( + deviceRecord.user_id === uid || + (deviceRecord.token_expired < Date.now()) + ) { + await deviceCollection.where({ + device_id: deviceId + }).update({ + user_id: uid, + token_expired: tokenExpired, + push_clientid: pushClientId, + appid: appId + }) + return { + errCode: 0 + } + } + + return { + errCode: ERROR.SYSTEM_ERROR + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/create-captcha.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/create-captcha.js index 1d77f5e5..81b60649 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/create-captcha.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/create-captcha.js @@ -1,34 +1,34 @@ -const { - CAPTCHA_SCENE -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') - -/** - * 创建图形验证码 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#create-captcha - * @param {Object} params - * @param {String} params.scene 图形验证码使用场景 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - scene: 'string' - } - this.middleware.validate(params, schema) - - const deviceId = this.getClientInfo().deviceId - const { - scene - } = params - if (!(Object.values(CAPTCHA_SCENE).includes(scene))) { - throw { - errCode: ERROR.INVALID_PARAM - } - } - return this.uniCaptcha.create({ - deviceId, - scene - }) -} +const { + CAPTCHA_SCENE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +/** + * 创建图形验证码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#create-captcha + * @param {Object} params + * @param {String} params.scene 图形验证码使用场景 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + scene: 'string' + } + this.middleware.validate(params, schema) + + const deviceId = this.getClientInfo().deviceId + const { + scene + } = params + if (!(Object.values(CAPTCHA_SCENE).includes(scene))) { + throw { + errCode: ERROR.INVALID_PARAM + } + } + return this.uniCaptcha.create({ + deviceId, + scene + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/index.js index fba35240..297dc2bb 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/index.js @@ -1,7 +1,7 @@ -module.exports = { - createCaptcha: require('./create-captcha'), - refreshCaptcha: require('./refresh-captcha'), - sendSmsCode: require('./send-sms-code'), - sendEmailLink: require('./send-email-link'), - sendEmailCode: require('./send-email-code') -} +module.exports = { + createCaptcha: require('./create-captcha'), + refreshCaptcha: require('./refresh-captcha'), + sendSmsCode: require('./send-sms-code'), + sendEmailLink: require('./send-email-link'), + sendEmailCode: require('./send-email-code') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/refresh-captcha.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/refresh-captcha.js index e5df2462..6cbbbdde 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/refresh-captcha.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/refresh-captcha.js @@ -1,34 +1,34 @@ -const { - CAPTCHA_SCENE -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') - -/** - * 刷新图形验证码 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#refresh-captcha - * @param {Object} params - * @param {String} params.scene 图形验证码使用场景 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - scene: 'string' - } - this.middleware.validate(params, schema) - - const deviceId = this.getClientInfo().deviceId - const { - scene - } = params - if (!(Object.values(CAPTCHA_SCENE).includes(scene))) { - throw { - errCode: ERROR.INVALID_PARAM - } - } - return this.uniCaptcha.refresh({ - deviceId, - scene - }) -} +const { + CAPTCHA_SCENE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +/** + * 刷新图形验证码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#refresh-captcha + * @param {Object} params + * @param {String} params.scene 图形验证码使用场景 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + scene: 'string' + } + this.middleware.validate(params, schema) + + const deviceId = this.getClientInfo().deviceId + const { + scene + } = params + if (!(Object.values(CAPTCHA_SCENE).includes(scene))) { + throw { + errCode: ERROR.INVALID_PARAM + } + } + return this.uniCaptcha.refresh({ + deviceId, + scene + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-code.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-code.js index 5ed867c7..03af1ad7 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-code.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-code.js @@ -1,60 +1,60 @@ -const { - verifyCaptcha -} = require('../../lib/utils/captcha') -const { - EMAIL_SCENE -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') -/** - * 发送邮箱验证码,可用于登录、注册、绑定邮箱、修改密码等操作 - * @tutorial - * @param {Object} params - * @param {String} params.email 邮箱 - * @param {String} params.captcha 图形验证码 - * @param {String} params.scene 使用场景 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - email: 'email', - captcha: 'string', - scene: 'string' - } - this.middleware.validate(params, schema) - - const { - email, - captcha, - scene - } = params - - if (!(Object.values(EMAIL_SCENE).includes(scene))) { - throw { - errCode: ERROR.INVALID_PARAM - } - } - - await verifyCaptcha.call(this, { - scene: 'send-email-code', - captcha - }) - - // -- 测试代码 - require('../../lib/utils/verify-code') - .setEmailVerifyCode.call(this, { - email, - code: '123456', - expiresIn: 180, - scene - }) - return { - errCode: 'uni-id-invalid-mail-template', - errMsg: `已启动测试模式,直接使用:123456作为邮箱验证码即可。\n如果是正式项目,需自行实现发送邮件的相关功能` - } - // -- 测试代码 - - - //发送邮件--需自行实现 -} +const { + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + EMAIL_SCENE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +/** + * 发送邮箱验证码,可用于登录、注册、绑定邮箱、修改密码等操作 + * @tutorial + * @param {Object} params + * @param {String} params.email 邮箱 + * @param {String} params.captcha 图形验证码 + * @param {String} params.scene 使用场景 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + email: 'email', + captcha: 'string', + scene: 'string' + } + this.middleware.validate(params, schema) + + const { + email, + captcha, + scene + } = params + + if (!(Object.values(EMAIL_SCENE).includes(scene))) { + throw { + errCode: ERROR.INVALID_PARAM + } + } + + await verifyCaptcha.call(this, { + scene: 'send-email-code', + captcha + }) + + // -- 测试代码 + require('../../lib/utils/verify-code') + .setEmailVerifyCode.call(this, { + email, + code: '123456', + expiresIn: 180, + scene + }) + return { + errCode: 'uni-id-invalid-mail-template', + errMsg: `已启动测试模式,直接使用:123456作为邮箱验证码即可。\n如果是正式项目,需自行实现发送邮件的相关功能` + } + // -- 测试代码 + + + //发送邮件--需自行实现 +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-link.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-link.js index f643434a..d48ac068 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-link.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-link.js @@ -1,12 +1,12 @@ -/** - * 发送邮箱链接,可用于登录、注册、绑定邮箱、修改密码等操作 - * @tutorial - * @param {Object} params - * @param {String} params.email 邮箱 - * @param {String} params.scene 使用场景 - * @returns - */ -module.exports = async function (params = {}) { - // 此接口暂未实现,欢迎向我们提交pr - throw new Error('api[sendEmailLink] is not yet implemented') -} +/** + * 发送邮箱链接,可用于登录、注册、绑定邮箱、修改密码等操作 + * @tutorial + * @param {Object} params + * @param {String} params.email 邮箱 + * @param {String} params.scene 使用场景 + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[sendEmailLink] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-sms-code.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-sms-code.js index a29c1011..e589999e 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-sms-code.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-sms-code.js @@ -1,71 +1,71 @@ -const { - sendSmsCode -} = require('../../lib/utils/sms') -const { - verifyCaptcha -} = require('../../lib/utils/captcha') -const { - SMS_SCENE -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') - -/** - * 发送短信验证码 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#send-sms-code - * @param {Object} params - * @param {String} params.mobile 手机号 - * @param {String} params.captcha 图形验证码 - * @param {String} params.scene 短信验证码使用场景 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - mobile: 'mobile', - captcha: 'string', - scene: 'string' - } - this.middleware.validate(params, schema) - const { - mobile, - captcha, - scene - } = params - if (!(Object.values(SMS_SCENE).includes(scene))) { - throw { - errCode: ERROR.INVALID_PARAM - } - } - await verifyCaptcha.call(this, { - scene: 'send-sms-code', - captcha - }) - - // -- 测试代码 - const { - templateId - } = (this.config.service && - this.config.service.sms && - this.config.service.sms.scene && - this.config.service.sms.scene[scene]) || {} - if (!templateId) { - require('../../lib/utils/verify-code') - .setMobileVerifyCode.call(this, { - mobile: params.mobile, - code: '123456', - expiresIn: 180, - scene - }) - return { - errCode: 'uni-id-invalid-sms-template-id', - errMsg: `未找到scene=${scene},的短信模版templateId。\n已启动测试模式,直接使用:123456作为短信验证码即可。\n如果是正式项目,请在路径:/common/uni-config-center/uni-id/config.json中service->sms中配置密钥等信息\n更多详情:https://uniapp.dcloud.io/uniCloud/uni-id.html#config` - } - } - // -- 测试代码 - - return sendSmsCode.call(this, { - mobile, - scene - }) -} +const { + sendSmsCode +} = require('../../lib/utils/sms') +const { + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + SMS_SCENE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +/** + * 发送短信验证码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#send-sms-code + * @param {Object} params + * @param {String} params.mobile 手机号 + * @param {String} params.captcha 图形验证码 + * @param {String} params.scene 短信验证码使用场景 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + mobile: 'mobile', + captcha: 'string', + scene: 'string' + } + this.middleware.validate(params, schema) + const { + mobile, + captcha, + scene + } = params + if (!(Object.values(SMS_SCENE).includes(scene))) { + throw { + errCode: ERROR.INVALID_PARAM + } + } + await verifyCaptcha.call(this, { + scene: 'send-sms-code', + captcha + }) + + // -- 测试代码 + const { + templateId + } = (this.config.service && + this.config.service.sms && + this.config.service.sms.scene && + this.config.service.sms.scene[scene]) || {} + if (!templateId) { + require('../../lib/utils/verify-code') + .setMobileVerifyCode.call(this, { + mobile: params.mobile, + code: '123456', + expiresIn: 180, + scene + }) + return { + errCode: 'uni-id-invalid-sms-template-id', + errMsg: `未找到scene=${scene},的短信模版templateId。\n已启动测试模式,直接使用:123456作为短信验证码即可。\n如果是正式项目,请在路径:/common/uni-config-center/uni-id/config.json中service->sms中配置密钥等信息\n更多详情:https://uniapp.dcloud.io/uniCloud/uni-id.html#config` + } + } + // -- 测试代码 + + return sendSmsCode.call(this, { + mobile, + scene + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package.json index 6cdd3859..1c6e40a5 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package.json +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package.json @@ -1,17 +1,19 @@ -{ - "name": "uni-id-co", - "version": "1.0.19", - "description": "", - "main": "index.js", - "keywords": [], - "author": "DCloud", - "dependencies": { - "jsonwebtoken": "8.5.1", - "lodash.merge": "^4.6.2", - "uni-captcha": "file:../../../../uni-captcha/uniCloud/cloudfunctions/common/uni-captcha", - "uni-config-center": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center", - "uni-id-common": "file:../../../../uni-id-common/uniCloud/cloudfunctions/common/uni-id-common", - "uni-open-bridge-common": "file:../../../../uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common" - }, - "extensions": {} -} +{ + "name": "uni-id-co", + "version": "1.0.26", + "description": "", + "main": "index.js", + "keywords": [], + "author": "DCloud", + "dependencies": { + "jsonwebtoken": "8.5.1", + "lodash.merge": "^4.6.2", + "uni-captcha": "file:../../../../uni-captcha/uniCloud/cloudfunctions/common/uni-captcha", + "uni-config-center": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center", + "uni-id-common": "file:../../../../uni-id-common/uniCloud/cloudfunctions/common/uni-id-common", + "uni-open-bridge-common": "file:../../../../uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common" + }, + "extensions": { + "uni-cloud-sms": {} + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/database/opendb-device.schema.json b/uni_modules/uni-id-pages/uniCloud/database/opendb-device.schema.json index c3591cc1..163e7c14 100644 --- a/uni_modules/uni-id-pages/uniCloud/database/opendb-device.schema.json +++ b/uni_modules/uni-id-pages/uniCloud/database/opendb-device.schema.json @@ -1,142 +1,142 @@ -{ - "bsonType": "object", - "required": [], - "permission": { - "read": false, - "create": true, - "update": false, - "delete": false - }, - "properties": { - "_id": { - "description": "ID,系统自动生成" - }, - "appid": { - "bsonType": "string", - "description": "DCloud appid" - }, - "device_id": { - "bsonType": "string", - "description": "设备唯一标识" - }, - "vendor": { - "bsonType": "string", - "description": "设备厂商" - }, - "push_clientid": { - "bsonType": "string", - "description": "推送设备客户端标识" - }, - "imei": { - "bsonType": "string", - "description": "国际移动设备识别码IMEI(International Mobile Equipment Identity)" - }, - "oaid": { - "bsonType": "string", - "description": "移动智能设备标识公共服务平台提供的匿名设备标识符(OAID)" - }, - "idfa": { - "bsonType": "string", - "description": "iOS平台配置应用使用广告标识(IDFA)" - }, - "imsi": { - "bsonType": "string", - "description": "国际移动用户识别码(International Mobile Subscriber Identification Number)" - }, - "model": { - "bsonType": "string", - "description": "设备型号" - }, - "platform": { - "bsonType": "string", - "description": "平台类型" - }, - "uni_platform": { - "bsonType": "string", - "description": "uni-app 运行平台,与条件编译平台相同。" - }, - "os_name": { - "bsonType": "string", - "description": "ios|android|windows|mac|linux " - }, - "os_version": { - "bsonType": "string", - "description": "操作系统版本号 " - }, - "os_language": { - "bsonType": "string", - "description": "操作系统语言 " - }, - "os_theme": { - "bsonType": "string", - "description": "操作系统主题 light|dark" - }, - "pixel_ratio": { - "bsonType": "string", - "description": "设备像素比 " - }, - "network_model": { - "bsonType": "string", - "description": "设备网络型号wifi\/3G\/4G\/" - }, - "window_width": { - "bsonType": "string", - "description": "设备窗口宽度 " - }, - "window_height": { - "bsonType": "string", - "description": "设备窗口高度" - }, - "screen_width": { - "bsonType": "string", - "description": "设备屏幕宽度" - }, - "screen_height": { - "bsonType": "string", - "description": "设备屏幕高度" - }, - "rom_name": { - "bsonType": "string", - "description": "rom 名称" - }, - "rom_version": { - "bsonType": "string", - "description": "rom 版本" - }, - "location_latitude": { - "bsonType": "double", - "description": "纬度" - }, - "location_longitude": { - "bsonType": "double", - "description": "经度" - }, - "location_country": { - "bsonType": "string", - "description": "国家" - }, - "location_province": { - "bsonType": "string", - "description": "省份" - }, - "location_city": { - "bsonType": "string", - "description": "城市" - }, - "create_date": { - "bsonType": "timestamp", - "description": "创建时间", - "forceDefaultValue": { - "$env": "now" - } - }, - "last_update_date": { - "bsonType": "timestamp", - "description": "最后一次修改时间", - "forceDefaultValue": { - "$env": "now" - } - } - }, - "version": "0.0.1" +{ + "bsonType": "object", + "required": [], + "permission": { + "read": false, + "create": true, + "update": false, + "delete": false + }, + "properties": { + "_id": { + "description": "ID,系统自动生成" + }, + "appid": { + "bsonType": "string", + "description": "DCloud appid" + }, + "device_id": { + "bsonType": "string", + "description": "设备唯一标识" + }, + "vendor": { + "bsonType": "string", + "description": "设备厂商" + }, + "push_clientid": { + "bsonType": "string", + "description": "推送设备客户端标识" + }, + "imei": { + "bsonType": "string", + "description": "国际移动设备识别码IMEI(International Mobile Equipment Identity)" + }, + "oaid": { + "bsonType": "string", + "description": "移动智能设备标识公共服务平台提供的匿名设备标识符(OAID)" + }, + "idfa": { + "bsonType": "string", + "description": "iOS平台配置应用使用广告标识(IDFA)" + }, + "imsi": { + "bsonType": "string", + "description": "国际移动用户识别码(International Mobile Subscriber Identification Number)" + }, + "model": { + "bsonType": "string", + "description": "设备型号" + }, + "platform": { + "bsonType": "string", + "description": "平台类型" + }, + "uni_platform": { + "bsonType": "string", + "description": "uni-app 运行平台,与条件编译平台相同。" + }, + "os_name": { + "bsonType": "string", + "description": "ios|android|windows|mac|linux " + }, + "os_version": { + "bsonType": "string", + "description": "操作系统版本号 " + }, + "os_language": { + "bsonType": "string", + "description": "操作系统语言 " + }, + "os_theme": { + "bsonType": "string", + "description": "操作系统主题 light|dark" + }, + "pixel_ratio": { + "bsonType": "string", + "description": "设备像素比 " + }, + "network_model": { + "bsonType": "string", + "description": "设备网络型号wifi\/3G\/4G\/" + }, + "window_width": { + "bsonType": "string", + "description": "设备窗口宽度 " + }, + "window_height": { + "bsonType": "string", + "description": "设备窗口高度" + }, + "screen_width": { + "bsonType": "string", + "description": "设备屏幕宽度" + }, + "screen_height": { + "bsonType": "string", + "description": "设备屏幕高度" + }, + "rom_name": { + "bsonType": "string", + "description": "rom 名称" + }, + "rom_version": { + "bsonType": "string", + "description": "rom 版本" + }, + "location_latitude": { + "bsonType": "double", + "description": "纬度" + }, + "location_longitude": { + "bsonType": "double", + "description": "经度" + }, + "location_country": { + "bsonType": "string", + "description": "国家" + }, + "location_province": { + "bsonType": "string", + "description": "省份" + }, + "location_city": { + "bsonType": "string", + "description": "城市" + }, + "create_date": { + "bsonType": "timestamp", + "description": "创建时间", + "forceDefaultValue": { + "$env": "now" + } + }, + "last_update_date": { + "bsonType": "timestamp", + "description": "最后一次修改时间", + "forceDefaultValue": { + "$env": "now" + } + } + }, + "version": "0.0.1" } \ No newline at end of file diff --git a/uni_modules/uni-id-pages/uniCloud/database/uni-id-device.schema.json b/uni_modules/uni-id-pages/uniCloud/database/uni-id-device.schema.json index 4981d752..356a6e23 100644 --- a/uni_modules/uni-id-pages/uniCloud/database/uni-id-device.schema.json +++ b/uni_modules/uni-id-pages/uniCloud/database/uni-id-device.schema.json @@ -1,83 +1,83 @@ -{ - "bsonType": "object", - "required": [ - "user_id" - ], - "properties": { - "_id": { - "description": "ID,系统自动生成" - }, - "user_id": { - "bsonType": "string", - "description": "用户id,参考uni-id-users表" - }, - "ua": { - "bsonType": "string", - "description": "userAgent" - }, - "uuid": { - "bsonType": "string", - "description": "设备唯一标识(需要加密存储)" - }, - "os_name": { - "bsonType": "string", - "description": "ios|android|windows|mac|linux " - }, - "os_version": { - "bsonType": "string", - "description": "操作系统版本号 " - }, - "os_language": { - "bsonType": "string", - "description": "操作系统语言 " - }, - "os_theme": { - "bsonType": "string", - "description": "操作系统主题 light|dark" - }, - "vendor": { - "bsonType": "string", - "description": "设备厂商" - }, - "push_clientid": { - "bsonType": "string", - "description": "推送设备客户端标识" - }, - "imei": { - "bsonType": "string", - "description": "国际移动设备识别码IMEI(International Mobile Equipment Identity)" - }, - "oaid": { - "bsonType": "string", - "description": "移动智能设备标识公共服务平台提供的匿名设备标识符(OAID)" - }, - "idfa": { - "bsonType": "string", - "description": "iOS平台配置应用使用广告标识(IDFA)" - }, - "model": { - "bsonType": "string", - "description": "设备型号" - }, - "platform": { - "bsonType": "string", - "description": "平台类型" - }, - "create_date": { - "bsonType": "timestamp", - "description": "创建时间", - "forceDefaultValue": { - "$env": "now" - } - }, - "last_active_date": { - "bsonType": "timestamp", - "description": "最后登录时间" - }, - "last_active_ip": { - "bsonType": "string", - "description": "最后登录IP" - } - }, - "version": "0.0.1" +{ + "bsonType": "object", + "required": [ + "user_id" + ], + "properties": { + "_id": { + "description": "ID,系统自动生成" + }, + "user_id": { + "bsonType": "string", + "description": "用户id,参考uni-id-users表" + }, + "ua": { + "bsonType": "string", + "description": "userAgent" + }, + "uuid": { + "bsonType": "string", + "description": "设备唯一标识(需要加密存储)" + }, + "os_name": { + "bsonType": "string", + "description": "ios|android|windows|mac|linux " + }, + "os_version": { + "bsonType": "string", + "description": "操作系统版本号 " + }, + "os_language": { + "bsonType": "string", + "description": "操作系统语言 " + }, + "os_theme": { + "bsonType": "string", + "description": "操作系统主题 light|dark" + }, + "vendor": { + "bsonType": "string", + "description": "设备厂商" + }, + "push_clientid": { + "bsonType": "string", + "description": "推送设备客户端标识" + }, + "imei": { + "bsonType": "string", + "description": "国际移动设备识别码IMEI(International Mobile Equipment Identity)" + }, + "oaid": { + "bsonType": "string", + "description": "移动智能设备标识公共服务平台提供的匿名设备标识符(OAID)" + }, + "idfa": { + "bsonType": "string", + "description": "iOS平台配置应用使用广告标识(IDFA)" + }, + "model": { + "bsonType": "string", + "description": "设备型号" + }, + "platform": { + "bsonType": "string", + "description": "平台类型" + }, + "create_date": { + "bsonType": "timestamp", + "description": "创建时间", + "forceDefaultValue": { + "$env": "now" + } + }, + "last_active_date": { + "bsonType": "timestamp", + "description": "最后登录时间" + }, + "last_active_ip": { + "bsonType": "string", + "description": "最后登录IP" + } + }, + "version": "0.0.1" } \ No newline at end of file diff --git a/uni_modules/uni-id-pages/uniCloud/database/uni-id-log.schema.json b/uni_modules/uni-id-pages/uniCloud/database/uni-id-log.schema.json index ff4f7973..1b3dc611 100644 --- a/uni_modules/uni-id-pages/uniCloud/database/uni-id-log.schema.json +++ b/uni_modules/uni-id-pages/uniCloud/database/uni-id-log.schema.json @@ -1,71 +1,71 @@ -{ - "bsonType": "object", - "required": ["user_id"], - "permission": { - "read": "'READ_UNI_ID_LOG' in auth.permission" - }, - "properties": { - "_id": { - "description": "ID,系统自动生成" - }, - "create_date": { - "bsonType": "timestamp", - "description": "创建时间", - "forceDefaultValue": { - "$env": "now" - } - }, - "device_uuid": { - "bsonType": "string", - "description": "设备唯一标识" - }, - "ip": { - "bsonType": "string", - "description": "ip地址" - }, - "state": { - "bsonType": "int", - "description": "结果:0 失败、1 成功" - }, - "type": { - "bsonType": "string", - "description": "操作类型", - "enum": [ - "logout", - "login", - "register", - "reset-pwd", - "bind-mobile", - "bind-weixin", - "bind-qq", - "bind-apple", - "bind-alipay" - ] - }, - "ua": { - "bsonType": "string", - "description": "userAgent" - }, - "user_id": { - "bsonType": "string", - "foreignKey": "uni-id-users._id", - "description": "用户id,参考uni-id-users表" - }, - "username": { - "bsonType": "string", - "description": "用户名" - }, - "email": { - "bsonType": "string", - "description": "邮箱" - }, - "mobile": { - "bsonType": "string", - "description": "手机号" - }, - "appid": { - "bsonType": "string", - "description": "客户端DCloud AppId" - } - } -} +{ + "bsonType": "object", + "required": ["user_id"], + "permission": { + "read": "'READ_UNI_ID_LOG' in auth.permission" + }, + "properties": { + "_id": { + "description": "ID,系统自动生成" + }, + "create_date": { + "bsonType": "timestamp", + "description": "创建时间", + "forceDefaultValue": { + "$env": "now" + } + }, + "device_uuid": { + "bsonType": "string", + "description": "设备唯一标识" + }, + "ip": { + "bsonType": "string", + "description": "ip地址" + }, + "state": { + "bsonType": "int", + "description": "结果:0 失败、1 成功" + }, + "type": { + "bsonType": "string", + "description": "操作类型", + "enum": [ + "logout", + "login", + "register", + "reset-pwd", + "bind-mobile", + "bind-weixin", + "bind-qq", + "bind-apple", + "bind-alipay" + ] + }, + "ua": { + "bsonType": "string", + "description": "userAgent" + }, + "user_id": { + "bsonType": "string", + "foreignKey": "uni-id-users._id", + "description": "用户id,参考uni-id-users表" + }, + "username": { + "bsonType": "string", + "description": "用户名" + }, + "email": { + "bsonType": "string", + "description": "邮箱" + }, + "mobile": { + "bsonType": "string", + "description": "手机号" + }, + "appid": { + "bsonType": "string", + "description": "客户端DCloud AppId" + } + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/database/uni-id-permissions.schema.json b/uni_modules/uni-id-pages/uniCloud/database/uni-id-permissions.schema.json index 25209cba..0178d256 100644 --- a/uni_modules/uni-id-pages/uniCloud/database/uni-id-permissions.schema.json +++ b/uni_modules/uni-id-pages/uniCloud/database/uni-id-permissions.schema.json @@ -1,52 +1,52 @@ -{ - "bsonType": "object", - "required": ["permission_id", "permission_name"], - "permission": { - "read": "'READ_UNI_ID_PERMISSIONS' in auth.permission", - "create": "'CREATE_UNI_ID_PERMISSIONS' in auth.permission", - "update": "'UPDATE_UNI_ID_PERMISSIONS' in auth.permission", - "delete": "'DELETE_UNI_ID_PERMISSIONS' in auth.permission" - }, - "properties": { - "_id": { - "description": "存储文档 ID,系统自动生成" - }, - "comment": { - "bsonType": "string", - "component": { - "name": "textarea" - }, - "description": "备注", - "label": "备注", - "title": "备注", - "trim": "both" - }, - "create_date": { - "bsonType": "timestamp", - "description": "创建时间", - "forceDefaultValue": { - "$env": "now" - } - }, - "permission_id": { - "bsonType": "string", - "component": { - "name": "input" - }, - "description": "权限唯一标识,不可修改,不允许重复", - "label": "权限标识", - "title": "权限ID", - "trim": "both" - }, - "permission_name": { - "bsonType": "string", - "component": { - "name": "input" - }, - "description": "权限名称", - "label": "权限名称", - "title": "权限名称", - "trim": "both" - } - } -} +{ + "bsonType": "object", + "required": ["permission_id", "permission_name"], + "permission": { + "read": "'READ_UNI_ID_PERMISSIONS' in auth.permission", + "create": "'CREATE_UNI_ID_PERMISSIONS' in auth.permission", + "update": "'UPDATE_UNI_ID_PERMISSIONS' in auth.permission", + "delete": "'DELETE_UNI_ID_PERMISSIONS' in auth.permission" + }, + "properties": { + "_id": { + "description": "存储文档 ID,系统自动生成" + }, + "comment": { + "bsonType": "string", + "component": { + "name": "textarea" + }, + "description": "备注", + "label": "备注", + "title": "备注", + "trim": "both" + }, + "create_date": { + "bsonType": "timestamp", + "description": "创建时间", + "forceDefaultValue": { + "$env": "now" + } + }, + "permission_id": { + "bsonType": "string", + "component": { + "name": "input" + }, + "description": "权限唯一标识,不可修改,不允许重复", + "label": "权限标识", + "title": "权限ID", + "trim": "both" + }, + "permission_name": { + "bsonType": "string", + "component": { + "name": "input" + }, + "description": "权限名称", + "label": "权限名称", + "title": "权限名称", + "trim": "both" + } + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/database/uni-id-roles.schema.json b/uni_modules/uni-id-pages/uniCloud/database/uni-id-roles.schema.json index e2fe3220..b9289c81 100644 --- a/uni_modules/uni-id-pages/uniCloud/database/uni-id-roles.schema.json +++ b/uni_modules/uni-id-pages/uniCloud/database/uni-id-roles.schema.json @@ -1,50 +1,50 @@ -{ - "bsonType": "object", - "required": ["role_id", "role_name"], - "permission": { - "read": "'READ_UNI_ID_ROLES' in auth.permission", - "create": "'CREATE_UNI_ID_ROLES' in auth.permission", - "update": "'UPDATE_UNI_ID_ROLES' in auth.permission", - "delete": "'DELETE_UNI_ID_ROLES' in auth.permission" - }, - "properties": { - "_id": { - "description": "存储文档 ID,系统自动生成" - }, - "comment": { - "title": "备注", - "bsonType": "string", - "description": "备注", - "trim": "both" - }, - "create_date": { - "bsonType": "timestamp", - "description": "创建时间", - "forceDefaultValue": { - "$env": "now" - } - }, - "permission": { - "title": "权限", - "bsonType": "array", - "foreignKey": "uni-id-permissions.permission_id", - "description": "角色拥有的权限列表", - "enum": { - "collection": "uni-id-permissions", - "field": "permission_name as text, permission_id as value" - } - }, - "role_id": { - "title": "唯一ID", - "bsonType": "string", - "description": "角色唯一标识,不可修改,不允许重复", - "trim": "both" - }, - "role_name": { - "title": "名称", - "bsonType": "string", - "description": "角色名称", - "trim": "both" - } - } -} +{ + "bsonType": "object", + "required": ["role_id", "role_name"], + "permission": { + "read": "'READ_UNI_ID_ROLES' in auth.permission", + "create": "'CREATE_UNI_ID_ROLES' in auth.permission", + "update": "'UPDATE_UNI_ID_ROLES' in auth.permission", + "delete": "'DELETE_UNI_ID_ROLES' in auth.permission" + }, + "properties": { + "_id": { + "description": "存储文档 ID,系统自动生成" + }, + "comment": { + "title": "备注", + "bsonType": "string", + "description": "备注", + "trim": "both" + }, + "create_date": { + "bsonType": "timestamp", + "description": "创建时间", + "forceDefaultValue": { + "$env": "now" + } + }, + "permission": { + "title": "权限", + "bsonType": "array", + "foreignKey": "uni-id-permissions.permission_id", + "description": "角色拥有的权限列表", + "enum": { + "collection": "uni-id-permissions", + "field": "permission_name as text, permission_id as value" + } + }, + "role_id": { + "title": "唯一ID", + "bsonType": "string", + "description": "角色唯一标识,不可修改,不允许重复", + "trim": "both" + }, + "role_name": { + "title": "名称", + "bsonType": "string", + "description": "角色名称", + "trim": "both" + } + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/database/uni-id-users.schema.json b/uni_modules/uni-id-pages/uniCloud/database/uni-id-users.schema.json index 84f7230d..8231c65d 100644 --- a/uni_modules/uni-id-pages/uniCloud/database/uni-id-users.schema.json +++ b/uni_modules/uni-id-pages/uniCloud/database/uni-id-users.schema.json @@ -1,6 +1,5 @@ { "bsonType": "object", - "required": ["username", "password"], "permission": { "read": true, "create": "'CREATE_UNI_ID_USERS' in auth.permission", @@ -15,28 +14,36 @@ "bsonType": "string", "description": "支付宝平台openid", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "apple_openid": { "bsonType": "string", "description": "苹果登录openid", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "avatar": { "bsonType": "string", "description": "头像地址", "title": "头像地址", - "trim": "both" + "trim": "both", + "permission": { + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "doc._id == auth.uid || 'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" + } }, "avatar_file": { "bsonType": "file", "description": "用file类型方便使用uni-file-picker组件", - "title": "头像文件" + "title": "头像文件", + "permission": { + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "doc._id == auth.uid || 'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" + } }, "comment": { "bsonType": "string", @@ -44,8 +51,8 @@ "title": "备注", "trim": "both", "permission": { - "write": false, - "read": false + "read": "'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "dcloud_appid": { @@ -53,8 +60,8 @@ "description": "允许登录的客户端的appid列表", "foreignKey": "opendb-app-list.appid", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "department_id": { @@ -68,8 +75,8 @@ "enumType": "tree", "title": "部门", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "email": { @@ -79,8 +86,8 @@ "title": "邮箱", "trim": "both", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "email_confirmed": { @@ -98,8 +105,8 @@ ], "title": "邮箱验证状态", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "gender": { @@ -121,16 +128,16 @@ ], "title": "性别", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "invite_time": { "bsonType": "timestamp", "description": "受邀时间", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "inviter_uid": { @@ -138,24 +145,24 @@ "description": "用户全部上级邀请者", "trim": "both", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "last_login_date": { "bsonType": "timestamp", "description": "最后登录时间", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "last_login_ip": { "bsonType": "string", "description": "最后登录时 IP 地址", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "mobile": { @@ -165,8 +172,8 @@ "title": "手机号码", "trim": "both", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "mobile_confirmed": { @@ -184,49 +191,49 @@ ], "title": "手机号验证状态", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "my_invite_code": { "bsonType": "string", "description": "用户自身邀请码", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "nickname": { "bsonType": "string", "description": "用户昵称", "title": "昵称", - "trim": "both" + "trim": "both", + "permission": { + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "doc._id == auth.uid || 'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" + } }, "password": { "bsonType": "password", "description": "密码,加密存储", "title": "密码", - "trim": "both", - "permission": { - "write": false, - "read": false - } + "trim": "both" }, "password_secret_version": { "bsonType": "int", "description": "密码使用的passwordSecret版本", "title": "passwordSecret", "permission": { - "write": false, - "read": false + "read": false, + "write": false } }, "realname_auth": { "bsonType": "object", "description": "实名认证信息", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" }, "properties": { "auth_date": { @@ -291,16 +298,22 @@ "bsonType": "timestamp", "description": "注册时间", "forceDefaultValue": { - "$env": "now", - "read": "doc._id == auth.uid" + "$env": "now" + }, + "permission": { + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "register_ip": { "bsonType": "string", "description": "注册时 IP 地址", "forceDefaultValue": { - "$env": "clientIP", - "read": "doc._id == auth.uid" + "$env": "clientIP" + }, + "permission": { + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "role": { @@ -312,8 +325,8 @@ }, "foreignKey": "uni-id-roles.role_id", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" }, "title": "角色" }, @@ -321,8 +334,8 @@ "bsonType": "int", "description": "用户积分,积分变更记录可参考:uni-id-scores表定义", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "status": { @@ -330,8 +343,8 @@ "defaultValue": 0, "description": "用户状态:0 正常 1 禁用 2 审核中 3 审核拒绝", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" }, "enum": [{ "text": "正常", @@ -356,7 +369,8 @@ "bsonType": "array", "description": "用户token", "permission": { - "read": "doc._id == auth.uid" + "read": "'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "username": { @@ -365,7 +379,8 @@ "title": "用户名", "trim": "both", "permission": { - "write": false + "read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "wx_openid": { @@ -390,16 +405,16 @@ } }, "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "wx_unionid": { "bsonType": "string", "description": "微信unionid", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "qq_openid": { @@ -416,17 +431,26 @@ } }, "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" } }, "qq_unionid": { "bsonType": "string", "description": "QQ unionid", "permission": { - "write": false, - "read": "doc._id == auth.uid" + "read": "'READ_UNI_ID_USERS' in auth.permission", + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" + } + }, + "third_party": { + "bsonType": "object", + "description": "三方平台凭证", + "permission": { + "read": false, + "write": false } } - } -} + }, + "required": [] +} \ No newline at end of file -- GitLab