From bbcd1233b8c071505b072a28f46a8de11a37efdb Mon Sep 17 00:00:00 2001 From: linju Date: Sat, 14 Jan 2023 11:57:54 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0uni-id-co?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../uni-id-co/common/constants.js | 184 +-- .../cloudfunctions/uni-id-co/common/error.js | 120 +- .../uni-id-co/common/universal.js | 94 +- .../cloudfunctions/uni-id-co/common/utils.js | 428 +++--- .../uni-id-co/common/validator.js | 878 ++++++------ .../uni-id-co/config/permission.js | 162 +-- .../cloudfunctions/uni-id-co/index.obj.js | 1232 ++++++++--------- .../cloudfunctions/uni-id-co/lang/en.js | 104 +- .../cloudfunctions/uni-id-co/lang/index.js | 44 +- .../cloudfunctions/uni-id-co/lang/zh-hans.js | 104 +- .../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 | 222 +-- .../lib/third-party/weixin/normalize.js | 190 +-- .../uni-id-co/lib/third-party/weixin/utils.js | 174 +-- .../uni-id-co/lib/utils/account.js | 194 +-- .../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 | 480 +++---- .../uni-id-co/lib/utils/logout.js | 98 +- .../uni-id-co/lib/utils/password.js | 522 +++---- .../cloudfunctions/uni-id-co/lib/utils/qq.js | 304 ++-- .../uni-id-co/lib/utils/register.js | 430 +++--- .../uni-id-co/lib/utils/relate.js | 328 ++--- .../cloudfunctions/uni-id-co/lib/utils/sms.js | 162 +-- .../uni-id-co/lib/utils/unified-login.js | 212 +-- .../uni-id-co/lib/utils/univerify.js | 54 +- .../uni-id-co/lib/utils/update-user-info.js | 50 +- .../uni-id-co/lib/utils/utils.js | 34 +- .../uni-id-co/lib/utils/verify-code.js | 304 ++-- .../uni-id-co/lib/utils/weixin.js | 468 +++---- .../uni-id-co/middleware/access-control.js | 118 +- .../uni-id-co/middleware/auth.js | 34 +- .../uni-id-co/middleware/index.js | 16 +- .../uni-id-co/middleware/rbac.js | 78 +- .../uni-id-co/middleware/uni-id-log.js | 78 +- .../uni-id-co/middleware/validate.js | 14 +- .../middleware/verify-request-sign.js | 78 +- .../uni-id-co/module/account/close-account.js | 32 +- .../module/account/get-account-info.js | 138 +- .../uni-id-co/module/account/index.js | 16 +- .../module/account/reset-pwd-by-email.js | 256 ++-- .../module/account/reset-pwd-by-sms.js | 256 ++-- .../uni-id-co/module/account/set-pwd.js | 166 +-- .../uni-id-co/module/account/update-pwd.js | 138 +- .../uni-id-co/module/admin/add-user.js | 242 ++-- .../uni-id-co/module/admin/index.js | 8 +- .../uni-id-co/module/admin/update-user.js | 278 ++-- .../module/dev/get-supported-login-type.js | 142 +- .../uni-id-co/module/dev/index.js | 6 +- .../uni-id-co/module/external/index.js | 8 +- .../uni-id-co/module/external/login.js | 58 +- .../uni-id-co/module/external/register.js | 104 +- .../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 | 40 +- .../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-sms.js | 198 +-- .../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 | 212 +-- .../uni-id-co/module/login/login-by-weixin.js | 350 ++--- .../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 | 76 +- .../uni-id-co/module/register/index.js | 10 +- .../module/register/register-admin.js | 144 +- .../module/register/register-user-by-email.js | 174 +-- .../module/register/register-user.js | 136 +- .../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 | 208 +-- .../module/relate/bind-mobile-by-sms.js | 184 +-- .../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 | 26 +- .../uni-id-co/module/relate/unbind-alipay.js | 64 +- .../uni-id-co/module/relate/unbind-apple.js | 64 +- .../uni-id-co/module/relate/unbind-qq.js | 92 +- .../uni-id-co/module/relate/unbind-weixin.js | 80 +- .../uni-id-co/module/utils/index.js | 10 +- .../uni-id-co/module/utils/refresh-token.js | 38 +- .../secure-network-handshake-by-weixin.js | 146 +- .../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 | 46 +- .../database/uni-id-users.schema.json | 919 ++++++------ 119 files changed, 9189 insertions(+), 9180 deletions(-) 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 2e2c179..a23dee4 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,92 +1,92 @@ -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 openDataCollectionName = 'opendb-open-data' -const openDataCollection = db.collection(openDataCollectionName) - -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', - SET_PWD_BY_SMS: 'set-pwd-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', - SET_PWD_BY_SMS: 'set-pwd-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, - openDataCollection, - 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 openDataCollectionName = 'opendb-open-data' +const openDataCollection = db.collection(openDataCollectionName) + +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', + SET_PWD_BY_SMS: 'set-pwd-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', + SET_PWD_BY_SMS: 'set-pwd-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, + openDataCollection, + 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 2e8aca0..d026fe7 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,60 +1,60 @@ -const ERROR = { - ACCOUNT_EXISTS: 'uni-id-account-exists', - ACCOUNT_NOT_EXISTS: 'uni-id-account-not-exists', - ACCOUNT_NOT_EXISTS_IN_CURRENT_APP: 'uni-id-account-not-exists-in-current-app', - 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', - UNSUPPORTED_REQUEST: 'uni-id-unsupported-request', - ILLEGAL_REQUEST: 'uni-id-illegal-request' -} - -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_NOT_EXISTS_IN_CURRENT_APP: 'uni-id-account-not-exists-in-current-app', + 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', + UNSUPPORTED_REQUEST: 'uni-id-unsupported-request', + ILLEGAL_REQUEST: 'uni-id-illegal-request' +} + +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/universal.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/universal.js index 084d759..4bf46a0 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/universal.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/universal.js @@ -1,47 +1,47 @@ -const { ERROR } = require('./error') - -function getHttpClientInfo () { - const requestId = this.getUniCloudRequestId() - const { clientIP, userAgent, source, secretType = 'none' } = this.getClientInfo() - const { clientInfo = {} } = JSON.parse(this.getHttpInfo().body) - - return { - ...clientInfo, - clientIP, - userAgent, - source, - secretType, - requestId - } -} - -function getHttpUniIdToken () { - const { uniIdToken = '' } = JSON.parse(this.getHttpInfo().body) - - return uniIdToken -} - -function verifyHttpMethod () { - const { headers, httpMethod } = this.getHttpInfo() - - if (!/^application\/json/.test(headers['content-type']) || httpMethod.toUpperCase() !== 'POST') { - throw { - errCode: ERROR.UNSUPPORTED_REQUEST, - errMsg: 'unsupported request' - } - } -} - -function universal () { - if (this.getClientInfo().source === 'http') { - verifyHttpMethod.call(this) - this.getParams()[0] = JSON.parse(this.getHttpInfo().body).params - this.getUniversalClientInfo = getHttpClientInfo.bind(this) - this.getUniversalUniIdToken = getHttpUniIdToken.bind(this) - } else { - this.getUniversalClientInfo = this.getClientInfo - this.getUniversalUniIdToken = this.getUniIdToken - } -} - -module.exports = universal +const { ERROR } = require('./error') + +function getHttpClientInfo () { + const requestId = this.getUniCloudRequestId() + const { clientIP, userAgent, source, secretType = 'none' } = this.getClientInfo() + const { clientInfo = {} } = JSON.parse(this.getHttpInfo().body) + + return { + ...clientInfo, + clientIP, + userAgent, + source, + secretType, + requestId + } +} + +function getHttpUniIdToken () { + const { uniIdToken = '' } = JSON.parse(this.getHttpInfo().body) + + return uniIdToken +} + +function verifyHttpMethod () { + const { headers, httpMethod } = this.getHttpInfo() + + if (!/^application\/json/.test(headers['content-type']) || httpMethod.toUpperCase() !== 'POST') { + throw { + errCode: ERROR.UNSUPPORTED_REQUEST, + errMsg: 'unsupported request' + } + } +} + +function universal () { + if (this.getClientInfo().source === 'http') { + verifyHttpMethod.call(this) + this.getParams()[0] = JSON.parse(this.getHttpInfo().body).params + this.getUniversalClientInfo = getHttpClientInfo.bind(this) + this.getUniversalUniIdToken = getHttpUniIdToken.bind(this) + } else { + this.getUniversalClientInfo = this.getClientInfo + this.getUniversalUniIdToken = this.getUniIdToken + } +} + +module.exports = universal 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 94b1291..8996aa5 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,214 +1,214 @@ -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/uni-id-co目录执行 npm install 安装依赖') - throw error -} - -function isMatchUserApp (userAppList, matchAppList) { - if (userAppList === undefined || userAppList === null) { - return true - } - if (getType(userAppList) !== 'array') { - return false - } - if (userAppList.includes('*')) { - return true - } - if (getType(matchAppList) === 'string') { - matchAppList = [matchAppList] - } - return userAppList.some(item => matchAppList.includes(item)) -} - -module.exports = { - getType, - isValidString, - batchFindObjctValue, - isPlainObject, - isFn, - getDistinctArray, - getFullTimeStr, - resolveUrl, - getOffsetDate, - camel2snakeJson, - snake2camelJson, - getExtension, - getVerifyCode, - coverMobile, - getNonceStr, - isMatchUserApp -} +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/uni-id-co目录执行 npm install 安装依赖') + throw error +} + +function isMatchUserApp (userAppList, matchAppList) { + if (userAppList === undefined || userAppList === null) { + return true + } + if (getType(userAppList) !== 'array') { + return false + } + if (userAppList.includes('*')) { + return true + } + if (getType(matchAppList) === 'string') { + matchAppList = [matchAppList] + } + return userAppList.some(item => matchAppList.includes(item)) +} + +module.exports = { + getType, + isValidString, + batchFindObjctValue, + isPlainObject, + isFn, + getDistinctArray, + getFullTimeStr, + resolveUrl, + getOffsetDate, + camel2snakeJson, + snake2camelJson, + getExtension, + getVerifyCode, + coverMobile, + getNonceStr, + isMatchUserApp +} 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 5c0f372..e14600c 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,439 +1,439 @@ -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 (getType(mobile) !== 'string') { - return { - errCode - } - } - if (mobile && !/^1\d{10}$/.test(mobile)) { - return { - errCode - } - } -} - -baseValidator.email = function (email) { - const errCode = ERROR.INVALID_EMAIL - if (getType(email) !== 'string') { - return { - errCode - } - } - if (email && !/@/.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 - } - } - } -} - -function isEmpty(value) { - return value === undefined || - value === null || - (typeof value === 'string' && value.trim() === '') -} - -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 (isEmpty(value[schemaKey])) { - if (required) { - return { - errCode: ERROR.PARAM_REQUIRED, - errMsgValue: { - param: schemaKey - }, - schemaKey - } - } else { - delete value[schemaKey] - 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 (getType(mobile) !== 'string') { + return { + errCode + } + } + if (mobile && !/^1\d{10}$/.test(mobile)) { + return { + errCode + } + } +} + +baseValidator.email = function (email) { + const errCode = ERROR.INVALID_EMAIL + if (getType(email) !== 'string') { + return { + errCode + } + } + if (email && !/@/.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 + } + } + } +} + +function isEmpty(value) { + return value === undefined || + value === null || + (typeof value === 'string' && value.trim() === '') +} + +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 (isEmpty(value[schemaKey])) { + if (required) { + return { + errCode: ERROR.PARAM_REQUIRED, + errMsgValue: { + param: schemaKey + }, + schemaKey + } + } else { + //delete value[schemaKey] + 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 8e367c5..8a06222 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,81 +1,81 @@ -// 各接口权限配置,未配置接口表示允许任何用户访问(包括未登录用户) -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 - }, - setPwd: { - 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 + }, + setPwd: { + 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 7d92eda..69013a4 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 @@ -1,616 +1,616 @@ -const uniIdCommon = require('uni-id-common') -const uniCaptcha = require('uni-captcha') -const { - getType -} = require('./common/utils') -const { - checkClientInfo, - Validator -} = require('./common/validator') -const ConfigUtils = require('./lib/utils/config') -const { - isUniIdError -} = require('./common/error') -const middleware = require('./middleware/index') -const universal = require('./common/universal') - -const { - registerAdmin, - registerUser, - registerUserByEmail -} = require('./module/register/index') -const { - addUser, - updateUser -} = require('./module/admin/index') -const { - login, - loginBySms, - loginByUniverify, - loginByWeixin, - loginByAlipay, - loginByQQ, - loginByApple, - loginByWeixinMobile -} = require('./module/login/index') -const { - logout -} = require('./module/logout/index') -const { - bindMobileBySms, - bindMobileByUniverify, - bindMobileByMpWeixin, - bindAlipay, - bindApple, - bindQQ, - bindWeixin, - unbindWeixin, - unbindAlipay, - unbindQQ, - unbindApple -} = require('./module/relate/index') -const { - setPwd, - updatePwd, - resetPwdBySms, - resetPwdByEmail, - closeAccount, - getAccountInfo -} = require('./module/account/index') -const { - createCaptcha, - refreshCaptcha, - sendSmsCode, - sendEmailCode -} = require('./module/verify/index') -const { - refreshToken, - setPushCid, - secureNetworkHandshakeByWeixin -} = require('./module/utils/index') -const { - getInvitedUser, - acceptInvite -} = require('./module/fission') -const { - authorizeAppLogin, - removeAuthorizedApp, - setAuthorizedApp -} = require('./module/multi-end') -const { - getSupportedLoginType -} = require('./module/dev/index') - -const { - externalRegister, - externalLogin -} = require('./module/external') - -module.exports = { - async _before () { - // 支持 callFunction 与 URL化 - universal.call(this) - - const clientInfo = this.getUniversalClientInfo() - /** - * 检查clientInfo,无appId和uniPlatform时本云对象无法正常运行 - * 此外需要保证用到的clientInfo字段均经过类型检查 - * clientInfo由客户端上传并非完全可信,clientInfo内除clientIP、userAgent、source外均为客户端上传参数 - * 否则可能会出现一些意料外的情况 - */ - checkClientInfo(clientInfo) - let clientPlatform = clientInfo.uniPlatform - // 统一platform名称 - switch (clientPlatform) { - case 'app': - case 'app-plus': - clientPlatform = 'app' - break - case 'web': - case 'h5': - clientPlatform = 'web' - break - default: - break - } - - this.clientPlatform = clientPlatform - - // 挂载uni-id实例到this上,方便后续调用 - this.uniIdCommon = uniIdCommon.createInstance({ - clientInfo - }) - - // 包含uni-id配置合并等功能的工具集 - this.configUtils = new ConfigUtils({ - context: this - }) - this.config = this.configUtils.getPlatformConfig() - this.hooks = this.configUtils.getHooks() - - this.validator = new Validator({ - passwordStrength: this.config.passwordStrength - }) - /** - * 示例:覆盖密码验证规则 - */ - // this.validator.mixin('password', function (password) { - // if (typeof password !== 'string' || password.length < 10) { - // // 调整为密码长度不能小于10 - // return { - // errCode: ERROR.INVALID_PASSWORD - // } - // } - // }) - /** - * 示例:新增验证规则 - */ - // this.validator.mixin('timestamp', function (timestamp) { - // if (typeof timestamp !== 'number' || timestamp > Date.now()) { - // return { - // errCode: ERROR.INVALID_PARAM - // } - // } - // }) - // // 新增规则同样可以在数组验证规则中使用 - // this.validator.valdate({ - // timestamp: 123456789 - // }, { - // timestamp: 'timestamp' - // }) - // this.validator.valdate({ - // timestampList: [123456789, 123123123123] - // }, { - // timestampList: 'array' - // }) - // // 甚至更复杂的写法 - // this.validator.valdate({ - // timestamp: [123456789, 123123123123] - // }, { - // timestamp: 'timestamp|array' - // }) - - // 挂载uni-captcha到this上,方便后续调用 - this.uniCaptcha = uniCaptcha - Object.defineProperty(this, 'uniOpenBridge', { - get () { - return require('uni-open-bridge-common') - } - }) - - // 挂载中间件 - this.middleware = {} - for (const mwName in middleware) { - this.middleware[mwName] = middleware[mwName].bind(this) - } - - // 国际化 - const i18n = uniCloud.initI18n({ - locale: clientInfo.locale, - fallbackLocale: 'zh-Hans', - messages: require('./lang/index') - }) - this.t = i18n.t.bind(i18n) - - this.response = {} - - // 请求鉴权验证 - await this.middleware.verifyRequestSign() - - // 通用权限校验模块 - await this.middleware.accessControl() - }, - _after (error, result) { - if (error) { - // 处理中间件内抛出的标准响应对象 - if (error.errCode && getType(error) === 'object') { - const errCode = error.errCode - if (!isUniIdError(errCode)) { - return error - } - return { - errCode, - errMsg: error.errMsg || this.t(errCode, error.errMsgValue) - } - } - throw error - } - return Object.assign(this.response, result) - }, - /** - * 注册管理员 - * @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 - */ - registerAdmin, - /** - * 新增用户 - * @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 - */ - addUser, - /** - * 修改用户 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#update-user - * @param {Object} params - * @param {String} params.id 要更新的用户id - * @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 - */ - updateUser, - /** - * 授权用户登录应用 - * @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 - */ - authorizeAppLogin, - /** - * 移除用户登录授权 - * @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 - */ - removeAuthorizedApp, - /** - * 设置用户允许登录的应用列表 - * @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 - */ - setAuthorizedApp, - /** - * 注册普通用户 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#register-user - * @param {Object} params - * @param {String} params.username 用户名 - * @param {String} params.password 密码 - * @param {String} params.captcha 图形验证码 - * @param {String} params.nickname 昵称 - * @param {String} params.inviteCode 邀请码 - * @returns - */ - registerUser, - /** - * 通过邮箱+验证码注册用户 - * @param {Object} params - * @param {String} params.email 邮箱 - * @param {String} params.password 密码 - * @param {String} params.nickname 昵称 - * @param {String} params.code 邮箱验证码 - * @param {String} params.inviteCode 邀请码 - * @returns - */ - registerUserByEmail, - /** - * 用户名密码登录 - * @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 - */ - login, - /** - * 短信验证码登录 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-sms - * @param {Object} params - * @param {String} params.mobile 手机号 - * @param {String} params.code 短信验证码 - * @param {String} params.captcha 图形验证码 - * @param {String} params.inviteCode 邀请码 - * @returns - */ - loginBySms, - /** - * 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 - */ - loginByUniverify, - /** - * 微信登录 - * @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 - */ - loginByWeixin, - /** - * 支付宝登录 - * @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 - */ - loginByAlipay, - /** - * 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 - */ - loginByQQ, - /** - * 苹果登录 - * @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 - */ - loginByApple, - loginByWeixinMobile, - /** - * 用户退出登录 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#logout - * @returns - */ - logout, - /** - * 通过短信验证码绑定手机号 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-sms - * @param {Object} params - * @param {String} params.mobile 手机号 - * @param {String} params.code 短信验证码 - * @param {String} params.captcha 图形验证码 - * @returns - */ - bindMobileBySms, - /** - * 通过一键登录绑定手机号 - * @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 - */ - bindMobileByUniverify, - /** - * 通过微信绑定手机号 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-mp-weixin - * @param {Object} params - * @param {String} params.encryptedData 微信获取手机号返回的加密信息 - * @param {String} params.iv 微信获取手机号返回的初始向量 - * @returns - */ - bindMobileByMpWeixin, - /** - * 绑定微信 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-weixin - * @param {Object} params - * @param {String} params.code 微信登录返回的code - * @returns - */ - bindWeixin, - /** - * 绑定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 - */ - bindQQ, - /** - * 绑定支付宝账号 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-alipay - * @param {Object} params - * @param {String} params.code 支付宝小程序登录返回的code参数 - * @returns - */ - bindAlipay, - /** - * 绑定苹果账号 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-apple - * @param {Object} params - * @param {String} params.identityToken 苹果登录返回identityToken - * @returns - */ - bindApple, - /** - * 更新密码 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#update-pwd - * @param {object} params - * @param {string} params.oldPassword 旧密码 - * @param {string} params.newPassword 新密码 - * @returns {object} - */ - updatePwd, - /** - * 通过短信验证码重置密码 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#reset-pwd-by-sms - * @param {object} params - * @param {string} params.mobile 手机号 - * @param {string} params.mobile 短信验证码 - * @param {string} params.password 密码 - * @param {string} params.captcha 图形验证码 - * @returns {object} - */ - resetPwdBySms, - /** - * 通过邮箱验证码重置密码 - * @param {object} params - * @param {string} params.email 邮箱 - * @param {string} params.code 邮箱验证码 - * @param {string} params.password 密码 - * @param {string} params.captcha 图形验证码 - * @returns {object} - */ - resetPwdByEmail, - /** - * 注销账户 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#close-account - * @returns - */ - closeAccount, - /** - * 获取账户账户简略信息 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-account-info - */ - getAccountInfo, - /** - * 创建图形验证码 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#create-captcha - * @param {Object} params - * @param {String} params.scene 图形验证码使用场景 - * @returns - */ - createCaptcha, - /** - * 刷新图形验证码 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#refresh-captcha - * @param {Object} params - * @param {String} params.scene 图形验证码使用场景 - * @returns - */ - refreshCaptcha, - /** - * 发送短信验证码 - * @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 - */ - sendSmsCode, - /** - * 发送邮箱验证码 - * @tutorial 需自行实现功能 - * @param {Object} params - * @param {String} params.email 邮箱 - * @param {String} params.captcha 图形验证码 - * @param {String} params.scene 短信验证码使用场景 - * @returns - */ - sendEmailCode, - /** - * 刷新token - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#refresh-token - */ - refreshToken, - /** - * 接受邀请 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#accept-invite - * @param {Object} params - * @param {String} params.inviteCode 邀请码 - * @returns - */ - acceptInvite, - /** - * 获取受邀用户 - * @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 - */ - getInvitedUser, - /** - * 更新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 - */ - setPushCid, - /** - * 获取支持的登录方式 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-supported-login-type - * @returns - */ - 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, - /** - * 安全网络握手,目前仅处理微信小程序安全网络握手 - */ - secureNetworkHandshakeByWeixin, - /** - * 设置密码 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-pwd - * @returns - */ - setPwd, - /** - * 外部用户注册,将自身系统的用户账号导入uniId,为其创建一个对应uniId的账号(unieid),使得该账号可以使用依赖uniId的系统及功能。 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#external-register - * @returns - */ - externalRegister, - /** - * 外部用户登录,使用unieid即可登录 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#external-login - * @returns - * */ - externalLogin -} +const uniIdCommon = require('uni-id-common') +const uniCaptcha = require('uni-captcha') +const { + getType +} = require('./common/utils') +const { + checkClientInfo, + Validator +} = require('./common/validator') +const ConfigUtils = require('./lib/utils/config') +const { + isUniIdError +} = require('./common/error') +const middleware = require('./middleware/index') +const universal = require('./common/universal') + +const { + registerAdmin, + registerUser, + registerUserByEmail +} = require('./module/register/index') +const { + addUser, + updateUser +} = require('./module/admin/index') +const { + login, + loginBySms, + loginByUniverify, + loginByWeixin, + loginByAlipay, + loginByQQ, + loginByApple, + loginByWeixinMobile +} = require('./module/login/index') +const { + logout +} = require('./module/logout/index') +const { + bindMobileBySms, + bindMobileByUniverify, + bindMobileByMpWeixin, + bindAlipay, + bindApple, + bindQQ, + bindWeixin, + unbindWeixin, + unbindAlipay, + unbindQQ, + unbindApple +} = require('./module/relate/index') +const { + setPwd, + updatePwd, + resetPwdBySms, + resetPwdByEmail, + closeAccount, + getAccountInfo +} = require('./module/account/index') +const { + createCaptcha, + refreshCaptcha, + sendSmsCode, + sendEmailCode +} = require('./module/verify/index') +const { + refreshToken, + setPushCid, + secureNetworkHandshakeByWeixin +} = require('./module/utils/index') +const { + getInvitedUser, + acceptInvite +} = require('./module/fission') +const { + authorizeAppLogin, + removeAuthorizedApp, + setAuthorizedApp +} = require('./module/multi-end') +const { + getSupportedLoginType +} = require('./module/dev/index') + +const { + externalRegister, + externalLogin +} = require('./module/external') + +module.exports = { + async _before () { + // 支持 callFunction 与 URL化 + universal.call(this) + + const clientInfo = this.getUniversalClientInfo() + /** + * 检查clientInfo,无appId和uniPlatform时本云对象无法正常运行 + * 此外需要保证用到的clientInfo字段均经过类型检查 + * clientInfo由客户端上传并非完全可信,clientInfo内除clientIP、userAgent、source外均为客户端上传参数 + * 否则可能会出现一些意料外的情况 + */ + checkClientInfo(clientInfo) + let clientPlatform = clientInfo.uniPlatform + // 统一platform名称 + switch (clientPlatform) { + case 'app': + case 'app-plus': + clientPlatform = 'app' + break + case 'web': + case 'h5': + clientPlatform = 'web' + break + default: + break + } + + this.clientPlatform = clientPlatform + + // 挂载uni-id实例到this上,方便后续调用 + this.uniIdCommon = uniIdCommon.createInstance({ + clientInfo + }) + + // 包含uni-id配置合并等功能的工具集 + this.configUtils = new ConfigUtils({ + context: this + }) + this.config = this.configUtils.getPlatformConfig() + this.hooks = this.configUtils.getHooks() + + this.validator = new Validator({ + passwordStrength: this.config.passwordStrength + }) + /** + * 示例:覆盖密码验证规则 + */ + // this.validator.mixin('password', function (password) { + // if (typeof password !== 'string' || password.length < 10) { + // // 调整为密码长度不能小于10 + // return { + // errCode: ERROR.INVALID_PASSWORD + // } + // } + // }) + /** + * 示例:新增验证规则 + */ + // this.validator.mixin('timestamp', function (timestamp) { + // if (typeof timestamp !== 'number' || timestamp > Date.now()) { + // return { + // errCode: ERROR.INVALID_PARAM + // } + // } + // }) + // // 新增规则同样可以在数组验证规则中使用 + // this.validator.valdate({ + // timestamp: 123456789 + // }, { + // timestamp: 'timestamp' + // }) + // this.validator.valdate({ + // timestampList: [123456789, 123123123123] + // }, { + // timestampList: 'array' + // }) + // // 甚至更复杂的写法 + // this.validator.valdate({ + // timestamp: [123456789, 123123123123] + // }, { + // timestamp: 'timestamp|array' + // }) + + // 挂载uni-captcha到this上,方便后续调用 + this.uniCaptcha = uniCaptcha + Object.defineProperty(this, 'uniOpenBridge', { + get () { + return require('uni-open-bridge-common') + } + }) + + // 挂载中间件 + this.middleware = {} + for (const mwName in middleware) { + this.middleware[mwName] = middleware[mwName].bind(this) + } + + // 国际化 + const i18n = uniCloud.initI18n({ + locale: clientInfo.locale, + fallbackLocale: 'zh-Hans', + messages: require('./lang/index') + }) + this.t = i18n.t.bind(i18n) + + this.response = {} + + // 请求鉴权验证 + await this.middleware.verifyRequestSign() + + // 通用权限校验模块 + await this.middleware.accessControl() + }, + _after (error, result) { + if (error) { + // 处理中间件内抛出的标准响应对象 + if (error.errCode && getType(error) === 'object') { + const errCode = error.errCode + if (!isUniIdError(errCode)) { + return error + } + return { + errCode, + errMsg: error.errMsg || this.t(errCode, error.errMsgValue) + } + } + throw error + } + return Object.assign(this.response, result) + }, + /** + * 注册管理员 + * @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 + */ + registerAdmin, + /** + * 新增用户 + * @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 + */ + addUser, + /** + * 修改用户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#update-user + * @param {Object} params + * @param {String} params.id 要更新的用户id + * @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 + */ + updateUser, + /** + * 授权用户登录应用 + * @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 + */ + authorizeAppLogin, + /** + * 移除用户登录授权 + * @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 + */ + removeAuthorizedApp, + /** + * 设置用户允许登录的应用列表 + * @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 + */ + setAuthorizedApp, + /** + * 注册普通用户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#register-user + * @param {Object} params + * @param {String} params.username 用户名 + * @param {String} params.password 密码 + * @param {String} params.captcha 图形验证码 + * @param {String} params.nickname 昵称 + * @param {String} params.inviteCode 邀请码 + * @returns + */ + registerUser, + /** + * 通过邮箱+验证码注册用户 + * @param {Object} params + * @param {String} params.email 邮箱 + * @param {String} params.password 密码 + * @param {String} params.nickname 昵称 + * @param {String} params.code 邮箱验证码 + * @param {String} params.inviteCode 邀请码 + * @returns + */ + registerUserByEmail, + /** + * 用户名密码登录 + * @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 + */ + login, + /** + * 短信验证码登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-sms + * @param {Object} params + * @param {String} params.mobile 手机号 + * @param {String} params.code 短信验证码 + * @param {String} params.captcha 图形验证码 + * @param {String} params.inviteCode 邀请码 + * @returns + */ + loginBySms, + /** + * 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 + */ + loginByUniverify, + /** + * 微信登录 + * @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 + */ + loginByWeixin, + /** + * 支付宝登录 + * @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 + */ + loginByAlipay, + /** + * 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 + */ + loginByQQ, + /** + * 苹果登录 + * @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 + */ + loginByApple, + loginByWeixinMobile, + /** + * 用户退出登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#logout + * @returns + */ + logout, + /** + * 通过短信验证码绑定手机号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-sms + * @param {Object} params + * @param {String} params.mobile 手机号 + * @param {String} params.code 短信验证码 + * @param {String} params.captcha 图形验证码 + * @returns + */ + bindMobileBySms, + /** + * 通过一键登录绑定手机号 + * @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 + */ + bindMobileByUniverify, + /** + * 通过微信绑定手机号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-mp-weixin + * @param {Object} params + * @param {String} params.encryptedData 微信获取手机号返回的加密信息 + * @param {String} params.iv 微信获取手机号返回的初始向量 + * @returns + */ + bindMobileByMpWeixin, + /** + * 绑定微信 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-weixin + * @param {Object} params + * @param {String} params.code 微信登录返回的code + * @returns + */ + bindWeixin, + /** + * 绑定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 + */ + bindQQ, + /** + * 绑定支付宝账号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-alipay + * @param {Object} params + * @param {String} params.code 支付宝小程序登录返回的code参数 + * @returns + */ + bindAlipay, + /** + * 绑定苹果账号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-apple + * @param {Object} params + * @param {String} params.identityToken 苹果登录返回identityToken + * @returns + */ + bindApple, + /** + * 更新密码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#update-pwd + * @param {object} params + * @param {string} params.oldPassword 旧密码 + * @param {string} params.newPassword 新密码 + * @returns {object} + */ + updatePwd, + /** + * 通过短信验证码重置密码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#reset-pwd-by-sms + * @param {object} params + * @param {string} params.mobile 手机号 + * @param {string} params.mobile 短信验证码 + * @param {string} params.password 密码 + * @param {string} params.captcha 图形验证码 + * @returns {object} + */ + resetPwdBySms, + /** + * 通过邮箱验证码重置密码 + * @param {object} params + * @param {string} params.email 邮箱 + * @param {string} params.code 邮箱验证码 + * @param {string} params.password 密码 + * @param {string} params.captcha 图形验证码 + * @returns {object} + */ + resetPwdByEmail, + /** + * 注销账户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#close-account + * @returns + */ + closeAccount, + /** + * 获取账户账户简略信息 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-account-info + */ + getAccountInfo, + /** + * 创建图形验证码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#create-captcha + * @param {Object} params + * @param {String} params.scene 图形验证码使用场景 + * @returns + */ + createCaptcha, + /** + * 刷新图形验证码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#refresh-captcha + * @param {Object} params + * @param {String} params.scene 图形验证码使用场景 + * @returns + */ + refreshCaptcha, + /** + * 发送短信验证码 + * @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 + */ + sendSmsCode, + /** + * 发送邮箱验证码 + * @tutorial 需自行实现功能 + * @param {Object} params + * @param {String} params.email 邮箱 + * @param {String} params.captcha 图形验证码 + * @param {String} params.scene 短信验证码使用场景 + * @returns + */ + sendEmailCode, + /** + * 刷新token + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#refresh-token + */ + refreshToken, + /** + * 接受邀请 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#accept-invite + * @param {Object} params + * @param {String} params.inviteCode 邀请码 + * @returns + */ + acceptInvite, + /** + * 获取受邀用户 + * @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 + */ + getInvitedUser, + /** + * 更新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 + */ + setPushCid, + /** + * 获取支持的登录方式 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-supported-login-type + * @returns + */ + 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, + /** + * 安全网络握手,目前仅处理微信小程序安全网络握手 + */ + secureNetworkHandshakeByWeixin, + /** + * 设置密码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-pwd + * @returns + */ + setPwd, + /** + * 外部用户注册,将自身系统的用户账号导入uniId,为其创建一个对应uniId的账号(unieid),使得该账号可以使用依赖uniId的系统及功能。 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#external-register + * @returns + */ + externalRegister, + /** + * 外部用户登录,使用unieid即可登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#external-login + * @returns + * */ + externalLogin +} 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 0a3c9dc..d329d01 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,52 +1,52 @@ -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-not-exists-in-current-app': 'Account does not exists in current app', - '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', - 'uni-id-unsupported-request': 'Unsupported request', - 'uni-id-illegal-request': 'Illegal request' -} - -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-not-exists-in-current-app': 'Account does not exists in current app', + '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', + 'uni-id-unsupported-request': 'Unsupported request', + 'uni-id-illegal-request': 'Illegal request' +} + +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 557575d..1f22998 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 5c63243..a42f06d 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,52 +1,52 @@ -const word = { - login: '登录', - 'verify-mobile': '验证手机号' -} - -const sentence = { - 'uni-id-account-exists': '此账号已注册', - 'uni-id-account-not-exists': '此账号未注册', - 'uni-id-account-not-exists-in-current-app': '此账号未在该应用注册', - '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': '请先设置密码在尝试解绑', - 'uni-id-unsupported-request': '不支持的请求方式', - 'uni-id-illegal-request': '非法请求' -} - -module.exports = { - ...word, - ...sentence -} +const word = { + login: '登录', + 'verify-mobile': '验证手机号' +} + +const sentence = { + 'uni-id-account-exists': '此账号已注册', + 'uni-id-account-not-exists': '此账号未注册', + 'uni-id-account-not-exists-in-current-app': '此账号未在该应用注册', + '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': '请先设置密码在尝试解绑', + 'uni-id-unsupported-request': '不支持的请求方式', + 'uni-id-illegal-request': '非法请求' +} + +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 69e6617..47d8c4c 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 fd4c7be..dbec081 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 17c9860..cff351d 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 8b18706..1462b04 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 24cd60f..0e51b4d 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 8fcc569..e1dbb31 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 499265e..149c7de 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 35a1a33..9b4879a 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 ca0ebe6..fcfdc1e 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 abb1f41..c58f1e8 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 734f642..7ecea84 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,111 +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 - } - } - - 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 - } - } -} +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 9749c38..908d916 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 acb053a..c141016 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 91cfd94..36a7cbf 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,97 +1,97 @@ -const { - db, - dbCmd, - userCollection -} = require('../../common/constants') -const { - USER_IDENTIFIER -} = require('../../common/constants') -const { - batchFindObjctValue, - getType, - isMatchUserApp -} = 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) - if (authorizedAppType !== 'string' && authorizedAppType !== 'array') { - throw new Error('Invalid authorized app') - } - - let finalQuery - - if (condition.length === 1) { - finalQuery = condition[0] - } else { - finalQuery = dbCmd.or(condition) - } - const userQueryRes = await userCollection.where(finalQuery).get() - return { - total: userQueryRes.data.length, - userMatched: userQueryRes.data.filter(item => { - return isMatchUserApp(item.dcloud_appid, authorizedApp) - }) - } -} - -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, + isMatchUserApp +} = 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) + if (authorizedAppType !== 'string' && authorizedAppType !== 'array') { + throw new Error('Invalid authorized app') + } + + let finalQuery + + if (condition.length === 1) { + finalQuery = condition[0] + } else { + finalQuery = dbCmd.or(condition) + } + const userQueryRes = await userCollection.where(finalQuery).get() + return { + total: userQueryRes.data.length, + userMatched: userQueryRes.data.filter(item => { + return isMatchUserApp(item.dcloud_appid, authorizedApp) + }) + } +} + +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 07c1f34..0dd620e 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.getUniversalClientInfo().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.getUniversalClientInfo().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.getUniversalClientInfo().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.getUniversalClientInfo().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 ed77667..48d5688 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.getUniversalClientInfo() - 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.getUniversalClientInfo() + 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 65d48e2..84233c3 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 b16e731..6f863bc 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,240 +1,240 @@ -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.getUniversalClientInfo().appId - const { - total, - userMatched - } = await findUser({ - userQuery: user, - authorizedApp: appId - }) - if (userMatched.length === 0) { - if (total > 0) { - throw { - errCode: ERROR.ACCOUNT_NOT_EXISTS_IN_CURRENT_APP - } - } - 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.getUniversalClientInfo() - // 根据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({ - userRecord, - clientInfo: this.getUniversalClientInfo(), - passwordSecret: this.config.passwordSecret - }) - - const { - success: checkPasswordSuccess, - refreshPasswordInfo - } = passwordUtils.checkUserPassword({ - password - }) - 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 - } = this.getUniversalClientInfo() - const uniIdToken = this.getUniversalUniIdToken() - 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 -} +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.getUniversalClientInfo().appId + const { + total, + userMatched + } = await findUser({ + userQuery: user, + authorizedApp: appId + }) + if (userMatched.length === 0) { + if (total > 0) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS_IN_CURRENT_APP + } + } + 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.getUniversalClientInfo() + // 根据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({ + userRecord, + clientInfo: this.getUniversalClientInfo(), + passwordSecret: this.config.passwordSecret + }) + + const { + success: checkPasswordSuccess, + refreshPasswordInfo + } = passwordUtils.checkUserPassword({ + password + }) + 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 + } = this.getUniversalClientInfo() + const uniIdToken = this.getUniversalUniIdToken() + 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 9005cef..ddcbb97 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,49 +1,49 @@ -const { - dbCmd, - LOG_TYPE, - deviceCollection, - userCollection -} = require('../../common/constants') - -async function logout () { - const { - deviceId - } = this.getUniversalClientInfo() - const uniIdToken = this.getUniversalUniIdToken() - const payload = await this.uniIdCommon.checkToken( - uniIdToken, - { - autoRefresh: false - } - ) - if (payload.errCode) { - throw payload - } - const uid = payload.uid - - // 删除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 { + deviceId + } = this.getUniversalClientInfo() + const uniIdToken = this.getUniversalUniIdToken() + const payload = await this.uniIdCommon.checkToken( + uniIdToken, + { + autoRefresh: false + } + ) + if (payload.errCode) { + throw payload + } + const uid = payload.uid + + // 删除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 +} 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 92294df..0e46757 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,261 +1,261 @@ -const { - getType -} = require('../../common/utils') -const crypto = require('crypto') -const createConfig = require('uni-config-center') -const shareConfig = createConfig({ - pluginId: 'uni-id' -}) -let customPassword = {} -if (shareConfig.hasFile('custom-password.js')) { - customPassword = shareConfig.requireFile('custom-password.js') || {} -} - -const passwordAlgorithmMap = { - UNI_ID_HMAC_SHA1: 'hmac-sha1', - UNI_ID_HMAC_SHA256: 'hmac-sha256', - UNI_ID_CUSTOM: 'custom' -} - -const passwordAlgorithmKeyMap = Object.keys(passwordAlgorithmMap).reduce((res, item) => { - res[passwordAlgorithmMap[item]] = item - return res -}, {}) - -const passwordExtMethod = { - [passwordAlgorithmMap.UNI_ID_HMAC_SHA1]: { - verify ({ password }) { - const { password_secret_version: passwordSecretVersion } = this.userRecord - - const passwordSecret = this._getSecretByVersion({ - version: passwordSecretVersion - }) - - const { passwordHash } = this.encrypt({ - password, - passwordSecret - }) - - return passwordHash === this.userRecord.password - }, - encrypt ({ password, passwordSecret }) { - const { value: secret, version } = passwordSecret - const hmac = crypto.createHmac('sha1', secret.toString('ascii')) - - hmac.update(password) - - return { - passwordHash: hmac.digest('hex'), - version - } - } - }, - [passwordAlgorithmMap.UNI_ID_HMAC_SHA256]: { - verify ({ password }) { - const parse = this._parsePassword() - const passwordHash = crypto.createHmac(parse.algorithm, parse.salt).update(password).digest('hex') - - return passwordHash === parse.hash - }, - encrypt ({ password, passwordSecret }) { - const { version } = passwordSecret - - // 默认使用 sha256 加密算法 - const salt = crypto.randomBytes(10).toString('hex') - const sha256Hash = crypto.createHmac(passwordAlgorithmMap.UNI_ID_HMAC_SHA256.substring(5), salt).update(password).digest('hex') - const algorithm = passwordAlgorithmKeyMap[passwordAlgorithmMap.UNI_ID_HMAC_SHA256] - // B 为固定值,对应 PasswordMethodMaps 中的 sha256算法 - // hash 格式 $[PasswordMethodFlagMapsKey]$[salt size]$[salt][Hash] - const passwordHash = `$${algorithm}$${salt.length}$${salt}${sha256Hash}` - - return { - passwordHash, - version - } - } - }, - [passwordAlgorithmMap.UNI_ID_CUSTOM]: { - verify ({ password, passwordSecret }) { - if (!customPassword.verifyPassword) throw new Error('verifyPassword method not found in custom password file') - - // return true or false - return customPassword.verifyPassword({ - password, - passwordSecret, - userRecord: this.userRecord, - clientInfo: this.clientInfo - }) - }, - encrypt ({ password, passwordSecret }) { - if (!customPassword.encryptPassword) throw new Error('encryptPassword method not found in custom password file') - - // return object<{passwordHash: string, version: number}> - return customPassword.encryptPassword({ - password, - passwordSecret, - clientInfo: this.clientInfo - }) - } - } -} - -class PasswordUtils { - constructor ({ - userRecord = {}, - clientInfo, - passwordSecret - } = {}) { - if (!clientInfo) throw new Error('Invalid clientInfo') - if (!passwordSecret) throw new Error('Invalid password secret') - - this.clientInfo = clientInfo - this.userRecord = userRecord - this.passwordSecret = this.prePasswordSecret(passwordSecret) - } - - /** - * passwordSecret 预处理 - * @param passwordSecret - * @return {*[]} - */ - prePasswordSecret (passwordSecret) { - const newPasswordSecret = [] - if (getType(passwordSecret) === 'string') { - newPasswordSecret.push({ - value: passwordSecret, - type: passwordAlgorithmMap.UNI_ID_HMAC_SHA1 - }) - } else if (getType(passwordSecret) === 'array') { - for (const secret of passwordSecret.sort((a, b) => a.version - b.version)) { - newPasswordSecret.push({ - ...secret, - // 没有 type 设置默认 type hmac-sha1 - type: secret.type || passwordAlgorithmMap.UNI_ID_HMAC_SHA1 - }) - } - } else { - throw new Error('Invalid password secret') - } - - return newPasswordSecret - } - - /** - * 获取最新加密密钥 - * @return {*} - * @private - */ - _getLastestSecret () { - return this.passwordSecret[this.passwordSecret.length - 1] - } - - _getOldestSecret () { - return this.passwordSecret[0] - } - - _getSecretByVersion ({ version } = {}) { - if (!version && version !== 0) { - return this._getOldestSecret() - } - if (this.passwordSecret.length === 1) { - return this.passwordSecret[0] - } - return this.passwordSecret.find(item => item.version === version) - } - - /** - * 获取密码的验证/加密方法 - * @param passwordSecret - * @return {*[]} - * @private - */ - _getPasswordExt (passwordSecret) { - const ext = passwordExtMethod[passwordSecret.type] - if (!ext) { - throw new Error(`暂不支持 ${passwordSecret.type} 类型的加密算法`) - } - - const passwordExt = Object.create(null) - - for (const key in ext) { - passwordExt[key] = ext[key].bind(Object.assign(this, Object.keys(ext).reduce((res, item) => { - if (item !== key) { - res[item] = ext[item].bind(this) - } - return res - }, {}))) - } - - return passwordExt - } - - _parsePassword () { - const [algorithmKey = '', cost = 0, hashStr = ''] = this.userRecord.password.split('$').filter(key => key) - const algorithm = passwordAlgorithmMap[algorithmKey] ? passwordAlgorithmMap[algorithmKey].substring(5) : null - const salt = hashStr.substring(0, Number(cost)) - const hash = hashStr.substring(Number(cost)) - - return { - algorithm, - salt, - hash - } - } - - /** - * 生成加密后的密码 - * @param {String} password 密码 - */ - generatePasswordHash ({ password }) { - if (!password) throw new Error('Invalid password') - - const passwordSecret = this._getLastestSecret() - const ext = this._getPasswordExt(passwordSecret) - - const { passwordHash, version } = ext.encrypt({ - password, - passwordSecret - }) - - return { - passwordHash, - version - } - } - - /** - * 密码校验 - * @param {String} password - * @param {Boolean} autoRefresh - * @return {{refreshPasswordInfo: {version: *, passwordHash: *}, success: boolean}|{success: boolean}} - */ - checkUserPassword ({ password, autoRefresh = true }) { - if (!password) throw new Error('Invalid password') - - const { password_secret_version: passwordSecretVersion } = this.userRecord - const passwordSecret = this._getSecretByVersion({ - version: passwordSecretVersion - }) - const ext = this._getPasswordExt(passwordSecret) - - const success = ext.verify({ password, passwordSecret }) - - if (!success) { - return { - success: false - } - } - - let refreshPasswordInfo - if (autoRefresh && passwordSecretVersion !== this._getLastestSecret().version) { - refreshPasswordInfo = this.generatePasswordHash({ password }) - } - - return { - success: true, - refreshPasswordInfo - } - } -} - -module.exports = PasswordUtils +const { + getType +} = require('../../common/utils') +const crypto = require('crypto') +const createConfig = require('uni-config-center') +const shareConfig = createConfig({ + pluginId: 'uni-id' +}) +let customPassword = {} +if (shareConfig.hasFile('custom-password.js')) { + customPassword = shareConfig.requireFile('custom-password.js') || {} +} + +const passwordAlgorithmMap = { + UNI_ID_HMAC_SHA1: 'hmac-sha1', + UNI_ID_HMAC_SHA256: 'hmac-sha256', + UNI_ID_CUSTOM: 'custom' +} + +const passwordAlgorithmKeyMap = Object.keys(passwordAlgorithmMap).reduce((res, item) => { + res[passwordAlgorithmMap[item]] = item + return res +}, {}) + +const passwordExtMethod = { + [passwordAlgorithmMap.UNI_ID_HMAC_SHA1]: { + verify ({ password }) { + const { password_secret_version: passwordSecretVersion } = this.userRecord + + const passwordSecret = this._getSecretByVersion({ + version: passwordSecretVersion + }) + + const { passwordHash } = this.encrypt({ + password, + passwordSecret + }) + + return passwordHash === this.userRecord.password + }, + encrypt ({ password, passwordSecret }) { + const { value: secret, version } = passwordSecret + const hmac = crypto.createHmac('sha1', secret.toString('ascii')) + + hmac.update(password) + + return { + passwordHash: hmac.digest('hex'), + version + } + } + }, + [passwordAlgorithmMap.UNI_ID_HMAC_SHA256]: { + verify ({ password }) { + const parse = this._parsePassword() + const passwordHash = crypto.createHmac(parse.algorithm, parse.salt).update(password).digest('hex') + + return passwordHash === parse.hash + }, + encrypt ({ password, passwordSecret }) { + const { version } = passwordSecret + + // 默认使用 sha256 加密算法 + const salt = crypto.randomBytes(10).toString('hex') + const sha256Hash = crypto.createHmac(passwordAlgorithmMap.UNI_ID_HMAC_SHA256.substring(5), salt).update(password).digest('hex') + const algorithm = passwordAlgorithmKeyMap[passwordAlgorithmMap.UNI_ID_HMAC_SHA256] + // B 为固定值,对应 PasswordMethodMaps 中的 sha256算法 + // hash 格式 $[PasswordMethodFlagMapsKey]$[salt size]$[salt][Hash] + const passwordHash = `$${algorithm}$${salt.length}$${salt}${sha256Hash}` + + return { + passwordHash, + version + } + } + }, + [passwordAlgorithmMap.UNI_ID_CUSTOM]: { + verify ({ password, passwordSecret }) { + if (!customPassword.verifyPassword) throw new Error('verifyPassword method not found in custom password file') + + // return true or false + return customPassword.verifyPassword({ + password, + passwordSecret, + userRecord: this.userRecord, + clientInfo: this.clientInfo + }) + }, + encrypt ({ password, passwordSecret }) { + if (!customPassword.encryptPassword) throw new Error('encryptPassword method not found in custom password file') + + // return object<{passwordHash: string, version: number}> + return customPassword.encryptPassword({ + password, + passwordSecret, + clientInfo: this.clientInfo + }) + } + } +} + +class PasswordUtils { + constructor ({ + userRecord = {}, + clientInfo, + passwordSecret + } = {}) { + if (!clientInfo) throw new Error('Invalid clientInfo') + if (!passwordSecret) throw new Error('Invalid password secret') + + this.clientInfo = clientInfo + this.userRecord = userRecord + this.passwordSecret = this.prePasswordSecret(passwordSecret) + } + + /** + * passwordSecret 预处理 + * @param passwordSecret + * @return {*[]} + */ + prePasswordSecret (passwordSecret) { + const newPasswordSecret = [] + if (getType(passwordSecret) === 'string') { + newPasswordSecret.push({ + value: passwordSecret, + type: passwordAlgorithmMap.UNI_ID_HMAC_SHA1 + }) + } else if (getType(passwordSecret) === 'array') { + for (const secret of passwordSecret.sort((a, b) => a.version - b.version)) { + newPasswordSecret.push({ + ...secret, + // 没有 type 设置默认 type hmac-sha1 + type: secret.type || passwordAlgorithmMap.UNI_ID_HMAC_SHA1 + }) + } + } else { + throw new Error('Invalid password secret') + } + + return newPasswordSecret + } + + /** + * 获取最新加密密钥 + * @return {*} + * @private + */ + _getLastestSecret () { + return this.passwordSecret[this.passwordSecret.length - 1] + } + + _getOldestSecret () { + return this.passwordSecret[0] + } + + _getSecretByVersion ({ version } = {}) { + if (!version && version !== 0) { + return this._getOldestSecret() + } + if (this.passwordSecret.length === 1) { + return this.passwordSecret[0] + } + return this.passwordSecret.find(item => item.version === version) + } + + /** + * 获取密码的验证/加密方法 + * @param passwordSecret + * @return {*[]} + * @private + */ + _getPasswordExt (passwordSecret) { + const ext = passwordExtMethod[passwordSecret.type] + if (!ext) { + throw new Error(`暂不支持 ${passwordSecret.type} 类型的加密算法`) + } + + const passwordExt = Object.create(null) + + for (const key in ext) { + passwordExt[key] = ext[key].bind(Object.assign(this, Object.keys(ext).reduce((res, item) => { + if (item !== key) { + res[item] = ext[item].bind(this) + } + return res + }, {}))) + } + + return passwordExt + } + + _parsePassword () { + const [algorithmKey = '', cost = 0, hashStr = ''] = this.userRecord.password.split('$').filter(key => key) + const algorithm = passwordAlgorithmMap[algorithmKey] ? passwordAlgorithmMap[algorithmKey].substring(5) : null + const salt = hashStr.substring(0, Number(cost)) + const hash = hashStr.substring(Number(cost)) + + return { + algorithm, + salt, + hash + } + } + + /** + * 生成加密后的密码 + * @param {String} password 密码 + */ + generatePasswordHash ({ password }) { + if (!password) throw new Error('Invalid password') + + const passwordSecret = this._getLastestSecret() + const ext = this._getPasswordExt(passwordSecret) + + const { passwordHash, version } = ext.encrypt({ + password, + passwordSecret + }) + + return { + passwordHash, + version + } + } + + /** + * 密码校验 + * @param {String} password + * @param {Boolean} autoRefresh + * @return {{refreshPasswordInfo: {version: *, passwordHash: *}, success: boolean}|{success: boolean}} + */ + checkUserPassword ({ password, autoRefresh = true }) { + if (!password) throw new Error('Invalid password') + + const { password_secret_version: passwordSecretVersion } = this.userRecord + const passwordSecret = this._getSecretByVersion({ + version: passwordSecretVersion + }) + const ext = this._getPasswordExt(passwordSecret) + + const success = ext.verify({ password, passwordSecret }) + + if (!success) { + return { + success: false + } + } + + let refreshPasswordInfo + if (autoRefresh && passwordSecretVersion !== this._getLastestSecret().version) { + refreshPasswordInfo = this.generatePasswordHash({ password }) + } + + return { + success: true, + refreshPasswordInfo + } + } +} + +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 18f5b55..7ea612d 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.getUniversalClientInfo().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.getUniversalClientInfo().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.getUniversalClientInfo().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.getUniversalClientInfo().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.getUniversalClientInfo().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.getUniversalClientInfo().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 ca027e4..24eec34 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,215 +1,215 @@ -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.getUniversalClientInfo().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({ - clientInfo: this.getUniversalClientInfo(), - 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 - } = this.getUniversalClientInfo() - const uniIdToken = this.getUniversalUniIdToken() - - 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.getUniversalClientInfo() - }) - } - - 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 - } - }) - : {} - ), - passwordConfirmed: !!userRecord.password - } -} - -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.getUniversalClientInfo().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({ + clientInfo: this.getUniversalClientInfo(), + 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 + } = this.getUniversalClientInfo() + const uniIdToken = this.getUniversalUniIdToken() + + 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.getUniversalClientInfo() + }) + } + + 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 + } + }) + : {} + ), + passwordConfirmed: !!userRecord.password + } +} + +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 77791f5..8431551 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,164 +1,164 @@ -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.getUniversalClientInfo().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 -} +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.getUniversalClientInfo().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 9caecaa..21c70e9 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 || {})[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 b974e06..eac7a51 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,106 +1,106 @@ -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.getUniversalClientInfo().appId - const { - total, - userMatched - } = await findUser({ - userQuery: user, - authorizedApp: appId - }) - if (userMatched.length === 0) { - if (type === 'login') { - if (total > 0) { - throw { - errCode: ERROR.ACCOUNT_NOT_EXISTS_IN_CURRENT_APP - } - } - 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.getUniversalClientInfo().appId + const { + total, + userMatched + } = await findUser({ + userQuery: user, + authorizedApp: appId + }) + if (userMatched.length === 0) { + if (type === 'login') { + if (total > 0) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS_IN_CURRENT_APP + } + } + 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 8b45b62..33c17c0 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.getUniversalClientInfo().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.getUniversalClientInfo().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 c2ebb1b..ced33b9 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/utils.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/utils.js index f00ca0a..7d3e0f3 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/utils.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/utils.js @@ -1,18 +1,18 @@ -let redisEnable = null -function getRedisEnable() { - // 未用到的时候不调用redis接口,节省一些连接数 - if (redisEnable !== null) { - return redisEnable - } - try { - uniCloud.redis() - redisEnable = true - } catch (error) { - redisEnable = false - } - return redisEnable -} - -module.exports = { - getRedisEnable +let redisEnable = null +function getRedisEnable() { + // 未用到的时候不调用redis接口,节省一些连接数 + if (redisEnable !== null) { + return redisEnable + } + try { + uniCloud.redis() + redisEnable = true + } catch (error) { + redisEnable = false + } + return redisEnable +} + +module.exports = { + getRedisEnable } \ No newline at end of file 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 31ba236..b11bc02 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.getUniversalClientInfo().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.getUniversalClientInfo().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 37a0cb8..619c722 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,234 +1,234 @@ -const crypto = require('crypto') -const { - userCollection -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') -const { - getRedisEnable -} = require('./utils') -const { - openDataCollection -} = require('../../common/constants') - -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.getUniversalClientInfo().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.getUniversalClientInfo().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 - } -} - -async function saveSecureNetworkCache ({ - code, - openid, - unionid, - sessionKey -}) { - const { - appId - } = this.getUniversalClientInfo() - const key = `uni-id:${appId}:weixin-mp:code:${code}:secure-network-cache` - const value = JSON.stringify({ - openid, - unionid, - session_key: sessionKey - }) - // 此处存储的是code的缓存,有效期两天即可 - const expiredSeconds = 2 * 24 * 60 * 60 - - await openDataCollection.doc(key).set({ - value, - expired: Date.now() + expiredSeconds * 1000 - }) - const isRedisEnable = getRedisEnable() - if (isRedisEnable) { - const redis = uniCloud.redis() - await redis.set(key, value, 'EX', expiredSeconds) - } -} - -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.getUniversalClientInfo().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.getUniversalClientInfo().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.getUniversalClientInfo().appId - - const cache = await this.uniOpenBridge.getAccessToken({ - dcloudAppid: appId, - platform: 'weixin-' + weixinPlatform - }) - - return cache.access_token -} -module.exports = { - decryptWeixinData, - getWeixinPlatform, - generateWeixinCache, - getWeixinCache, - saveWeixinUserKey, - getWeixinAccessToken, - saveSecureNetworkCache -} +const crypto = require('crypto') +const { + userCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + getRedisEnable +} = require('./utils') +const { + openDataCollection +} = require('../../common/constants') + +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.getUniversalClientInfo().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.getUniversalClientInfo().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 + } +} + +async function saveSecureNetworkCache ({ + code, + openid, + unionid, + sessionKey +}) { + const { + appId + } = this.getUniversalClientInfo() + const key = `uni-id:${appId}:weixin-mp:code:${code}:secure-network-cache` + const value = JSON.stringify({ + openid, + unionid, + session_key: sessionKey + }) + // 此处存储的是code的缓存,有效期两天即可 + const expiredSeconds = 2 * 24 * 60 * 60 + + await openDataCollection.doc(key).set({ + value, + expired: Date.now() + expiredSeconds * 1000 + }) + const isRedisEnable = getRedisEnable() + if (isRedisEnable) { + const redis = uniCloud.redis() + await redis.set(key, value, 'EX', expiredSeconds) + } +} + +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.getUniversalClientInfo().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.getUniversalClientInfo().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.getUniversalClientInfo().appId + + const cache = await this.uniOpenBridge.getAccessToken({ + dcloudAppid: appId, + platform: 'weixin-' + weixinPlatform + }) + + return cache.access_token +} +module.exports = { + decryptWeixinData, + getWeixinPlatform, + generateWeixinCache, + getWeixinCache, + saveWeixinUserKey, + getWeixinAccessToken, + saveSecureNetworkCache +} 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 6041ffa..e333fe0 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 a111ee3..1915335 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.getUniversalUniIdToken() - 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.getUniversalUniIdToken() + 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 5be1000..9f7c958 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,8 +1,8 @@ -module.exports = { - auth: require('./auth'), - uniIdLog: require('./uni-id-log'), - validate: require('./validate'), - accessControl: require('./access-control'), - verifyRequestSign: require('./verify-request-sign'), - ...require('./rbac') -} +module.exports = { + auth: require('./auth'), + uniIdLog: require('./uni-id-log'), + validate: require('./validate'), + accessControl: require('./access-control'), + verifyRequestSign: require('./verify-request-sign'), + ...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 32fe0f8..f42ef8d 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 013f7ae..ca6927d 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.getUniversalClientInfo() - 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.getUniversalClientInfo() + 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 a58e8b4..52ff047 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/middleware/verify-request-sign.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/verify-request-sign.js index 3d631b6..84420e3 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/verify-request-sign.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/verify-request-sign.js @@ -1,39 +1,39 @@ -const crypto = require('crypto') -const { ERROR } = require('../common/error') -const needSignFunctions = new Set([ - 'externalRegister', - 'externalLogin' -]) - -module.exports = function () { - const methodName = this.getMethodName() - const { source } = this.getUniversalClientInfo() - // 非 HTTP 方式请求不需要鉴权 - if (source !== 'http') return - // 指定接口需要鉴权 - if (!needSignFunctions.has(methodName)) return - - const timeout = 20 * 1000 // 请求超过20秒不能再请求,防止重放攻击 - const { headers, body: _body } = this.getHttpInfo() - const { 'uni-id-nonce': nonce, 'uni-id-timestamp': timestamp, 'uni-id-signature': signature } = headers - const body = JSON.parse(_body).params || {} - const bodyStr = Object.keys(body) - .sort() - .filter(item => typeof body[item] !== 'object') - .map(item => `${item}=${body[item]}`) - .join('&') - - if (isNaN(Number(timestamp)) || (Number(timestamp) + timeout) < Date.now()) { - throw { - errCode: ERROR.ILLEGAL_REQUEST - } - } - - const reSignature = crypto.createHmac('sha256', `${this.config.requestAuthSecret + nonce}`).update(`${timestamp}${bodyStr}`).digest('hex') - - if (signature !== reSignature.toUpperCase()) { - throw { - errCode: ERROR.ILLEGAL_REQUEST - } - } -} +const crypto = require('crypto') +const { ERROR } = require('../common/error') +const needSignFunctions = new Set([ + 'externalRegister', + 'externalLogin' +]) + +module.exports = function () { + const methodName = this.getMethodName() + const { source } = this.getUniversalClientInfo() + // 非 HTTP 方式请求不需要鉴权 + if (source !== 'http') return + // 指定接口需要鉴权 + if (!needSignFunctions.has(methodName)) return + + const timeout = 20 * 1000 // 请求超过20秒不能再请求,防止重放攻击 + const { headers, body: _body } = this.getHttpInfo() + const { 'uni-id-nonce': nonce, 'uni-id-timestamp': timestamp, 'uni-id-signature': signature } = headers + const body = JSON.parse(_body).params || {} + const bodyStr = Object.keys(body) + .sort() + .filter(item => typeof body[item] !== 'object') + .map(item => `${item}=${body[item]}`) + .join('&') + + if (isNaN(Number(timestamp)) || (Number(timestamp) + timeout) < Date.now()) { + throw { + errCode: ERROR.ILLEGAL_REQUEST + } + } + + const reSignature = crypto.createHmac('sha256', `${this.config.requestAuthSecret + nonce}`).update(`${timestamp}${bodyStr}`).digest('hex') + + if (signature !== reSignature.toUpperCase()) { + throw { + errCode: ERROR.ILLEGAL_REQUEST + } + } +} 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 58fdb9d..f1bdf96 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 b57fe00..7b8599a 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 23157be..b4e06d6 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,8 +1,8 @@ -module.exports = { - setPwd: require('./set-pwd'), - 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 = { + setPwd: require('./set-pwd'), + 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 eff026a..20c6219 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,128 +1,128 @@ -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 { - total, - userMatched - } = await findUser.call(this, { - userQuery: { - email - }, - authorizedApp: [this.getUniversalClientInfo().appId] - }) - if (userMatched.length === 0) { - if (total > 0) { - throw { - errCode: ERROR.ACCOUNT_NOT_EXISTS_IN_CURRENT_APP - } - } - 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({ - clientInfo: this.getUniversalClientInfo(), - 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 { + total, + userMatched + } = await findUser.call(this, { + userQuery: { + email + }, + authorizedApp: [this.getUniversalClientInfo().appId] + }) + if (userMatched.length === 0) { + if (total > 0) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS_IN_CURRENT_APP + } + } + 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({ + clientInfo: this.getUniversalClientInfo(), + 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/account/reset-pwd-by-sms.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-sms.js index 1e3e5f6..bc10dc8 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-sms.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-sms.js @@ -1,128 +1,128 @@ -const { - ERROR -} = require('../../common/error') -const { - getNeedCaptcha, - verifyCaptcha -} = require('../../lib/utils/captcha') -const { - verifyMobileCode -} = require('../../lib/utils/verify-code') -const { - userCollection, - SMS_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-sms - * @param {object} params - * @param {string} params.mobile 手机号 - * @param {string} params.mobile 短信验证码 - * @param {string} params.password 密码 - * @param {string} params.captcha 图形验证码 - * @returns {object} - */ -module.exports = async function (params = {}) { - const schema = { - mobile: 'mobile', - code: 'string', - password: 'password', - captcha: { - required: false, - type: 'string' - } - } - this.middleware.validate(params, schema) - const { - mobile, - code, - password, - captcha - } = params - - const needCaptcha = await getNeedCaptcha.call(this, { - mobile, - type: LOG_TYPE.RESET_PWD_BY_SMS - }) - if (needCaptcha) { - await verifyCaptcha.call(this, { - captcha, - scene: CAPTCHA_SCENE.RESET_PWD_BY_SMS - }) - } - try { - // 验证手机号验证码,验证不通过时写入失败日志 - await verifyMobileCode({ - mobile, - code, - scene: SMS_SCENE.RESET_PWD_BY_SMS - }) - } catch (error) { - await this.middleware.uniIdLog({ - data: { - mobile - }, - type: LOG_TYPE.RESET_PWD_BY_SMS, - success: false - }) - throw error - } - // 根据手机号查找匹配的用户 - const { - total, - userMatched - } = await findUser.call(this, { - userQuery: { - mobile - }, - authorizedApp: [this.getUniversalClientInfo().appId] - }) - if (userMatched.length === 0) { - if (total > 0) { - throw { - errCode: ERROR.ACCOUNT_NOT_EXISTS_IN_CURRENT_APP - } - } - 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({ - clientInfo: this.getUniversalClientInfo(), - 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: { - mobile - }, - type: LOG_TYPE.RESET_PWD_BY_SMS - }) - return { - errCode: 0 - } -} +const { + ERROR +} = require('../../common/error') +const { + getNeedCaptcha, + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + verifyMobileCode +} = require('../../lib/utils/verify-code') +const { + userCollection, + SMS_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-sms + * @param {object} params + * @param {string} params.mobile 手机号 + * @param {string} params.mobile 短信验证码 + * @param {string} params.password 密码 + * @param {string} params.captcha 图形验证码 + * @returns {object} + */ +module.exports = async function (params = {}) { + const schema = { + mobile: 'mobile', + code: 'string', + password: 'password', + captcha: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + const { + mobile, + code, + password, + captcha + } = params + + const needCaptcha = await getNeedCaptcha.call(this, { + mobile, + type: LOG_TYPE.RESET_PWD_BY_SMS + }) + if (needCaptcha) { + await verifyCaptcha.call(this, { + captcha, + scene: CAPTCHA_SCENE.RESET_PWD_BY_SMS + }) + } + try { + // 验证手机号验证码,验证不通过时写入失败日志 + await verifyMobileCode({ + mobile, + code, + scene: SMS_SCENE.RESET_PWD_BY_SMS + }) + } catch (error) { + await this.middleware.uniIdLog({ + data: { + mobile + }, + type: LOG_TYPE.RESET_PWD_BY_SMS, + success: false + }) + throw error + } + // 根据手机号查找匹配的用户 + const { + total, + userMatched + } = await findUser.call(this, { + userQuery: { + mobile + }, + authorizedApp: [this.getUniversalClientInfo().appId] + }) + if (userMatched.length === 0) { + if (total > 0) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS_IN_CURRENT_APP + } + } + 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({ + clientInfo: this.getUniversalClientInfo(), + 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: { + mobile + }, + type: LOG_TYPE.RESET_PWD_BY_SMS + }) + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/set-pwd.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/set-pwd.js index 1b484f3..f33c6f4 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/set-pwd.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/set-pwd.js @@ -1,83 +1,83 @@ -const { userCollection, SMS_SCENE, LOG_TYPE, CAPTCHA_SCENE } = require('../../common/constants') -const { ERROR } = require('../../common/error') -const { verifyMobileCode } = require('../../lib/utils/verify-code') -const PasswordUtils = require('../../lib/utils/password') -const { getNeedCaptcha, verifyCaptcha } = require('../../lib/utils/captcha') - -module.exports = async function (params = {}) { - const schema = { - password: 'password', - code: 'string', - captcha: { - required: false, - type: 'string' - } - } - this.middleware.validate(params, schema) - - const { password, code, captcha } = params - const uid = this.authInfo.uid - const getUserRes = await userCollection.doc(uid).get() - const userRecord = getUserRes.data[0] - if (!userRecord) { - throw { - errCode: ERROR.ACCOUNT_NOT_EXISTS - } - } - - const needCaptcha = await getNeedCaptcha.call(this, { - mobile: userRecord.mobile - }) - - if (needCaptcha) { - await verifyCaptcha.call(this, { - captcha, - scene: CAPTCHA_SCENE.SET_PWD_BY_SMS - }) - } - - try { - // 验证手机号验证码,验证不通过时写入失败日志 - await verifyMobileCode({ - mobile: userRecord.mobile, - code, - scene: SMS_SCENE.SET_PWD_BY_SMS - }) - } catch (error) { - await this.middleware.uniIdLog({ - data: { - mobile: userRecord.mobile - }, - type: LOG_TYPE.SET_PWD_BY_SMS, - success: false - }) - throw error - } - - const { - passwordHash, - version - } = new PasswordUtils({ - clientInfo: this.getUniversalClientInfo(), - passwordSecret: this.config.passwordSecret - }).generatePasswordHash({ - password - }) - - // 更新用户密码 - await userCollection.doc(uid).update({ - password: passwordHash, - password_secret_version: version - }) - - await this.middleware.uniIdLog({ - data: { - mobile: userRecord.mobile - }, - type: LOG_TYPE.SET_PWD_BY_SMS - }) - - return { - errCode: 0 - } -} +const { userCollection, SMS_SCENE, LOG_TYPE, CAPTCHA_SCENE } = require('../../common/constants') +const { ERROR } = require('../../common/error') +const { verifyMobileCode } = require('../../lib/utils/verify-code') +const PasswordUtils = require('../../lib/utils/password') +const { getNeedCaptcha, verifyCaptcha } = require('../../lib/utils/captcha') + +module.exports = async function (params = {}) { + const schema = { + password: 'password', + code: 'string', + captcha: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + + const { password, code, captcha } = params + const uid = this.authInfo.uid + const getUserRes = await userCollection.doc(uid).get() + const userRecord = getUserRes.data[0] + if (!userRecord) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + + const needCaptcha = await getNeedCaptcha.call(this, { + mobile: userRecord.mobile + }) + + if (needCaptcha) { + await verifyCaptcha.call(this, { + captcha, + scene: CAPTCHA_SCENE.SET_PWD_BY_SMS + }) + } + + try { + // 验证手机号验证码,验证不通过时写入失败日志 + await verifyMobileCode({ + mobile: userRecord.mobile, + code, + scene: SMS_SCENE.SET_PWD_BY_SMS + }) + } catch (error) { + await this.middleware.uniIdLog({ + data: { + mobile: userRecord.mobile + }, + type: LOG_TYPE.SET_PWD_BY_SMS, + success: false + }) + throw error + } + + const { + passwordHash, + version + } = new PasswordUtils({ + clientInfo: this.getUniversalClientInfo(), + passwordSecret: this.config.passwordSecret + }).generatePasswordHash({ + password + }) + + // 更新用户密码 + await userCollection.doc(uid).update({ + password: passwordHash, + password_secret_version: version + }) + + await this.middleware.uniIdLog({ + data: { + mobile: userRecord.mobile + }, + type: LOG_TYPE.SET_PWD_BY_SMS + }) + + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/update-pwd.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/update-pwd.js index 8a02718..97fd1be 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/update-pwd.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/update-pwd.js @@ -1,69 +1,69 @@ -const { - userCollection -} = require('../../common/constants') -const { - ERROR -} = require('../../common/error') -const PasswordUtils = require('../../lib/utils/password') -/** - * 更新密码 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#update-pwd - * @param {object} params - * @param {string} params.oldPassword 旧密码 - * @param {string} params.newPassword 新密码 - * @returns {object} - */ -module.exports = async function (params = {}) { - const schema = { - oldPassword: 'string', // 防止密码规则调整导致旧密码无法更新 - newPassword: 'password' - } - this.middleware.validate(params, schema) - const uid = this.authInfo.uid - const getUserRes = await userCollection.doc(uid).get() - const userRecord = getUserRes.data[0] - if (!userRecord) { - throw { - errCode: ERROR.ACCOUNT_NOT_EXISTS - } - } - const { - oldPassword, - newPassword - } = params - const passwordUtils = new PasswordUtils({ - userRecord, - clientInfo: this.getUniversalClientInfo(), - passwordSecret: this.config.passwordSecret - }) - - const { - success: checkPasswordSuccess - } = passwordUtils.checkUserPassword({ - password: oldPassword, - autoRefresh: false - }) - - if (!checkPasswordSuccess) { - throw { - errCode: ERROR.PASSWORD_ERROR - } - } - - const { - passwordHash, - version - } = passwordUtils.generatePasswordHash({ - password: newPassword - }) - - await userCollection.doc(uid).update({ - password: passwordHash, - password_secret_version: version, - valid_token_date: Date.now() // refreshToken时会校验,如果创建token时间在此时间点之前,则拒绝下发新token,返回token失效错误码 - }) - // 执行更新密码操作后客户端应将用户退出重新登录 - return { - errCode: 0 - } -} +const { + userCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const PasswordUtils = require('../../lib/utils/password') +/** + * 更新密码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#update-pwd + * @param {object} params + * @param {string} params.oldPassword 旧密码 + * @param {string} params.newPassword 新密码 + * @returns {object} + */ +module.exports = async function (params = {}) { + const schema = { + oldPassword: 'string', // 防止密码规则调整导致旧密码无法更新 + newPassword: 'password' + } + this.middleware.validate(params, schema) + const uid = this.authInfo.uid + const getUserRes = await userCollection.doc(uid).get() + const userRecord = getUserRes.data[0] + if (!userRecord) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + const { + oldPassword, + newPassword + } = params + const passwordUtils = new PasswordUtils({ + userRecord, + clientInfo: this.getUniversalClientInfo(), + passwordSecret: this.config.passwordSecret + }) + + const { + success: checkPasswordSuccess + } = passwordUtils.checkUserPassword({ + password: oldPassword, + autoRefresh: false + }) + + if (!checkPasswordSuccess) { + throw { + errCode: ERROR.PASSWORD_ERROR + } + } + + const { + passwordHash, + version + } = passwordUtils.generatePasswordHash({ + password: newPassword + }) + + await userCollection.doc(uid).update({ + password: passwordHash, + password_secret_version: version, + valid_token_date: Date.now() // refreshToken时会校验,如果创建token时间在此时间点之前,则拒绝下发新token,返回token失效错误码 + }) + // 执行更新密码操作后客户端应将用户退出重新登录 + 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 70aade3..a928489 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,121 +1,121 @@ -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({ - clientInfo: this.getUniversalClientInfo(), - 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({ + clientInfo: this.getUniversalClientInfo(), + 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 6baff53..c8830f5 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/admin/update-user.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/update-user.js index 8b5bbc0..085d64a 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/update-user.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/update-user.js @@ -1,139 +1,139 @@ -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#update-user - * @param {Object} params - * @param {String} params.uid 要更新的用户id - * @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 = { - uid: 'string', - username: 'username', - password: { - required: false, - type: '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 { - uid, - username, - password, - authorizedApp, - nickname, - role, - mobile, - email, - tags, - status - } = params - - // 更新的用户数据字段 - const data = { - username, - dcloud_appid: authorizedApp, - nickname, - role: role, - mobile, - email, - tags: tags, - status - } - - const realData = Object.keys(data).reduce((res, key) => { - const item = data[key] - if (item) { - res[key] = item - } - return res - }, {}) - - // 更新用户名时验证用户名是否重新 - if (username) { - const { - userMatched - } = await findUser({ - userQuery: { - username - }, - authorizedApp - }) - if (userMatched.filter(user => user._id !== uid).length) { - throw { - errCode: ERROR.ACCOUNT_EXISTS - } - } - } - - if (password) { - const passwordUtils = new PasswordUtils({ - clientInfo: this.getUniversalClientInfo(), - passwordSecret: this.config.passwordSecret - }) - const { - passwordHash, - version - } = passwordUtils.generatePasswordHash({ - password - }) - - data.password = passwordHash - data.password_secret_version = version - } - - await userCollection.doc(uid).update(realData) - - return { - errCode: 0 - } -} +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#update-user + * @param {Object} params + * @param {String} params.uid 要更新的用户id + * @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 = { + uid: 'string', + username: 'username', + password: { + required: false, + type: '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 { + uid, + username, + password, + authorizedApp, + nickname, + role, + mobile, + email, + tags, + status + } = params + + // 更新的用户数据字段 + const data = { + username, + dcloud_appid: authorizedApp, + nickname, + role: role, + mobile, + email, + tags: tags, + status + } + + const realData = Object.keys(data).reduce((res, key) => { + const item = data[key] + if (item !== undefined) { + res[key] = item + } + return res + }, {}) + + // 更新用户名时验证用户名是否重新 + if (username) { + const { + userMatched + } = await findUser({ + userQuery: { + username + }, + authorizedApp + }) + if (userMatched.filter(user => user._id !== uid).length) { + throw { + errCode: ERROR.ACCOUNT_EXISTS + } + } + } + if (password) { + const passwordUtils = new PasswordUtils({ + clientInfo: this.getUniversalClientInfo(), + passwordSecret: this.config.passwordSecret + }) + const { + passwordHash, + version + } = passwordUtils.generatePasswordHash({ + password + }) + + realData.password = passwordHash + realData.password_secret_version = version + } + + await userCollection.doc(uid).update(realData) + + + return { + errCode: 0 + } +} 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 7d235fe..476e234 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 d6c28cc..e22f9f2 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/external/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/index.js index 8ad500e..fe2ab8b 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/index.js @@ -1,4 +1,4 @@ -module.exports = { - externalRegister: require('./register'), - externalLogin: require('./login') -} +module.exports = { + externalRegister: require('./register'), + externalLogin: require('./login') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/login.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/login.js index 2053ac0..2eccf09 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/login.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/login.js @@ -1,29 +1,29 @@ -const { preLogin, postLogin } = require('../../lib/utils/login') - -module.exports = async function (params = {}) { - const schema = { - unieid: 'username' - } - - this.middleware.validate(params, schema) - - const { - unieid - } = params - - const user = await preLogin.call(this, { - user: { - username: unieid - } - }) - - const result = await postLogin.call(this, { - user - }) - - return { - errCode: result.errCode, - newToken: result.newToken, - unieid - } -} +const { preLogin, postLogin } = require('../../lib/utils/login') + +module.exports = async function (params = {}) { + const schema = { + unieid: 'username' + } + + this.middleware.validate(params, schema) + + const { + unieid + } = params + + const user = await preLogin.call(this, { + user: { + username: unieid + } + }) + + const result = await postLogin.call(this, { + user + }) + + return { + errCode: result.errCode, + newToken: result.newToken, + unieid + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/register.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/register.js index 5c2b12b..ad65c1e 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/register.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/register.js @@ -1,52 +1,52 @@ -const { preRegister, postRegister } = require('../../lib/utils/register') - -module.exports = async function (params = {}) { - const schema = { - unieid: 'username', - nickname: { - required: false, - type: 'nickname' - }, - gender: { - required: false, - type: 'number' - }, - avatar: { - required: false, - type: 'string' - } - } - - this.middleware.validate(params, schema) - - const { - unieid, - avatar, - gender, - nickname - } = params - - await preRegister.call(this, { - user: { - username: unieid - } - }) - - const result = await postRegister.call(this, { - user: { - username: unieid, - avatar, - gender, - nickname - } - }) - - return { - errCode: result.errCode, - newToken: result.newToken, - unieid, - avatar, - gender, - nickname - } -} +const { preRegister, postRegister } = require('../../lib/utils/register') + +module.exports = async function (params = {}) { + const schema = { + unieid: 'username', + nickname: { + required: false, + type: 'nickname' + }, + gender: { + required: false, + type: 'number' + }, + avatar: { + required: false, + type: 'string' + } + } + + this.middleware.validate(params, schema) + + const { + unieid, + avatar, + gender, + nickname + } = params + + await preRegister.call(this, { + user: { + username: unieid + } + }) + + const result = await postRegister.call(this, { + user: { + username: unieid, + avatar, + gender, + nickname + } + }) + + return { + errCode: result.errCode, + newToken: result.newToken, + unieid, + avatar, + gender, + nickname + } +} 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 c1d3ba9..2461e06 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 d232977..93d4671 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 dcca9a3..4a9bee1 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 7fbd964..f65f58b 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,20 +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'), - loginByWeixinMobile: require('./login-by-weixin-mobile') -} +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 4611b0c..d5d4631 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 5a1e2fe..5f39e62 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 9d4b453..856449d 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 22c2f8b..afe1f01 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 cecf581..8cd4ab5 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 1f3c3a6..c3af08f 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 a8f9e6f..0ebbf3a 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 1a5eab8..5c93bd4 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 c12efe3..8054ece 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 445c5cd..fbc4069 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.getUniversalClientInfo() - 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.getUniversalClientInfo() + 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-sms.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-sms.js index 8f9aeaf..915e9b6 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-sms.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-sms.js @@ -1,99 +1,99 @@ -const { - getNeedCaptcha, - verifyCaptcha -} = require('../../lib/utils/captcha') -const { - verifyMobileCode -} = require('../../lib/utils/verify-code') -const { - preUnifiedLogin, - postUnifiedLogin -} = require('../../lib/utils/unified-login') -const { - CAPTCHA_SCENE, - SMS_SCENE, - LOG_TYPE -} = require('../../common/constants') - -/** - * 短信验证码登录 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-sms - * @param {Object} params - * @param {String} params.mobile 手机号 - * @param {String} params.code 短信验证码 - * @param {String} params.captcha 图形验证码 - * @param {String} params.inviteCode 邀请码 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - mobile: 'mobile', - code: 'string', - captcha: { - required: false, - type: 'string' - }, - inviteCode: { - required: false, - type: 'string' - } - } - this.middleware.validate(params, schema) - const { - mobile, - code, - captcha, - inviteCode - } = params - - const needCaptcha = await getNeedCaptcha.call(this, { - mobile - }) - - if (needCaptcha) { - await verifyCaptcha.call(this, { - captcha, - scene: CAPTCHA_SCENE.LOGIN_BY_SMS - }) - } - - try { - await verifyMobileCode({ - mobile, - code, - scene: SMS_SCENE.LOGIN_BY_SMS - }) - } catch (error) { - console.log(error, { - mobile, - code, - type: SMS_SCENE.LOGIN_BY_SMS - }) - await this.middleware.uniIdLog({ - success: false, - data: { - mobile - }, - type: LOG_TYPE.LOGIN - }) - throw error - } - - const { - type, - user - } = await preUnifiedLogin.call(this, { - user: { - mobile - } - }) - return postUnifiedLogin.call(this, { - user, - extraData: { - mobile_confirmed: 1 - }, - isThirdParty: false, - type, - inviteCode - }) -} +const { + getNeedCaptcha, + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + verifyMobileCode +} = require('../../lib/utils/verify-code') +const { + preUnifiedLogin, + postUnifiedLogin +} = require('../../lib/utils/unified-login') +const { + CAPTCHA_SCENE, + SMS_SCENE, + LOG_TYPE +} = require('../../common/constants') + +/** + * 短信验证码登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-sms + * @param {Object} params + * @param {String} params.mobile 手机号 + * @param {String} params.code 短信验证码 + * @param {String} params.captcha 图形验证码 + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + mobile: 'mobile', + code: 'string', + captcha: { + required: false, + type: 'string' + }, + inviteCode: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + const { + mobile, + code, + captcha, + inviteCode + } = params + + const needCaptcha = await getNeedCaptcha.call(this, { + mobile + }) + + if (needCaptcha) { + await verifyCaptcha.call(this, { + captcha, + scene: CAPTCHA_SCENE.LOGIN_BY_SMS + }) + } + + try { + await verifyMobileCode({ + mobile, + code, + scene: SMS_SCENE.LOGIN_BY_SMS + }) + } catch (error) { + console.log(error, { + mobile, + code, + type: SMS_SCENE.LOGIN_BY_SMS + }) + await this.middleware.uniIdLog({ + success: false, + data: { + mobile + }, + type: LOG_TYPE.LOGIN + }) + throw error + } + + const { + type, + user + } = await preUnifiedLogin.call(this, { + user: { + mobile + } + }) + return postUnifiedLogin.call(this, { + user, + extraData: { + mobile_confirmed: 1 + }, + isThirdParty: false, + 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 8234fa0..6a6d599 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 11fda9b..133aadb 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 05199b0..53e681c 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 b12a17f..496cdb4 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 index 1b6e515..c27c2b2 100644 --- 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 @@ -1,106 +1,106 @@ -const { - initWeixin -} = require('../../lib/third-party/index') -const { - getWeixinAccessToken -} = 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 - }) -} +const { + initWeixin +} = require('../../lib/third-party/index') +const { + getWeixinAccessToken +} = 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 3bbe3ec..fb20db9 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,175 +1,175 @@ -const { - initWeixin -} = require('../../lib/third-party/index') -const { - ERROR -} = require('../../common/error') -const { - preUnifiedLogin, - postUnifiedLogin -} = require('../../lib/utils/unified-login') -const { - generateWeixinCache, - getWeixinPlatform, - saveWeixinUserKey, - saveSecureNetworkCache -} = 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, - // 内部参数,暂不暴露 - secureNetworkCache = false - } = params - const { - appId - } = this.getUniversalClientInfo() - 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 - - if (secureNetworkCache) { - if (weixinPlatform !== 'mp') { - throw new Error('Unsupported weixin platform, expect mp-weixin') - } - await saveSecureNetworkCache({ - code, - openid, - unionid, - sessionKey - }) - } - - 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 - }) - - if (avatar) { - // 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.avatar_file = { - name: cloudPath, - extname: extName, - url: fileID - } - } - - extraData.nickname = nickname - } - 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, + saveSecureNetworkCache +} = 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, + // 内部参数,暂不暴露 + secureNetworkCache = false + } = params + const { + appId + } = this.getUniversalClientInfo() + 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 + + if (secureNetworkCache) { + if (weixinPlatform !== 'mp') { + throw new Error('Unsupported weixin platform, expect mp-weixin') + } + await saveSecureNetworkCache({ + code, + openid, + unionid, + sessionKey + }) + } + + 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 + }) + + if (avatar) { + // 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.avatar_file = { + name: cloudPath, + extname: extName, + url: fileID + } + } + + extraData.nickname = nickname + } + 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 8419ee8..97e9cfe 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 897cc1c..544be2b 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 f11b437..7d491c6 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 c686138..8f8a167 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 ee4dd44..ce9cc7b 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 4fa69dc..df82184 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 774ecec..a438ef9 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 bfd1a04..4ee4e26 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,38 +1,38 @@ -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 319210f..64ff603 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 564ec14..5e122ab 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,72 +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) { - const [admin] = getAdminRes.data - const appId = this.getUniversalClientInfo().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'] - } - }) -} +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.getUniversalClientInfo().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 f5a54c5..b52c1d2 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/register/register-user.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user.js index 510d768..130dece 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user.js @@ -1,68 +1,68 @@ -const { - postRegister, - preRegisterWithPassword -} = require('../../lib/utils/register') -const { - verifyCaptcha -} = require('../../lib/utils/captcha') -const { - CAPTCHA_SCENE -} = require('../../common/constants') - -/** - * 注册普通用户 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#register-user - * @param {Object} params - * @param {String} params.username 用户名 - * @param {String} params.password 密码 - * @param {String} params.captcha 图形验证码 - * @param {String} params.nickname 昵称 - * @param {String} params.inviteCode 邀请码 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - username: 'username', - password: 'password', - captcha: 'string', - nickname: { - required: false, - type: 'nickname' - }, - inviteCode: { - required: false, - type: 'string' - } - } - this.middleware.validate(params, schema) - const { - username, - password, - nickname, - captcha, - inviteCode - } = params - - await verifyCaptcha.call(this, { - captcha, - scene: CAPTCHA_SCENE.REGISTER - }) - - const { - user, - extraData - } = await preRegisterWithPassword.call(this, { - user: { - username - }, - password - }) - return postRegister.call(this, { - user, - extraData: { - ...extraData, - nickname - }, - inviteCode - }) -} +const { + postRegister, + preRegisterWithPassword +} = require('../../lib/utils/register') +const { + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + CAPTCHA_SCENE +} = require('../../common/constants') + +/** + * 注册普通用户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#register-user + * @param {Object} params + * @param {String} params.username 用户名 + * @param {String} params.password 密码 + * @param {String} params.captcha 图形验证码 + * @param {String} params.nickname 昵称 + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + username: 'username', + password: 'password', + captcha: 'string', + nickname: { + required: false, + type: 'nickname' + }, + inviteCode: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + const { + username, + password, + nickname, + captcha, + inviteCode + } = params + + await verifyCaptcha.call(this, { + captcha, + scene: CAPTCHA_SCENE.REGISTER + }) + + const { + user, + extraData + } = await preRegisterWithPassword.call(this, { + user: { + username + }, + password + }) + return postRegister.call(this, { + user, + extraData: { + ...extraData, + nickname + }, + 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 76e1247..bdb451b 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 = { - 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 - }) -} +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 b87ac80..eb87f8b 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 2e9a991..f4c2bd0 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 @@ -1,104 +1,104 @@ -const { - preBind, - postBind -} = require('../../lib/utils/relate') -const { - LOG_TYPE -} = require('../../common/constants') -const { - decryptWeixinData, - getWeixinCache, getWeixinAccessToken -} = require('../../lib/utils/weixin') -const { initWeixin } = require('../../lib/third-party') -const { ERROR } = require('../../common/error') - -/** - * 通过微信绑定手机号 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-mp-weixin - * @param {Object} params - * @param {String} params.encryptedData 微信获取手机号返回的加密信息 - * @param {String} params.iv 微信获取手机号返回的初始向量 - * @param {String} params.code 微信获取手机号返回的code - * @returns - */ -module.exports = async function (params = {}) { - /** - * 微信小程序的规则是客户端应先使用checkSession接口检测上次获取的sessionKey是否仍有效 - * 如果有效则直接使用上次存储的sessionKey即可 - * 如果无效应重新调用login接口再次刷新sessionKey - * 因此此接口不应直接使用客户端login获取的code,只能使用缓存的sessionKey - */ - const schema = { - encryptedData: { - required: false, - type: 'string' - }, - iv: { - required: false, - type: 'string' - }, - code: { - required: false, - type: 'string' - } - } - const { - encryptedData, - iv, - code - } = params - this.middleware.validate(params, schema) - - if ((!encryptedData && !iv) && !code) { - return { - errCode: ERROR.INVALID_PARAM - } - } - - const uid = this.authInfo.uid - - 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 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 { + preBind, + postBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE +} = require('../../common/constants') +const { + decryptWeixinData, + getWeixinCache, getWeixinAccessToken +} = require('../../lib/utils/weixin') +const { initWeixin } = require('../../lib/third-party') +const { ERROR } = require('../../common/error') + +/** + * 通过微信绑定手机号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-mp-weixin + * @param {Object} params + * @param {String} params.encryptedData 微信获取手机号返回的加密信息 + * @param {String} params.iv 微信获取手机号返回的初始向量 + * @param {String} params.code 微信获取手机号返回的code + * @returns + */ +module.exports = async function (params = {}) { + /** + * 微信小程序的规则是客户端应先使用checkSession接口检测上次获取的sessionKey是否仍有效 + * 如果有效则直接使用上次存储的sessionKey即可 + * 如果无效应重新调用login接口再次刷新sessionKey + * 因此此接口不应直接使用客户端login获取的code,只能使用缓存的sessionKey + */ + const schema = { + encryptedData: { + required: false, + type: 'string' + }, + iv: { + required: false, + type: 'string' + }, + code: { + required: false, + type: 'string' + } + } + const { + encryptedData, + iv, + code + } = params + this.middleware.validate(params, schema) + + if ((!encryptedData && !iv) && !code) { + return { + errCode: ERROR.INVALID_PARAM + } + } + + const uid = this.authInfo.uid + + 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 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-mobile-by-sms.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-sms.js index 2275b05..1640c2d 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-sms.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-sms.js @@ -1,92 +1,92 @@ -const { - getNeedCaptcha, - verifyCaptcha -} = require('../../lib/utils/captcha') -const { - LOG_TYPE, - SMS_SCENE, - CAPTCHA_SCENE -} = require('../../common/constants') -const { - verifyMobileCode -} = require('../../lib/utils/verify-code') -const { - preBind, - postBind -} = require('../../lib/utils/relate') - -/** - * 通过短信验证码绑定手机号 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-sms - * @param {Object} params - * @param {String} params.mobile 手机号 - * @param {String} params.code 短信验证码 - * @param {String} params.captcha 图形验证码 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - mobile: 'mobile', - code: 'string', - captcha: { - type: 'string', - required: false - } - } - const { - mobile, - code, - captcha - } = params - this.middleware.validate(params, schema) - const uid = this.authInfo.uid - - // 判断是否需要验证码 - const needCaptcha = await getNeedCaptcha.call(this, { - uid, - type: LOG_TYPE.BIND_MOBILE - }) - if (needCaptcha) { - await verifyCaptcha.call(this, { - captcha, - scene: CAPTCHA_SCENE.BIND_MOBILE_BY_SMS - }) - } - - try { - // 验证手机号验证码,验证不通过时写入失败日志 - await verifyMobileCode({ - mobile, - code, - scene: SMS_SCENE.BIND_MOBILE_BY_SMS - }) - } catch (error) { - await this.middleware.uniIdLog({ - data: { - user_id: uid - }, - type: LOG_TYPE.BIND_MOBILE, - success: false - }) - 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 { + getNeedCaptcha, + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + LOG_TYPE, + SMS_SCENE, + CAPTCHA_SCENE +} = require('../../common/constants') +const { + verifyMobileCode +} = require('../../lib/utils/verify-code') +const { + preBind, + postBind +} = require('../../lib/utils/relate') + +/** + * 通过短信验证码绑定手机号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-sms + * @param {Object} params + * @param {String} params.mobile 手机号 + * @param {String} params.code 短信验证码 + * @param {String} params.captcha 图形验证码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + mobile: 'mobile', + code: 'string', + captcha: { + type: 'string', + required: false + } + } + const { + mobile, + code, + captcha + } = params + this.middleware.validate(params, schema) + const uid = this.authInfo.uid + + // 判断是否需要验证码 + const needCaptcha = await getNeedCaptcha.call(this, { + uid, + type: LOG_TYPE.BIND_MOBILE + }) + if (needCaptcha) { + await verifyCaptcha.call(this, { + captcha, + scene: CAPTCHA_SCENE.BIND_MOBILE_BY_SMS + }) + } + + try { + // 验证手机号验证码,验证不通过时写入失败日志 + await verifyMobileCode({ + mobile, + code, + scene: SMS_SCENE.BIND_MOBILE_BY_SMS + }) + } catch (error) { + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: LOG_TYPE.BIND_MOBILE, + success: false + }) + 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-mobile-by-univerify.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-univerify.js index b38d1bc..2970c61 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 2ae771d..574f917 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.getUniversalClientInfo().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: { - [qqPlatform]: 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.getUniversalClientInfo().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: { + [qqPlatform]: 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 def541a..d649478 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.getUniversalClientInfo().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: { - [weixinPlatform]: 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.getUniversalClientInfo().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: { + [weixinPlatform]: 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 a587e76..4d99c02 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,13 +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'), - unbindWeixin: require('./unbind-weixin'), - unbindAlipay: require('./unbind-alipay'), - unbindQQ: require('./unbind-qq'), - unbindApple: require('./unbind-apple') -} +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 index db7b1a6..67bb43b 100644 --- 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 @@ -1,32 +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 - }) -} +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 index c966e3f..111c1bf 100644 --- 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 @@ -1,32 +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 - }) -} +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 index c4aec72..0f9e02e 100644 --- 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 @@ -1,46 +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.getUniversalClientInfo() - 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 - }) -} +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.getUniversalClientInfo() + 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 index 9174bef..8770bbd 100644 --- 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 @@ -1,40 +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 - }) -} +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 314d458..0ec67a5 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,5 +1,5 @@ -module.exports = { - refreshToken: require('./refresh-token'), - setPushCid: require('./set-push-cid'), - secureNetworkHandshakeByWeixin: require('./secure-network-handshake-by-weixin') -} +module.exports = { + refreshToken: require('./refresh-token'), + setPushCid: require('./set-push-cid'), + secureNetworkHandshakeByWeixin: require('./secure-network-handshake-by-weixin') +} 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 316a9ca..4b0d0a8 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.getUniversalUniIdToken() - }) - 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.getUniversalUniIdToken() + }) + return { + errCode: 0, + newToken: { + token, + tokenExpired + } + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/secure-network-handshake-by-weixin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/secure-network-handshake-by-weixin.js index 5b9c4af..82ea0b3 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/secure-network-handshake-by-weixin.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/secure-network-handshake-by-weixin.js @@ -1,73 +1,73 @@ -const { - ERROR -} = require('../../common/error') -const { - initWeixin -} = require('../../lib/third-party/index') -const { - saveWeixinUserKey, - saveSecureNetworkCache -} = require('../../lib/utils/weixin') -const loginByWeixin = require('../login/login-by-weixin') -/** - * 微信安全网络握手 - * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-push-cid - * @param {object} params - * @param {string} params.code 微信登录返回的code - * @param {boolean} params.callLoginByWeixin 是否同时调用一次微信登录 - * @returns - */ -module.exports = async function (params = {}) { - const schema = { - code: 'string', - callLoginByWeixin: { - type: 'boolean', - required: false - } - } - this.middleware.validate(params, schema) - let platform = this.clientPlatform - if (platform !== 'mp-weixin') { - throw new Error(`[secureNetworkHandshake] platform ${platform} is not supported`) - } - const { - code, - callLoginByWeixin = false - } = params - if (callLoginByWeixin) { - return loginByWeixin.call(this, { - code, - secureNetworkCache: true - }) - } - - const weixinApi = initWeixin.call(this) - let getWeixinAccountResult - try { - getWeixinAccountResult = await weixinApi.code2Session(code) - } catch (error) { - console.error(error) - throw { - errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED - } - } - const { - openid, - unionid, - sessionKey // 微信小程序用户sessionKey - } = getWeixinAccountResult - await saveSecureNetworkCache.call(this, { - code, - openid, - unionid, - sessionKey - }) - await saveWeixinUserKey.call(this, { - openid, - sessionKey - }) - - return { - errCode: 0 - } -} +const { + ERROR +} = require('../../common/error') +const { + initWeixin +} = require('../../lib/third-party/index') +const { + saveWeixinUserKey, + saveSecureNetworkCache +} = require('../../lib/utils/weixin') +const loginByWeixin = require('../login/login-by-weixin') +/** + * 微信安全网络握手 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-push-cid + * @param {object} params + * @param {string} params.code 微信登录返回的code + * @param {boolean} params.callLoginByWeixin 是否同时调用一次微信登录 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + code: 'string', + callLoginByWeixin: { + type: 'boolean', + required: false + } + } + this.middleware.validate(params, schema) + let platform = this.clientPlatform + if (platform !== 'mp-weixin') { + throw new Error(`[secureNetworkHandshake] platform ${platform} is not supported`) + } + const { + code, + callLoginByWeixin = false + } = params + if (callLoginByWeixin) { + return loginByWeixin.call(this, { + code, + secureNetworkCache: true + }) + } + + const weixinApi = initWeixin.call(this) + let getWeixinAccountResult + try { + getWeixinAccountResult = await weixinApi.code2Session(code) + } catch (error) { + console.error(error) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + const { + openid, + unionid, + sessionKey // 微信小程序用户sessionKey + } = getWeixinAccountResult + await saveSecureNetworkCache.call(this, { + code, + openid, + unionid, + sessionKey + }) + await saveWeixinUserKey.call(this, { + openid, + sessionKey + }) + + return { + errCode: 0 + } +} 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 70ff66f..326b4ff 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.getUniversalClientInfo() - 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.getUniversalClientInfo() - 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.getUniversalClientInfo() + 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.getUniversalClientInfo() + 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 a8f338a..9103d5b 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.getUniversalClientInfo().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.getUniversalClientInfo().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 297dc2b..fba3524 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 0d7df4b..7a1cab9 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.getUniversalClientInfo().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.getUniversalClientInfo().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 361b22f..1a6304d 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 - }) - - // -- 测试代码 - await 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 + }) + + // -- 测试代码 + await 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 d48ac06..f643434 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 b549a1f..b392e7e 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) { - await 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) { + await 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 b76749a..e4b8b33 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,23 +1,23 @@ -{ - "name": "uni-id-co", - "version": "1.0.38", - "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": {}, - "uni-cloud-redis": {} - }, - "cloudfunction-config": { - "keepRunningAfterReturn": false - } -} +{ + "name": "uni-id-co", + "version": "1.0.38", + "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": {}, + "uni-cloud-redis": {} + }, + "cloudfunction-config": { + "keepRunningAfterReturn": false + } +} 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 504c9b0..36945cb 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,456 +1,465 @@ -{ - "bsonType": "object", - "permission": { - "read": true, - "create": "'CREATE_UNI_ID_USERS' in auth.permission", - "update": "doc._id == auth.uid || 'UPDATE_UNI_ID_USERS' in auth.permission", - "delete": "'DELETE_UNI_ID_USERS' in auth.permission" - }, - "properties": { - "_id": { - "description": "存储文档 ID(用户 ID),系统自动生成" - }, - "ali_openid": { - "bsonType": "string", - "description": "支付宝平台openid", - "permission": { - "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": { - "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", - "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": "头像文件", - "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", - "description": "备注", - "title": "备注", - "trim": "both", - "permission": { - "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": { - "bsonType": "array", - "description": "允许登录的客户端的appid列表", - "foreignKey": "opendb-app-list.appid", - "permission": { - "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": { - "bsonType": "array", - "description": "部门ID", - "enum": { - "collection": "opendb-department", - "field": "_id as value, name as text", - "orderby": "name asc" - }, - "enumType": "tree", - "title": "部门", - "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" - } - }, - "email": { - "bsonType": "string", - "description": "邮箱地址", - "format": "email", - "title": "邮箱", - "trim": "both", - "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" - } - }, - "email_confirmed": { - "bsonType": "int", - "defaultValue": 0, - "description": "邮箱验证状态:0 未验证 1 已验证", - "enum": [{ - "text": "未验证", - "value": 0 - }, - { - "text": "已验证", - "value": 1 - } - ], - "title": "邮箱验证状态", - "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" - } - }, - "gender": { - "bsonType": "int", - "defaultValue": 0, - "description": "用户性别:0 未知 1 男性 2 女性", - "enum": [{ - "text": "未知", - "value": 0 - }, - { - "text": "男", - "value": 1 - }, - { - "text": "女", - "value": 2 - } - ], - "title": "性别", - "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" - } - }, - "invite_time": { - "bsonType": "timestamp", - "description": "受邀时间", - "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" - } - }, - "inviter_uid": { - "bsonType": "array", - "description": "用户全部上级邀请者", - "trim": "both", - "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" - } - }, - "last_login_date": { - "bsonType": "timestamp", - "description": "最后登录时间", - "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" - } - }, - "last_login_ip": { - "bsonType": "string", - "description": "最后登录时 IP 地址", - "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" - } - }, - "mobile": { - "bsonType": "string", - "description": "手机号码", - "pattern": "^\\+?[0-9-]{3,20}$", - "title": "手机号码", - "trim": "both", - "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" - } - }, - "mobile_confirmed": { - "bsonType": "int", - "defaultValue": 0, - "description": "手机号验证状态:0 未验证 1 已验证", - "enum": [{ - "text": "未验证", - "value": 0 - }, - { - "text": "已验证", - "value": 1 - } - ], - "title": "手机号验证状态", - "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" - } - }, - "my_invite_code": { - "bsonType": "string", - "description": "用户自身邀请码", - "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" - } - }, - "nickname": { - "bsonType": "string", - "description": "用户昵称", - "title": "昵称", - "trim": "both", - "permission": { - "read": true, - "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" - }, - "password_secret_version": { - "bsonType": "int", - "description": "密码使用的passwordSecret版本", - "title": "passwordSecret", - "permission": { - "read": false, - "write": false - } - }, - "realname_auth": { - "bsonType": "object", - "description": "实名认证信息", - "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" - }, - "properties": { - "auth_date": { - "bsonType": "timestamp", - "description": "认证通过时间" - }, - "auth_status": { - "bsonType": "int", - "description": "认证状态:0 未认证 1 等待认证 2 认证通过 3 认证失败", - "maximum": 3, - "minimum": 0 - }, - "contact_email": { - "bsonType": "string", - "description": "联系人邮箱" - }, - "contact_mobile": { - "bsonType": "string", - "description": "联系人手机号码" - }, - "contact_person": { - "bsonType": "string", - "description": "联系人姓名" - }, - "id_card_back": { - "bsonType": "string", - "description": "身份证反面照 URL" - }, - "id_card_front": { - "bsonType": "string", - "description": "身份证正面照 URL" - }, - "identity": { - "bsonType": "string", - "description": "身份证号码/营业执照号码" - }, - "in_hand": { - "bsonType": "string", - "description": "手持身份证照片 URL" - }, - "license": { - "bsonType": "string", - "description": "营业执照 URL" - }, - "real_name": { - "bsonType": "string", - "description": "真实姓名/企业名称" - }, - "type": { - "bsonType": "int", - "description": "用户类型:0 个人用户 1 企业用户", - "maximum": 1, - "minimum": 0 - } - }, - "required": [ - "type", - "auth_status" - ] - }, - "register_date": { - "bsonType": "timestamp", - "description": "注册时间", - "forceDefaultValue": { - "$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" - }, - "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": { - "bsonType": "array", - "description": "用户角色", - "enum": { - "collection": "uni-id-roles", - "field": "role_id as value, role_name as text" - }, - "foreignKey": "uni-id-roles.role_id", - "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" - }, - "title": "角色" - }, - "score": { - "bsonType": "int", - "description": "用户积分,积分变更记录可参考:uni-id-scores表定义", - "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" - } - }, - "status": { - "bsonType": "int", - "defaultValue": 0, - "description": "用户状态:0 正常 1 禁用 2 审核中 3 审核拒绝", - "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" - }, - "enum": [{ - "text": "正常", - "value": 0 - }, - { - "text": "禁用", - "value": 1 - }, - { - "text": "审核中", - "value": 2 - }, - { - "text": "审核拒绝", - "value": 3 - } - ], - "title": "用户状态" - }, - "token": { - "bsonType": "array", - "description": "用户token", - "permission": { - "read": "'READ_UNI_ID_USERS' in auth.permission", - "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" - } - }, - "username": { - "bsonType": "string", - "description": "用户名,不允许重复", - "title": "用户名", - "trim": "both", - "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" - } - }, - "wx_openid": { - "bsonType": "object", - "description": "微信各个平台openid", - "properties": { - "app": { - "bsonType": "string", - "description": "app平台微信openid" - }, - "mp": { - "bsonType": "string", - "description": "微信小程序平台openid" - }, - "h5": { - "bsonType": "string", - "description": "微信公众号登录openid" - }, - "web": { - "bsonType": "string", - "description": "PC页面扫码登录openid" - } - }, - "permission": { - "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": { - "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": { - "bsonType": "object", - "description": "QQ各个平台openid", - "properties": { - "app": { - "bsonType": "string", - "description": "app平台QQ openid" - }, - "mp": { - "bsonType": "string", - "description": "QQ小程序平台openid" - } - }, - "permission": { - "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": { - "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": [] +{ + "bsonType": "object", + "permission": { + "read": true, + "create": "'CREATE_UNI_ID_USERS' in auth.permission", + "update": "doc._id == auth.uid || 'UPDATE_UNI_ID_USERS' in auth.permission", + "delete": "'DELETE_UNI_ID_USERS' in auth.permission" + }, + "properties": { + "_id": { + "description": "存储文档 ID(用户 ID),系统自动生成" + }, + "ali_openid": { + "bsonType": "string", + "description": "支付宝平台openid", + "permission": { + "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": { + "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", + "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": "头像文件", + "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", + "description": "备注", + "title": "备注", + "trim": "both", + "permission": { + "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": { + "bsonType": "array", + "description": "允许登录的客户端的appid列表", + "foreignKey": "opendb-app-list.appid", + "permission": { + "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": { + "bsonType": "array", + "description": "部门ID", + "enum": { + "collection": "opendb-department", + "field": "_id as value, name as text", + "orderby": "name asc" + }, + "enumType": "tree", + "title": "部门", + "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" + } + }, + "email": { + "bsonType": "string", + "description": "邮箱地址", + "format": "email", + "title": "邮箱", + "trim": "both", + "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" + } + }, + "email_confirmed": { + "bsonType": "int", + "defaultValue": 0, + "description": "邮箱验证状态:0 未验证 1 已验证", + "enum": [{ + "text": "未验证", + "value": 0 + }, + { + "text": "已验证", + "value": 1 + } + ], + "title": "邮箱验证状态", + "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" + } + }, + "gender": { + "bsonType": "int", + "defaultValue": 0, + "description": "用户性别:0 未知 1 男性 2 女性", + "enum": [{ + "text": "未知", + "value": 0 + }, + { + "text": "男", + "value": 1 + }, + { + "text": "女", + "value": 2 + } + ], + "title": "性别", + "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" + } + }, + "invite_time": { + "bsonType": "timestamp", + "description": "受邀时间", + "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" + } + }, + "inviter_uid": { + "bsonType": "array", + "description": "用户全部上级邀请者", + "trim": "both", + "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" + } + }, + "last_login_date": { + "bsonType": "timestamp", + "description": "最后登录时间", + "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" + } + }, + "last_login_ip": { + "bsonType": "string", + "description": "最后登录时 IP 地址", + "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" + } + }, + "mobile": { + "bsonType": "string", + "description": "手机号码", + "pattern": "^\\+?[0-9-]{3,20}$", + "title": "手机号码", + "trim": "both", + "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" + } + }, + "mobile_confirmed": { + "bsonType": "int", + "defaultValue": 0, + "description": "手机号验证状态:0 未验证 1 已验证", + "enum": [{ + "text": "未验证", + "value": 0 + }, + { + "text": "已验证", + "value": 1 + } + ], + "title": "手机号验证状态", + "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" + } + }, + "my_invite_code": { + "bsonType": "string", + "description": "用户自身邀请码", + "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" + } + }, + "nickname": { + "bsonType": "string", + "description": "用户昵称", + "title": "昵称", + "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" + }, + "password_secret_version": { + "bsonType": "int", + "description": "密码使用的passwordSecret版本", + "title": "passwordSecret", + "permission": { + "read": false, + "write": false + } + }, + "realname_auth": { + "bsonType": "object", + "description": "实名认证信息", + "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" + }, + "properties": { + "auth_date": { + "bsonType": "timestamp", + "description": "认证通过时间" + }, + "auth_status": { + "bsonType": "int", + "description": "认证状态:0 未认证 1 等待认证 2 认证通过 3 认证失败", + "maximum": 3, + "minimum": 0 + }, + "contact_email": { + "bsonType": "string", + "description": "联系人邮箱" + }, + "contact_mobile": { + "bsonType": "string", + "description": "联系人手机号码" + }, + "contact_person": { + "bsonType": "string", + "description": "联系人姓名" + }, + "id_card_back": { + "bsonType": "string", + "description": "身份证反面照 URL" + }, + "id_card_front": { + "bsonType": "string", + "description": "身份证正面照 URL" + }, + "identity": { + "bsonType": "string", + "description": "身份证号码/营业执照号码" + }, + "in_hand": { + "bsonType": "string", + "description": "手持身份证照片 URL" + }, + "license": { + "bsonType": "string", + "description": "营业执照 URL" + }, + "real_name": { + "bsonType": "string", + "description": "真实姓名/企业名称" + }, + "type": { + "bsonType": "int", + "description": "用户类型:0 个人用户 1 企业用户", + "maximum": 1, + "minimum": 0 + } + }, + "required": [ + "type", + "auth_status" + ] + }, + "register_date": { + "bsonType": "timestamp", + "description": "注册时间", + "forceDefaultValue": { + "$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" + }, + "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": { + "bsonType": "array", + "description": "用户角色", + "enum": { + "collection": "uni-id-roles", + "field": "role_id as value, role_name as text" + }, + "foreignKey": "uni-id-roles.role_id", + "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" + }, + "title": "角色" + }, + "tags":{ + "bsonType": "array", + "description": "用户标签", + "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" + }, + "title": "标签" + }, + "score": { + "bsonType": "int", + "description": "用户积分,积分变更记录可参考:uni-id-scores表定义", + "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" + } + }, + "status": { + "bsonType": "int", + "defaultValue": 0, + "description": "用户状态:0 正常 1 禁用 2 审核中 3 审核拒绝", + "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" + }, + "enum": [{ + "text": "正常", + "value": 0 + }, + { + "text": "禁用", + "value": 1 + }, + { + "text": "审核中", + "value": 2 + }, + { + "text": "审核拒绝", + "value": 3 + } + ], + "title": "用户状态" + }, + "token": { + "bsonType": "array", + "description": "用户token", + "permission": { + "read": false, + "write": "'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission" + } + }, + "username": { + "bsonType": "string", + "description": "用户名,不允许重复", + "title": "用户名", + "trim": "both", + "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" + } + }, + "wx_openid": { + "bsonType": "object", + "description": "微信各个平台openid", + "properties": { + "app": { + "bsonType": "string", + "description": "app平台微信openid" + }, + "mp": { + "bsonType": "string", + "description": "微信小程序平台openid" + }, + "h5": { + "bsonType": "string", + "description": "微信公众号登录openid" + }, + "web": { + "bsonType": "string", + "description": "PC页面扫码登录openid" + } + }, + "permission": { + "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": { + "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": { + "bsonType": "object", + "description": "QQ各个平台openid", + "properties": { + "app": { + "bsonType": "string", + "description": "app平台QQ openid" + }, + "mp": { + "bsonType": "string", + "description": "QQ小程序平台openid" + } + }, + "permission": { + "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": { + "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