From 9e5ce58aee2f21414ae43c688844314f8a50b4d9 Mon Sep 17 00:00:00 2001 From: anne-lxm <1076217653@qq.com> Date: Thu, 27 Oct 2022 20:33:22 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BE=9D=E8=B5=96=E6=8F=92?= =?UTF-8?q?=E4=BB=B6/=E5=AE=89=E5=85=A8=E7=BD=91=E7=BB=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 + App.vue | 3 + pages.json | 2 +- pages/secure-network/cloud-function.vue | 156 +- pages/secure-network/cloud-object.vue | 140 +- .../secure-network-object/index.obj.js | 2 +- .../cloudfunctions/secure-network/index.js | 2 +- .../node_modules/uni-config-center/index.js | 1 + .../uni-config-center/package.json | 9 + uni_modules/uni-data-checkbox/changelog.md | 2 + .../uni-data-checkbox/uni-data-checkbox.vue | 82 +- uni_modules/uni-data-checkbox/package.json | 11 +- uni_modules/uni-easyinput/changelog.md | 6 + .../uni-easyinput/uni-easyinput.vue | 22 +- uni_modules/uni-easyinput/package.json | 11 +- uni_modules/uni-id-common/changelog.md | 26 + uni_modules/uni-id-common/package.json | 87 + uni_modules/uni-id-common/readme.md | 3 + .../common/uni-id-common/index.js | 1 + .../node_modules/uni-config-center/index.js | 1 + .../uni-config-center/package.json | 9 + .../common/uni-id-common/package.json | 16 + uni_modules/uni-id-pages/changelog.md | 83 + .../uni-id-pages/common/login-page.mixin.js | 88 + .../uni-id-pages/common/login-page.scss | 125 ++ uni_modules/uni-id-pages/common/password.js | 85 + uni_modules/uni-id-pages/common/store.js | 137 ++ .../components/cloud-image/cloud-image.vue | 79 + .../uni-id-pages-agreements.vue | 168 ++ .../uni-id-pages-avatar.vue | 166 ++ .../uni-id-pages-bind-mobile.vue | 165 ++ .../uni-id-pages-email-form.vue | 246 ++ .../uni-id-pages-fab-login.vue | 573 +++++ .../uni-id-pages-sms-form.vue | 241 ++ .../uni-id-pages-user-profile.vue | 176 ++ uni_modules/uni-id-pages/config.js | 56 + uni_modules/uni-id-pages/init.js | 99 + uni_modules/uni-id-pages/package.json | 101 + .../pages/common/webview/webview.vue | 40 + .../pages/login/login-smscode.vue | 122 + .../pages/login/login-withoutpwd.vue | 221 ++ .../pages/login/login-withpwd.vue | 173 ++ .../pages/register/register-admin.vue | 179 ++ .../pages/register/register-by-email.vue | 216 ++ .../uni-id-pages/pages/register/register.vue | 183 ++ .../uni-id-pages/pages/register/validator.js | 56 + .../pages/retrieve/retrieve-by-email.vue | 223 ++ .../uni-id-pages/pages/retrieve/retrieve.vue | 246 ++ .../userinfo/bind-mobile/bind-mobile.vue | 130 ++ .../pages/userinfo/change_pwd/change_pwd.vue | 134 ++ .../pages/userinfo/cropImage/cropImage.vue | 39 + .../userinfo/cropImage/limeClipper/README.md | 227 ++ .../cropImage/limeClipper/images/photo.svg | 19 + .../cropImage/limeClipper/images/rotate.svg | 15 + .../userinfo/cropImage/limeClipper/index.css | 160 ++ .../cropImage/limeClipper/limeClipper.vue | 816 +++++++ .../userinfo/cropImage/limeClipper/utils.js | 244 ++ .../pages/userinfo/deactivate/deactivate.vue | 119 + .../uni-id-pages/pages/userinfo/userinfo.vue | 253 +++ uni_modules/uni-id-pages/readme.md | 15 + .../uni-id-pages/static/limeClipper/photo.svg | 19 + .../static/limeClipper/rotate.svg | 15 + .../uni-id-pages/static/login/apple.png | Bin 0 -> 18205 bytes .../uni-id-pages/static/login/weixin.png | Bin 0 -> 13060 bytes .../static/uni-center/defaultAvatarUrl.png | Bin 0 -> 5947 bytes .../uni-id-pages/static/uni-center/grey.png | Bin 0 -> 6669 bytes .../static/uni-center/headers.png | Bin 0 -> 33054 bytes .../static/uni-fab-login/alipay.png | Bin 0 -> 6184 bytes .../static/uni-fab-login/apple.png | Bin 0 -> 9231 bytes .../static/uni-fab-login/douyin.png | Bin 0 -> 5911 bytes .../static/uni-fab-login/facebook.png | Bin 0 -> 4184 bytes .../static/uni-fab-login/google.png | Bin 0 -> 9718 bytes .../uni-id-pages/static/uni-fab-login/qq.png | Bin 0 -> 6441 bytes .../static/uni-fab-login/sinaweibo.png | Bin 0 -> 7920 bytes .../uni-id-pages/static/uni-fab-login/sms.png | Bin 0 -> 18264 bytes .../static/uni-fab-login/taobao.png | Bin 0 -> 12011 bytes .../static/uni-fab-login/univerify.png | Bin 0 -> 8719 bytes .../static/uni-fab-login/user.png | Bin 0 -> 8175 bytes .../static/uni-fab-login/weixin.png | Bin 0 -> 17743 bytes .../uni-id-co/common/constants.js | 90 + .../cloudfunctions/uni-id-co/common/error.js | 57 + .../cloudfunctions/uni-id-co/common/utils.js | 197 ++ .../uni-id-co/common/validator.js | 432 ++++ .../uni-id-co/config/permission.js | 78 + .../cloudfunctions/uni-id-co/index.obj.js | 585 +++++ .../cloudfunctions/uni-id-co/lang/en.js | 49 + .../cloudfunctions/uni-id-co/lang/index.js | 22 + .../cloudfunctions/uni-id-co/lang/zh-hans.js | 49 + .../cloudfunctions/uni-id-co/lib/README.md | 3 + .../lib/third-party/alipay/account/index.js | 16 + .../third-party/alipay/account/protocols.js | 10 + .../lib/third-party/alipay/alipayBase.js | 231 ++ .../lib/third-party/apple/account/index.js | 76 + .../third-party/apple/rsa-public-key-pem.js | 64 + .../uni-id-co/lib/third-party/index.js | 36 + .../lib/third-party/qq/account/index.js | 97 + .../lib/third-party/qq/account/protocol.js | 0 .../uni-id-co/lib/third-party/qq/normalize.js | 85 + .../lib/third-party/share/create-api.js | 73 + .../lib/third-party/weixin/account/index.js | 111 + .../lib/third-party/weixin/normalize.js | 95 + .../uni-id-co/lib/third-party/weixin/utils.js | 87 + .../uni-id-co/lib/utils/account.js | 130 ++ .../uni-id-co/lib/utils/captcha.js | 76 + .../uni-id-co/lib/utils/config.js | 135 ++ .../uni-id-co/lib/utils/fission.js | 192 ++ .../uni-id-co/lib/utils/login.js | 232 ++ .../uni-id-co/lib/utils/logout.js | 47 + .../uni-id-co/lib/utils/password.js | 116 + .../cloudfunctions/uni-id-co/lib/utils/qq.js | 152 ++ .../uni-id-co/lib/utils/register.js | 211 ++ .../uni-id-co/lib/utils/relate.js | 162 ++ .../cloudfunctions/uni-id-co/lib/utils/sms.js | 81 + .../uni-id-co/lib/utils/unified-login.js | 98 + .../uni-id-co/lib/utils/univerify.js | 27 + .../uni-id-co/lib/utils/update-user-info.js | 25 + .../uni-id-co/lib/utils/utils.js | 18 + .../uni-id-co/lib/utils/verify-code.js | 152 ++ .../uni-id-co/lib/utils/weixin.js | 234 ++ .../uni-id-co/middleware/access-control.js | 59 + .../uni-id-co/middleware/auth.js | 17 + .../uni-id-co/middleware/index.js | 7 + .../uni-id-co/middleware/rbac.js | 39 + .../uni-id-co/middleware/uni-id-log.js | 39 + .../uni-id-co/middleware/validate.js | 7 + .../uni-id-co/module/account/close-account.js | 16 + .../module/account/get-account-info.js | 69 + .../uni-id-co/module/account/index.js | 7 + .../module/account/reset-pwd-by-email.js | 119 + .../module/account/reset-pwd-by-sms.js | 119 + .../uni-id-co/module/account/update-pwd.js | 67 + .../uni-id-co/module/admin/add-user.js | 118 + .../uni-id-co/module/admin/index.js | 4 + .../uni-id-co/module/admin/update-user.js | 128 ++ .../module/dev/get-supported-login-type.js | 71 + .../uni-id-co/module/dev/index.js | 3 + .../uni-id-co/module/fission/accept-invite.js | 25 + .../module/fission/get-invited-user.js | 80 + .../uni-id-co/module/fission/index.js | 4 + .../uni-id-co/module/login/index.js | 20 + .../uni-id-co/module/login/login-by-alipay.js | 70 + .../uni-id-co/module/login/login-by-apple.js | 77 + .../uni-id-co/module/login/login-by-baidu.js | 9 + .../module/login/login-by-dingtalk.js | 9 + .../uni-id-co/module/login/login-by-douyin.js | 9 + .../module/login/login-by-email-code.js | 9 + .../module/login/login-by-email-link.js | 9 + .../module/login/login-by-facebook.js | 9 + .../uni-id-co/module/login/login-by-google.js | 9 + .../uni-id-co/module/login/login-by-qq.js | 164 ++ .../uni-id-co/module/login/login-by-sms.js | 99 + .../uni-id-co/module/login/login-by-taobao.js | 9 + .../module/login/login-by-toutiao.js | 9 + .../module/login/login-by-univerify.js | 69 + .../uni-id-co/module/login/login-by-weibo.js | 9 + .../module/login/login-by-weixin-mobile.js | 106 + .../uni-id-co/module/login/login-by-weixin.js | 169 ++ .../uni-id-co/module/login/login.js | 94 + .../uni-id-co/module/logout/index.js | 3 + .../uni-id-co/module/logout/logout.js | 15 + .../module/multi-end/authorize-app-login.js | 37 + .../uni-id-co/module/multi-end/index.js | 5 + .../module/multi-end/remove-authorized-app.js | 30 + .../module/multi-end/set-authorized-app.js | 36 + .../uni-id-co/module/multi-end/utils.js | 36 + .../uni-id-co/module/register/index.js | 5 + .../module/register/register-admin.js | 72 + .../module/register/register-user-by-email.js | 87 + .../module/register/register-user.js | 68 + .../uni-id-co/module/relate/bind-alipay.js | 63 + .../uni-id-co/module/relate/bind-apple.js | 62 + .../module/relate/bind-mobile-by-mp-weixin.js | 104 + .../module/relate/bind-mobile-by-sms.js | 92 + .../module/relate/bind-mobile-by-univerify.js | 70 + .../uni-id-co/module/relate/bind-qq.js | 110 + .../uni-id-co/module/relate/bind-weixin.js | 100 + .../uni-id-co/module/relate/index.js | 13 + .../uni-id-co/module/relate/unbind-alipay.js | 32 + .../uni-id-co/module/relate/unbind-apple.js | 32 + .../uni-id-co/module/relate/unbind-qq.js | 46 + .../uni-id-co/module/relate/unbind-weixin.js | 40 + .../uni-id-co/module/utils/index.js | 5 + .../uni-id-co/module/utils/refresh-token.js | 19 + .../secure-network-handshake-by-weixin.js | 73 + .../uni-id-co/module/utils/set-push-cid.js | 141 ++ .../uni-id-co/module/verify/create-captcha.js | 34 + .../uni-id-co/module/verify/index.js | 7 + .../module/verify/refresh-captcha.js | 34 + .../module/verify/send-email-code.js | 60 + .../module/verify/send-email-link.js | 12 + .../uni-id-co/module/verify/send-sms-code.js | 71 + .../uni-id-co/node_modules/.bin/semver | 15 + .../uni-id-co/node_modules/.bin/semver.cmd | 17 + .../uni-id-co/node_modules/.bin/semver.ps1 | 18 + .../buffer-equal-constant-time/.npmignore | 2 + .../buffer-equal-constant-time/.travis.yml | 4 + .../buffer-equal-constant-time/LICENSE.txt | 12 + .../buffer-equal-constant-time/README.md | 50 + .../buffer-equal-constant-time/index.js | 41 + .../buffer-equal-constant-time/package.json | 55 + .../buffer-equal-constant-time/test.js | 42 + .../ecdsa-sig-formatter/CODEOWNERS | 1 + .../node_modules/ecdsa-sig-formatter/LICENSE | 201 ++ .../ecdsa-sig-formatter/README.md | 65 + .../ecdsa-sig-formatter/package.json | 73 + .../src/ecdsa-sig-formatter.d.ts | 17 + .../src/ecdsa-sig-formatter.js | 187 ++ .../src/param-bytes-for-alg.js | 23 + .../node_modules/jsonwebtoken/CHANGELOG.md | 476 ++++ .../node_modules/jsonwebtoken/LICENSE | 21 + .../node_modules/jsonwebtoken/README.md | 375 ++++ .../node_modules/jsonwebtoken/decode.js | 30 + .../node_modules/jsonwebtoken/index.js | 8 + .../jsonwebtoken/lib/JsonWebTokenError.js | 14 + .../jsonwebtoken/lib/NotBeforeError.js | 13 + .../jsonwebtoken/lib/TokenExpiredError.js | 13 + .../jsonwebtoken/lib/psSupported.js | 3 + .../node_modules/jsonwebtoken/lib/timespan.js | 18 + .../node_modules/jsonwebtoken/package.json | 99 + .../node_modules/jsonwebtoken/sign.js | 206 ++ .../node_modules/jsonwebtoken/verify.js | 225 ++ .../uni-id-co/node_modules/jwa/LICENSE | 17 + .../uni-id-co/node_modules/jwa/README.md | 150 ++ .../uni-id-co/node_modules/jwa/index.js | 252 +++ .../uni-id-co/node_modules/jwa/package.json | 69 + .../uni-id-co/node_modules/jws/CHANGELOG.md | 34 + .../uni-id-co/node_modules/jws/LICENSE | 17 + .../uni-id-co/node_modules/jws/index.js | 22 + .../node_modules/jws/lib/data-stream.js | 55 + .../node_modules/jws/lib/sign-stream.js | 78 + .../node_modules/jws/lib/tostring.js | 10 + .../node_modules/jws/lib/verify-stream.js | 120 + .../uni-id-co/node_modules/jws/package.json | 64 + .../uni-id-co/node_modules/jws/readme.md | 255 +++ .../node_modules/lodash.includes/LICENSE | 47 + .../node_modules/lodash.includes/README.md | 18 + .../node_modules/lodash.includes/index.js | 745 +++++++ .../node_modules/lodash.includes/package.json | 69 + .../node_modules/lodash.isboolean/LICENSE | 22 + .../node_modules/lodash.isboolean/README.md | 18 + .../node_modules/lodash.isboolean/index.js | 70 + .../lodash.isboolean/package.json | 69 + .../node_modules/lodash.isinteger/LICENSE | 47 + .../node_modules/lodash.isinteger/README.md | 18 + .../node_modules/lodash.isinteger/index.js | 265 +++ .../lodash.isinteger/package.json | 69 + .../node_modules/lodash.isnumber/LICENSE | 22 + .../node_modules/lodash.isnumber/README.md | 18 + .../node_modules/lodash.isnumber/index.js | 79 + .../node_modules/lodash.isnumber/package.json | 69 + .../node_modules/lodash.isplainobject/LICENSE | 47 + .../lodash.isplainobject/README.md | 18 + .../lodash.isplainobject/index.js | 139 ++ .../lodash.isplainobject/package.json | 69 + .../node_modules/lodash.isstring/LICENSE | 22 + .../node_modules/lodash.isstring/README.md | 18 + .../node_modules/lodash.isstring/index.js | 95 + .../node_modules/lodash.isstring/package.json | 69 + .../node_modules/lodash.merge/LICENSE | 47 + .../node_modules/lodash.merge/README.md | 18 + .../node_modules/lodash.merge/index.js | 1977 +++++++++++++++++ .../node_modules/lodash.merge/package.json | 61 + .../node_modules/lodash.once/LICENSE | 47 + .../node_modules/lodash.once/README.md | 18 + .../node_modules/lodash.once/index.js | 294 +++ .../node_modules/lodash.once/package.json | 69 + .../uni-id-co/node_modules/ms/index.js | 162 ++ .../uni-id-co/node_modules/ms/license.md | 21 + .../uni-id-co/node_modules/ms/package.json | 70 + .../uni-id-co/node_modules/ms/readme.md | 59 + .../node_modules/safe-buffer/LICENSE | 21 + .../node_modules/safe-buffer/README.md | 584 +++++ .../node_modules/safe-buffer/index.d.ts | 187 ++ .../node_modules/safe-buffer/index.js | 65 + .../node_modules/safe-buffer/package.json | 78 + .../node_modules/semver/CHANGELOG.md | 39 + .../uni-id-co/node_modules/semver/LICENSE | 15 + .../uni-id-co/node_modules/semver/README.md | 412 ++++ .../uni-id-co/node_modules/semver/bin/semver | 160 ++ .../node_modules/semver/package.json | 60 + .../uni-id-co/node_modules/semver/range.bnf | 16 + .../uni-id-co/node_modules/semver/semver.js | 1483 +++++++++++++ .../node_modules/uni-captcha/LICENSE.md | 201 ++ .../node_modules/uni-captcha/fonts/font.ttf | Bin 0 -> 7080 bytes .../node_modules/uni-captcha/index.js | 1 + .../node_modules/uni-config-center/index.js | 1 + .../uni-config-center/package.json | 9 + .../uni-config-center/uni-id/config.json | 44 + .../uni-open-bridge/config.json | 12 + .../node_modules/uni-captcha/package.json | 16 + .../node_modules/uni-config-center/index.js | 1 + .../uni-config-center/package.json | 9 + .../uni-config-center/uni-id/config.json | 44 + .../uni-open-bridge/config.json | 12 + .../node_modules/uni-id-common/index.js | 1 + .../node_modules/uni-config-center/index.js | 1 + .../uni-config-center/package.json | 9 + .../uni-config-center/uni-id/config.json | 44 + .../uni-open-bridge/config.json | 12 + .../node_modules/uni-id-common/package.json | 16 + .../uni-open-bridge-common/bridge-error.js | 26 + .../uni-open-bridge-common/config.js | 95 + .../uni-open-bridge-common/consts.js | 26 + .../uni-open-bridge-common/index.js | 221 ++ .../node_modules/uni-config-center/index.js | 1 + .../uni-config-center/package.json | 9 + .../uni-config-center/uni-id/config.json | 44 + .../uni-open-bridge/config.json | 12 + .../uni-open-bridge-common/package.json | 15 + .../uni-open-bridge-common/storage.js | 117 + .../uni-open-bridge-common/uni-cloud-cache.js | 324 +++ .../uni-open-bridge-common/validator.js | 31 + .../uni-open-bridge-common/weixin-server.js | 202 ++ .../uni-id-co/package-lock.json | 148 ++ .../cloudfunctions/uni-id-co/package.json | 23 + .../database/opendb-device.schema.json | 142 ++ .../database/uni-id-device.schema.json | 83 + .../uniCloud/database/uni-id-log.schema.json | 71 + .../database/uni-id-permissions.schema.json | 52 + .../database/uni-id-roles.schema.json | 50 + .../database/uni-id-users.schema.json | 456 ++++ .../uni-open-bridge-common/changelog.md | 8 + .../uni-open-bridge-common/package.json | 84 + uni_modules/uni-open-bridge-common/readme.md | 5 + .../uni-open-bridge-common/bridge-error.js | 26 + .../common/uni-open-bridge-common/config.js | 95 + .../common/uni-open-bridge-common/consts.js | 26 + .../common/uni-open-bridge-common/index.js | 221 ++ .../node_modules/uni-config-center/index.js | 1 + .../uni-config-center/package.json | 9 + .../uni-open-bridge-common/package.json | 15 + .../common/uni-open-bridge-common/storage.js | 117 + .../uni-open-bridge-common/uni-cloud-cache.js | 324 +++ .../uni-open-bridge-common/validator.js | 31 + .../uni-open-bridge-common/weixin-server.js | 202 ++ .../database/opendb-open-data.schema.json | 19 + 336 files changed, 30355 insertions(+), 209 deletions(-) create mode 100644 uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/node_modules/uni-config-center/index.js create mode 100644 uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/node_modules/uni-config-center/package.json create mode 100644 uni_modules/uni-id-common/changelog.md create mode 100644 uni_modules/uni-id-common/package.json create mode 100644 uni_modules/uni-id-common/readme.md create mode 100644 uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/index.js create mode 100644 uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/node_modules/uni-config-center/index.js create mode 100644 uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/node_modules/uni-config-center/package.json create mode 100644 uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/package.json create mode 100644 uni_modules/uni-id-pages/changelog.md create mode 100644 uni_modules/uni-id-pages/common/login-page.mixin.js create mode 100644 uni_modules/uni-id-pages/common/login-page.scss create mode 100644 uni_modules/uni-id-pages/common/password.js create mode 100644 uni_modules/uni-id-pages/common/store.js create mode 100644 uni_modules/uni-id-pages/components/cloud-image/cloud-image.vue create mode 100644 uni_modules/uni-id-pages/components/uni-id-pages-agreements/uni-id-pages-agreements.vue create mode 100644 uni_modules/uni-id-pages/components/uni-id-pages-avatar/uni-id-pages-avatar.vue create mode 100644 uni_modules/uni-id-pages/components/uni-id-pages-bind-mobile/uni-id-pages-bind-mobile.vue create mode 100644 uni_modules/uni-id-pages/components/uni-id-pages-email-form/uni-id-pages-email-form.vue create mode 100644 uni_modules/uni-id-pages/components/uni-id-pages-fab-login/uni-id-pages-fab-login.vue create mode 100644 uni_modules/uni-id-pages/components/uni-id-pages-sms-form/uni-id-pages-sms-form.vue create mode 100644 uni_modules/uni-id-pages/components/uni-id-pages-user-profile/uni-id-pages-user-profile.vue create mode 100644 uni_modules/uni-id-pages/config.js create mode 100644 uni_modules/uni-id-pages/init.js create mode 100644 uni_modules/uni-id-pages/package.json create mode 100644 uni_modules/uni-id-pages/pages/common/webview/webview.vue create mode 100644 uni_modules/uni-id-pages/pages/login/login-smscode.vue create mode 100644 uni_modules/uni-id-pages/pages/login/login-withoutpwd.vue create mode 100644 uni_modules/uni-id-pages/pages/login/login-withpwd.vue create mode 100644 uni_modules/uni-id-pages/pages/register/register-admin.vue create mode 100644 uni_modules/uni-id-pages/pages/register/register-by-email.vue create mode 100644 uni_modules/uni-id-pages/pages/register/register.vue create mode 100644 uni_modules/uni-id-pages/pages/register/validator.js create mode 100644 uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email.vue create mode 100644 uni_modules/uni-id-pages/pages/retrieve/retrieve.vue create mode 100644 uni_modules/uni-id-pages/pages/userinfo/bind-mobile/bind-mobile.vue create mode 100644 uni_modules/uni-id-pages/pages/userinfo/change_pwd/change_pwd.vue create mode 100644 uni_modules/uni-id-pages/pages/userinfo/cropImage/cropImage.vue create mode 100644 uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/README.md create mode 100644 uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/photo.svg create mode 100644 uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/rotate.svg create mode 100644 uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/index.css create mode 100644 uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/limeClipper.vue create mode 100644 uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/utils.js create mode 100644 uni_modules/uni-id-pages/pages/userinfo/deactivate/deactivate.vue create mode 100644 uni_modules/uni-id-pages/pages/userinfo/userinfo.vue create mode 100644 uni_modules/uni-id-pages/readme.md create mode 100644 uni_modules/uni-id-pages/static/limeClipper/photo.svg create mode 100644 uni_modules/uni-id-pages/static/limeClipper/rotate.svg create mode 100644 uni_modules/uni-id-pages/static/login/apple.png create mode 100644 uni_modules/uni-id-pages/static/login/weixin.png create mode 100644 uni_modules/uni-id-pages/static/uni-center/defaultAvatarUrl.png create mode 100644 uni_modules/uni-id-pages/static/uni-center/grey.png create mode 100644 uni_modules/uni-id-pages/static/uni-center/headers.png create mode 100644 uni_modules/uni-id-pages/static/uni-fab-login/alipay.png create mode 100644 uni_modules/uni-id-pages/static/uni-fab-login/apple.png create mode 100644 uni_modules/uni-id-pages/static/uni-fab-login/douyin.png create mode 100644 uni_modules/uni-id-pages/static/uni-fab-login/facebook.png create mode 100644 uni_modules/uni-id-pages/static/uni-fab-login/google.png create mode 100644 uni_modules/uni-id-pages/static/uni-fab-login/qq.png create mode 100644 uni_modules/uni-id-pages/static/uni-fab-login/sinaweibo.png create mode 100644 uni_modules/uni-id-pages/static/uni-fab-login/sms.png create mode 100644 uni_modules/uni-id-pages/static/uni-fab-login/taobao.png create mode 100644 uni_modules/uni-id-pages/static/uni-fab-login/univerify.png create mode 100644 uni_modules/uni-id-pages/static/uni-fab-login/user.png create mode 100644 uni_modules/uni-id-pages/static/uni-fab-login/weixin.png create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/constants.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/error.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/utils.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/validator.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/config/permission.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/index.obj.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/en.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/zh-hans.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/README.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/protocols.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/alipayBase.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/account/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/rsa-public-key-pem.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/account/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/account/protocol.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/normalize.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/share/create-api.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/account/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/normalize.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/utils.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/account.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/captcha.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/config.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/fission.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/login.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/logout.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/qq.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/register.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/relate.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/sms.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/unified-login.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/univerify.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/update-user-info.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/utils.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/verify-code.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/weixin.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/access-control.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/auth.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/rbac.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/uni-id-log.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/validate.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/close-account.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/get-account-info.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-email.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-sms.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/update-pwd.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/add-user.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/update-user.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/get-supported-login-type.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/accept-invite.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/get-invited-user.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-alipay.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-apple.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-baidu.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-dingtalk.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-douyin.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-code.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-link.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-facebook.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-google.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-qq.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-sms.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-taobao.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-toutiao.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-univerify.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weibo.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin-mobile.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/logout.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/authorize-app-login.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/remove-authorized-app.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/set-authorized-app.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/utils.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-admin.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user-by-email.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-alipay.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-apple.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-mp-weixin.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-sms.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-univerify.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-qq.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-weixin.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-alipay.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-apple.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-qq.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-weixin.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/refresh-token.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/secure-network-handshake-by-weixin.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/set-push-cid.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/create-captcha.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/refresh-captcha.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-code.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-link.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-sms-code.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/.bin/semver create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/.bin/semver.cmd create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/.bin/semver.ps1 create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/.npmignore create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/.travis.yml create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/LICENSE.txt create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/README.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/test.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/CODEOWNERS create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/LICENSE create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/README.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/src/ecdsa-sig-formatter.d.ts create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/src/ecdsa-sig-formatter.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/src/param-bytes-for-alg.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/CHANGELOG.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/LICENSE create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/README.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/decode.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/JsonWebTokenError.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/NotBeforeError.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/TokenExpiredError.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/psSupported.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/timespan.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/sign.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/verify.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jwa/LICENSE create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jwa/README.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jwa/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jwa/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/CHANGELOG.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/LICENSE create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/lib/data-stream.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/lib/sign-stream.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/lib/tostring.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/lib/verify-stream.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/readme.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.includes/LICENSE create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.includes/README.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.includes/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.includes/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isboolean/LICENSE create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isboolean/README.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isboolean/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isboolean/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isinteger/LICENSE create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isinteger/README.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isinteger/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isinteger/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isnumber/LICENSE create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isnumber/README.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isnumber/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isnumber/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isplainobject/LICENSE create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isplainobject/README.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isplainobject/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isplainobject/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isstring/LICENSE create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isstring/README.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isstring/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isstring/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.merge/LICENSE create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.merge/README.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.merge/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.merge/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.once/LICENSE create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.once/README.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.once/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.once/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ms/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ms/license.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ms/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ms/readme.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/LICENSE create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/README.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/index.d.ts create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/CHANGELOG.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/LICENSE create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/README.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/bin/semver create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/range.bnf create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/semver.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/LICENSE.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/fonts/font.ttf create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/node_modules/uni-config-center/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/node_modules/uni-config-center/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/node_modules/uni-config-center/uni-id/config.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/node_modules/uni-config-center/uni-open-bridge/config.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-config-center/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-config-center/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-config-center/uni-id/config.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-config-center/uni-open-bridge/config.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-id-common/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-id-common/node_modules/uni-config-center/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-id-common/node_modules/uni-config-center/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-id-common/node_modules/uni-config-center/uni-id/config.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-id-common/node_modules/uni-config-center/uni-open-bridge/config.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-id-common/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/bridge-error.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/config.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/consts.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/node_modules/uni-config-center/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/node_modules/uni-config-center/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/node_modules/uni-config-center/uni-id/config.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/node_modules/uni-config-center/uni-open-bridge/config.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/storage.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/uni-cloud-cache.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/validator.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/weixin-server.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package-lock.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/database/opendb-device.schema.json create mode 100644 uni_modules/uni-id-pages/uniCloud/database/uni-id-device.schema.json create mode 100644 uni_modules/uni-id-pages/uniCloud/database/uni-id-log.schema.json create mode 100644 uni_modules/uni-id-pages/uniCloud/database/uni-id-permissions.schema.json create mode 100644 uni_modules/uni-id-pages/uniCloud/database/uni-id-roles.schema.json create mode 100644 uni_modules/uni-id-pages/uniCloud/database/uni-id-users.schema.json create mode 100644 uni_modules/uni-open-bridge-common/changelog.md create mode 100644 uni_modules/uni-open-bridge-common/package.json create mode 100644 uni_modules/uni-open-bridge-common/readme.md create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/bridge-error.js create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/config.js create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/consts.js create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/index.js create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/node_modules/uni-config-center/index.js create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/node_modules/uni-config-center/package.json create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/package.json create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/storage.js create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/uni-cloud-cache.js create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/validator.js create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/weixin-server.js create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/database/opendb-open-data.schema.json diff --git a/.gitignore b/.gitignore index 09c0a23..36e7207 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ /unpackage/ /vue.config.js /manifest.json +uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/node_modules/uni-config-center/uni-id/config.json +manifest.json +uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/node_modules/uni-config-center/uni-id/config.json diff --git a/App.vue b/App.vue index f40b2de..7142519 100644 --- a/App.vue +++ b/App.vue @@ -3,6 +3,9 @@ export default { onLaunch: async function() { console.log('App Launch') + // #ifdef MP-WEIXIN + uniCloud.initSecureNetworkByWeixin() + // #endif checkUpdate() //更新升级 }, mounted() { diff --git a/pages.json b/pages.json index 0188204..a5e596e 100644 --- a/pages.json +++ b/pages.json @@ -211,7 +211,7 @@ "navigationBarTitleText": "版本信息查看" } } - ], +], "tabBar": { "color": "#7A7E83", "selectedColor": "#1296db", diff --git a/pages/secure-network/cloud-function.vue b/pages/secure-network/cloud-function.vue index baea07f..486159c 100644 --- a/pages/secure-network/cloud-function.vue +++ b/pages/secure-network/cloud-function.vue @@ -1,90 +1,90 @@ diff --git a/pages/secure-network/cloud-object.vue b/pages/secure-network/cloud-object.vue index cde071c..7c81aba 100644 --- a/pages/secure-network/cloud-object.vue +++ b/pages/secure-network/cloud-object.vue @@ -1,82 +1,82 @@ diff --git a/uniCloud-aliyun/cloudfunctions/secure-network-object/index.obj.js b/uniCloud-aliyun/cloudfunctions/secure-network-object/index.obj.js index bb182aa..7ecd4d2 100644 --- a/uniCloud-aliyun/cloudfunctions/secure-network-object/index.obj.js +++ b/uniCloud-aliyun/cloudfunctions/secure-network-object/index.obj.js @@ -10,7 +10,7 @@ module.exports = { console.log(secretType); - if (methodName === 'get' && (secretType !== 'both' || secretType !== 'response')) { + if (secretType !== 'both' ) { throw new Error('secretType invalid') // 拒绝返回有效数据 } }, diff --git a/uniCloud-aliyun/cloudfunctions/secure-network/index.js b/uniCloud-aliyun/cloudfunctions/secure-network/index.js index 6a0979e..8396a41 100644 --- a/uniCloud-aliyun/cloudfunctions/secure-network/index.js +++ b/uniCloud-aliyun/cloudfunctions/secure-network/index.js @@ -7,7 +7,7 @@ exports.main = async (event, context) => { const secretType = context.secretType // secretType 是客户端调用 uniCloud.callFunction 传递的参数 secretType - if (secretType !== 'both' || secretType !== 'response') { + if (secretType !== 'both') { throw new Error('secretType invalid') // 拒绝返回有效数据 } diff --git a/uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/node_modules/uni-config-center/index.js b/uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/node_modules/uni-config-center/index.js new file mode 100644 index 0000000..e14fb3b --- /dev/null +++ b/uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/node_modules/uni-config-center/index.js @@ -0,0 +1 @@ +"use strict";var t=require("fs"),r=require("path");function e(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var n=e(t),o=e(r),i="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};var u=function(t){var r={exports:{}};return t(r,r.exports),r.exports}((function(t,r){var e="__lodash_hash_undefined__",n=9007199254740991,o="[object Arguments]",u="[object Function]",c="[object Object]",a=/^\[object .+?Constructor\]$/,f=/^(?:0|[1-9]\d*)$/,s={};s["[object Float32Array]"]=s["[object Float64Array]"]=s["[object Int8Array]"]=s["[object Int16Array]"]=s["[object Int32Array]"]=s["[object Uint8Array]"]=s["[object Uint8ClampedArray]"]=s["[object Uint16Array]"]=s["[object Uint32Array]"]=!0,s[o]=s["[object Array]"]=s["[object ArrayBuffer]"]=s["[object Boolean]"]=s["[object DataView]"]=s["[object Date]"]=s["[object Error]"]=s[u]=s["[object Map]"]=s["[object Number]"]=s[c]=s["[object RegExp]"]=s["[object Set]"]=s["[object String]"]=s["[object WeakMap]"]=!1;var l="object"==typeof i&&i&&i.Object===Object&&i,h="object"==typeof self&&self&&self.Object===Object&&self,p=l||h||Function("return this")(),_=r&&!r.nodeType&&r,v=_&&t&&!t.nodeType&&t,d=v&&v.exports===_,y=d&&l.process,g=function(){try{var t=v&&v.require&&v.require("util").types;return t||y&&y.binding&&y.binding("util")}catch(t){}}(),b=g&&g.isTypedArray;function j(t,r,e){switch(e.length){case 0:return t.call(r);case 1:return t.call(r,e[0]);case 2:return t.call(r,e[0],e[1]);case 3:return t.call(r,e[0],e[1],e[2])}return t.apply(r,e)}var w,O,m,A=Array.prototype,z=Function.prototype,M=Object.prototype,x=p["__core-js_shared__"],C=z.toString,F=M.hasOwnProperty,U=(w=/[^.]+$/.exec(x&&x.keys&&x.keys.IE_PROTO||""))?"Symbol(src)_1."+w:"",S=M.toString,I=C.call(Object),P=RegExp("^"+C.call(F).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),T=d?p.Buffer:void 0,q=p.Symbol,E=p.Uint8Array,$=T?T.allocUnsafe:void 0,D=(O=Object.getPrototypeOf,m=Object,function(t){return O(m(t))}),k=Object.create,B=M.propertyIsEnumerable,N=A.splice,L=q?q.toStringTag:void 0,R=function(){try{var t=_t(Object,"defineProperty");return t({},"",{}),t}catch(t){}}(),G=T?T.isBuffer:void 0,V=Math.max,W=Date.now,H=_t(p,"Map"),J=_t(Object,"create"),K=function(){function t(){}return function(r){if(!Mt(r))return{};if(k)return k(r);t.prototype=r;var e=new t;return t.prototype=void 0,e}}();function Q(t){var r=-1,e=null==t?0:t.length;for(this.clear();++r-1},X.prototype.set=function(t,r){var e=this.__data__,n=nt(e,t);return n<0?(++this.size,e.push([t,r])):e[n][1]=r,this},Y.prototype.clear=function(){this.size=0,this.__data__={hash:new Q,map:new(H||X),string:new Q}},Y.prototype.delete=function(t){var r=pt(this,t).delete(t);return this.size-=r?1:0,r},Y.prototype.get=function(t){return pt(this,t).get(t)},Y.prototype.has=function(t){return pt(this,t).has(t)},Y.prototype.set=function(t,r){var e=pt(this,t),n=e.size;return e.set(t,r),this.size+=e.size==n?0:1,this},Z.prototype.clear=function(){this.__data__=new X,this.size=0},Z.prototype.delete=function(t){var r=this.__data__,e=r.delete(t);return this.size=r.size,e},Z.prototype.get=function(t){return this.__data__.get(t)},Z.prototype.has=function(t){return this.__data__.has(t)},Z.prototype.set=function(t,r){var e=this.__data__;if(e instanceof X){var n=e.__data__;if(!H||n.length<199)return n.push([t,r]),this.size=++e.size,this;e=this.__data__=new Y(n)}return e.set(t,r),this.size=e.size,this};var it,ut=function(t,r,e){for(var n=-1,o=Object(t),i=e(t),u=i.length;u--;){var c=i[it?u:++n];if(!1===r(o[c],c,o))break}return t};function ct(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":L&&L in Object(t)?function(t){var r=F.call(t,L),e=t[L];try{t[L]=void 0;var n=!0}catch(t){}var o=S.call(t);n&&(r?t[L]=e:delete t[L]);return o}(t):function(t){return S.call(t)}(t)}function at(t){return xt(t)&&ct(t)==o}function ft(t){return!(!Mt(t)||function(t){return!!U&&U in t}(t))&&(At(t)?P:a).test(function(t){if(null!=t){try{return C.call(t)}catch(t){}try{return t+""}catch(t){}}return""}(t))}function st(t){if(!Mt(t))return function(t){var r=[];if(null!=t)for(var e in Object(t))r.push(e);return r}(t);var r=dt(t),e=[];for(var n in t)("constructor"!=n||!r&&F.call(t,n))&&e.push(n);return e}function lt(t,r,e,n,o){t!==r&&ut(r,(function(i,u){if(o||(o=new Z),Mt(i))!function(t,r,e,n,o,i,u){var a=yt(t,e),f=yt(r,e),s=u.get(f);if(s)return void rt(t,e,s);var l=i?i(a,f,e+"",t,r,u):void 0,h=void 0===l;if(h){var p=wt(f),_=!p&&mt(f),v=!p&&!_&&Ct(f);l=f,p||_||v?wt(a)?l=a:xt(j=a)&&Ot(j)?l=function(t,r){var e=-1,n=t.length;r||(r=Array(n));for(;++e-1&&t%1==0&&t0){if(++r>=800)return arguments[0]}else r=0;return t.apply(void 0,arguments)}}(R?function(t,r){return R(t,"toString",{configurable:!0,enumerable:!1,value:(e=r,function(){return e}),writable:!0});var e}:It);function bt(t,r){return t===r||t!=t&&r!=r}var jt=at(function(){return arguments}())?at:function(t){return xt(t)&&F.call(t,"callee")&&!B.call(t,"callee")},wt=Array.isArray;function Ot(t){return null!=t&&zt(t.length)&&!At(t)}var mt=G||function(){return!1};function At(t){if(!Mt(t))return!1;var r=ct(t);return r==u||"[object GeneratorFunction]"==r||"[object AsyncFunction]"==r||"[object Proxy]"==r}function zt(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=n}function Mt(t){var r=typeof t;return null!=t&&("object"==r||"function"==r)}function xt(t){return null!=t&&"object"==typeof t}var Ct=b?function(t){return function(r){return t(r)}}(b):function(t){return xt(t)&&zt(t.length)&&!!s[ct(t)]};function Ft(t){return Ot(t)?tt(t,!0):st(t)}var Ut,St=(Ut=function(t,r,e){lt(t,r,e)},ht((function(t,r){var e=-1,n=r.length,o=n>1?r[n-1]:void 0,i=n>2?r[2]:void 0;for(o=Ut.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,r,e){if(!Mt(e))return!1;var n=typeof r;return!!("number"==n?Ot(e)&&vt(r,e.length):"string"==n&&r in e)&&bt(e[r],t)}(r[0],r[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++ec.call(t,r);class f{constructor({pluginId:t,defaultConfig:r={},customMerge:e,root:n}){this.pluginId=t,this.defaultConfig=r,this.pluginConfigPath=o.default.resolve(n||__dirname,t),this.customMerge=e,this._config=void 0}resolve(t){return o.default.resolve(this.pluginConfigPath,t)}hasFile(t){return n.default.existsSync(this.resolve(t))}requireFile(t){try{return require(this.resolve(t))}catch(t){if("MODULE_NOT_FOUND"===t.code)return;throw t}}_getUserConfig(){return this.requireFile("config.json")}config(t,r){this._config||(this._config=(this.customMerge||u)(this.defaultConfig,this._getUserConfig()));let e=this._config;return t?function(t,r,e){if("number"==typeof r)return t[r];if("symbol"==typeof r)return a(t,r)?t[r]:e;const n="string"!=typeof(o=r)?o:o.split(".").reduce(((t,r)=>(r.split(/\[([^}]+)\]/g).forEach((r=>r&&t.push(r))),t)),[]);var o;let i=t;for(let t=0;t diff --git a/uni_modules/uni-id-pages/components/uni-id-pages-avatar/uni-id-pages-avatar.vue b/uni_modules/uni-id-pages/components/uni-id-pages-avatar/uni-id-pages-avatar.vue new file mode 100644 index 0000000..3c20fb2 --- /dev/null +++ b/uni_modules/uni-id-pages/components/uni-id-pages-avatar/uni-id-pages-avatar.vue @@ -0,0 +1,166 @@ + + + + + diff --git a/uni_modules/uni-id-pages/components/uni-id-pages-bind-mobile/uni-id-pages-bind-mobile.vue b/uni_modules/uni-id-pages/components/uni-id-pages-bind-mobile/uni-id-pages-bind-mobile.vue new file mode 100644 index 0000000..c2c5dde --- /dev/null +++ b/uni_modules/uni-id-pages/components/uni-id-pages-bind-mobile/uni-id-pages-bind-mobile.vue @@ -0,0 +1,165 @@ + + + + + diff --git a/uni_modules/uni-id-pages/components/uni-id-pages-email-form/uni-id-pages-email-form.vue b/uni_modules/uni-id-pages/components/uni-id-pages-email-form/uni-id-pages-email-form.vue new file mode 100644 index 0000000..e95652b --- /dev/null +++ b/uni_modules/uni-id-pages/components/uni-id-pages-email-form/uni-id-pages-email-form.vue @@ -0,0 +1,246 @@ + + + + + diff --git a/uni_modules/uni-id-pages/components/uni-id-pages-fab-login/uni-id-pages-fab-login.vue b/uni_modules/uni-id-pages/components/uni-id-pages-fab-login/uni-id-pages-fab-login.vue new file mode 100644 index 0000000..f6073c4 --- /dev/null +++ b/uni_modules/uni-id-pages/components/uni-id-pages-fab-login/uni-id-pages-fab-login.vue @@ -0,0 +1,573 @@ + + + + diff --git a/uni_modules/uni-id-pages/components/uni-id-pages-sms-form/uni-id-pages-sms-form.vue b/uni_modules/uni-id-pages/components/uni-id-pages-sms-form/uni-id-pages-sms-form.vue new file mode 100644 index 0000000..484a9ee --- /dev/null +++ b/uni_modules/uni-id-pages/components/uni-id-pages-sms-form/uni-id-pages-sms-form.vue @@ -0,0 +1,241 @@ + + + + + diff --git a/uni_modules/uni-id-pages/components/uni-id-pages-user-profile/uni-id-pages-user-profile.vue b/uni_modules/uni-id-pages/components/uni-id-pages-user-profile/uni-id-pages-user-profile.vue new file mode 100644 index 0000000..703f484 --- /dev/null +++ b/uni_modules/uni-id-pages/components/uni-id-pages-user-profile/uni-id-pages-user-profile.vue @@ -0,0 +1,176 @@ + + + + + diff --git a/uni_modules/uni-id-pages/config.js b/uni_modules/uni-id-pages/config.js new file mode 100644 index 0000000..d7bd4a0 --- /dev/null +++ b/uni_modules/uni-id-pages/config.js @@ -0,0 +1,56 @@ +export default { + //调试模式 + "debug": false, + /* + 登录类型 未列举到的或运行环境不支持的,将被自动隐藏。 + 如果需要在不同平台有不同的配置,直接用条件编译即可 + */ + "isAdmin": false, // 区分管理端与用户端 + "loginTypes": [ + // "qq", + // "xiaomi", + // "sinaweibo", + // "taobao", + // "facebook", + // "google", + // "alipay", + // "douyin", + + // #ifdef APP + "univerify", + // #endif + "weixin", + "username", + // #ifdef APP + "apple", + // #endif + "smsCode" + ], + //政策协议 + "agreements": { + "serviceUrl": "https://xxx", //用户服务协议链接 + "privacyUrl": "https://xxx", //隐私政策条款链接 + // 哪些场景下显示,1.注册(包括登录并注册,如:微信登录、苹果登录、短信验证码登录)、2.登录(如:用户名密码登录) + "scope": [ + 'register', 'login' + ] + }, + // 提供各类服务接入(如微信登录服务)的应用id + "appid": { + "weixin": { + // 微信公众号的appid,来源:登录微信公众号(https://mp.weixin.qq.com)-> 设置与开发 -> 基本配置 -> 公众号开发信息 -> AppID + "h5": "xxxxxx", + // 微信开放平台的appid,来源:登录微信开放平台(https://open.weixin.qq.com) -> 管理中心 -> 网站应用 -> 选择对应的应用名称,点击查看 -> AppID + "web": "xxxxxx" + } + }, + /** + * 密码强度 + * super(超强:密码必须包含大小写字母、数字和特殊符号,长度范围:8-16位之间) + * strong(强: 密密码必须包含字母、数字和特殊符号,长度范围:8-16位之间) + * medium (中:密码必须为字母、数字和特殊符号任意两种的组合,长度范围:8-16位之间) + * weak(弱:密码必须包含字母和数字,长度范围:6-16位之间) + * 为空或false则不验证密码强度 + */ + "passwordStrength":"medium" +} diff --git a/uni_modules/uni-id-pages/init.js b/uni_modules/uni-id-pages/init.js new file mode 100644 index 0000000..fa8df81 --- /dev/null +++ b/uni_modules/uni-id-pages/init.js @@ -0,0 +1,99 @@ +// 导入配置 +import config from '@/uni_modules/uni-id-pages/config.js'; +// uni-id的云对象 +const uniIdCo = uniCloud.importObject("uni-id-co", { + customUI: true +}) +// 用户配置的登录方式、是否打开调试模式 +const { + loginTypes, + debug +} = config + +export default async function() { + + // 有打开调试模式的情况下 + if (debug) { + // 1. 检查本地uni-id-pages中配置的登录方式,服务器端是否已经配置正确。否则提醒并引导去配置 + //调用云对象,获取服务端已正确配置的登录方式 + let { + supportedLoginType + } = await uniIdCo.getSupportedLoginType() + console.log("supportedLoginType: " + JSON.stringify(supportedLoginType)); + //登录方式,服务端和客户端的映射关系 + let data = { + smsCode: 'mobile-code', + univerify: 'univerify', + username: 'username-password', + weixin: 'weixin', + qq: 'qq', + xiaomi: 'xiaomi', + sinaweibo: 'sinaweibo', + taobao: 'taobao', + facebook: 'facebook', + google: 'google', + alipay: 'alipay', + apple: "apple" + } + //遍历客户端配置的登录方式,与服务端比对。并在错误时抛出错误提示 + let list = loginTypes.filter(type => !supportedLoginType.includes(data[type])) + if (list.length) { + console.error( + `错误:前端启用的登录方式:${list.join(',')};没有在服务端完成配置。配置文件路径:"/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json"` + ); + } + } + + // #ifdef APP-PLUS + //如果uni-id-pages配置的登录功能有一键登录,有则执行预登录(异步) + if (loginTypes.includes('univerify')) { + uni.preLogin({ + provider: 'univerify', + complete: e => { + console.log(e); + } + }) + } + // #endif + + //3. 绑定clientDB错误事件 + // clientDB对象 + const db = uniCloud.database() + db.on('error', onDBError) + //clientDB的错误提示 + function onDBError({ + code, // 错误码详见https://uniapp.dcloud.net.cn/uniCloud/clientdb?id=returnvalue + message + }) { + console.error('onDBError', { + code, + message + }); + } + // 解绑clientDB错误事件 + //db.off('error', onDBError) + + + //4. 同步客户端push_clientid至device表 + if (uniCloud.onRefreshToken) { + uniCloud.onRefreshToken(() => { + console.log('onRefreshToken'); + if (uni.getPushClientId) { + uni.getPushClientId({ + success: async function(e) { + console.log(e) + let pushClientId = e.cid + console.log(pushClientId); + let res = await uniIdCo.setPushCid({ + pushClientId + }) + console.log('getPushClientId', res); + }, + fail(e) { + console.log(e) + } + }) + } + }) + } +} diff --git a/uni_modules/uni-id-pages/package.json b/uni_modules/uni-id-pages/package.json new file mode 100644 index 0000000..fa04708 --- /dev/null +++ b/uni_modules/uni-id-pages/package.json @@ -0,0 +1,101 @@ +{ + "id": "uni-id-pages", + "displayName": "uni-id-pages", + "version": "1.0.27", + "description": "云端一体简单、统一、可扩展的用户中心页面模版", + "keywords": [ + "用户管理", + "用户中心", + "短信验证码", + "login", + "登录" + ], + "repository": "https://gitcode.net/dcloud/hello_uni-id-pages", + "engines": { + "HBuilderX": "^3.4.17" + }, + "dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "", + "type": "unicloud-template-page" + }, + "uni_modules": { + "dependencies": [ + "uni-captcha", + "uni-config-center", + "uni-data-checkbox", + "uni-easyinput", + "uni-forms", + "uni-icons", + "uni-id-common", + "uni-list", + "uni-load-more", + "uni-popup", + "uni-scss", + "uni-transition", + "uni-open-bridge-common" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "Vue": { + "vue2": "y", + "vue3": "y" + }, + "App": { + "app-vue": "y", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "u", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + }, + "dependencies": { + } +} diff --git a/uni_modules/uni-id-pages/pages/common/webview/webview.vue b/uni_modules/uni-id-pages/pages/common/webview/webview.vue new file mode 100644 index 0000000..83d07ec --- /dev/null +++ b/uni_modules/uni-id-pages/pages/common/webview/webview.vue @@ -0,0 +1,40 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/login/login-smscode.vue b/uni_modules/uni-id-pages/pages/login/login-smscode.vue new file mode 100644 index 0000000..df67bc4 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/login/login-smscode.vue @@ -0,0 +1,122 @@ + + + + diff --git a/uni_modules/uni-id-pages/pages/login/login-withoutpwd.vue b/uni_modules/uni-id-pages/pages/login/login-withoutpwd.vue new file mode 100644 index 0000000..868776c --- /dev/null +++ b/uni_modules/uni-id-pages/pages/login/login-withoutpwd.vue @@ -0,0 +1,221 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/login/login-withpwd.vue b/uni_modules/uni-id-pages/pages/login/login-withpwd.vue new file mode 100644 index 0000000..ca6fc5d --- /dev/null +++ b/uni_modules/uni-id-pages/pages/login/login-withpwd.vue @@ -0,0 +1,173 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/register/register-admin.vue b/uni_modules/uni-id-pages/pages/register/register-admin.vue new file mode 100644 index 0000000..71690d9 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/register/register-admin.vue @@ -0,0 +1,179 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/register/register-by-email.vue b/uni_modules/uni-id-pages/pages/register/register-by-email.vue new file mode 100644 index 0000000..f45dc57 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/register/register-by-email.vue @@ -0,0 +1,216 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/register/register.vue b/uni_modules/uni-id-pages/pages/register/register.vue new file mode 100644 index 0000000..097d12f --- /dev/null +++ b/uni_modules/uni-id-pages/pages/register/register.vue @@ -0,0 +1,183 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/register/validator.js b/uni_modules/uni-id-pages/pages/register/validator.js new file mode 100644 index 0000000..9173e3c --- /dev/null +++ b/uni_modules/uni-id-pages/pages/register/validator.js @@ -0,0 +1,56 @@ +import passwordMod from '@/uni_modules/uni-id-pages/common/password.js' +export default { + "username": { + "rules": [{ + required: true, + errorMessage: '请输入用户名', + }, + { + minLength: 3, + maxLength: 32, + errorMessage: '用户名长度在 {minLength} 到 {maxLength} 个字符', + }, + { + validateFunction: function(rule, value, data, callback) { + // console.log(value); + if (/^1\d{10}$/.test(value) || /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/.test(value)) { + callback('用户名不能是:手机号或邮箱') + }; + if (/^\d+$/.test(value)) { + callback('用户名不能为纯数字') + }; + if(/[\u4E00-\u9FA5\uF900-\uFA2D]{1,}/.test(value)){ + callback('用户名不能包含中文') + } + return true + } + } + ], + "label": "用户名" + }, + "nickname": { + "rules": [{ + minLength: 3, + maxLength: 32, + errorMessage: '昵称长度在 {minLength} 到 {maxLength} 个字符', + }, + { + validateFunction: function(rule, value, data, callback) { + // console.log(value); + if (/^1\d{10}$/.test(value) || /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/.test(value)) { + callback('昵称不能是:手机号或邮箱') + }; + if (/^\d+$/.test(value)) { + callback('昵称不能为纯数字') + }; + if(/[\u4E00-\u9FA5\uF900-\uFA2D]{1,}/.test(value)){ + callback('昵称不能包含中文') + } + return true + } + } + ], + "label": "昵称" + }, + ...passwordMod.getPwdRules() +} diff --git a/uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email.vue b/uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email.vue new file mode 100644 index 0000000..71ca8fe --- /dev/null +++ b/uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email.vue @@ -0,0 +1,223 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/retrieve/retrieve.vue b/uni_modules/uni-id-pages/pages/retrieve/retrieve.vue new file mode 100644 index 0000000..74ed220 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/retrieve/retrieve.vue @@ -0,0 +1,246 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/userinfo/bind-mobile/bind-mobile.vue b/uni_modules/uni-id-pages/pages/userinfo/bind-mobile/bind-mobile.vue new file mode 100644 index 0000000..15d68eb --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/bind-mobile/bind-mobile.vue @@ -0,0 +1,130 @@ + + + + + diff --git a/uni_modules/uni-id-pages/pages/userinfo/change_pwd/change_pwd.vue b/uni_modules/uni-id-pages/pages/userinfo/change_pwd/change_pwd.vue new file mode 100644 index 0000000..d38c429 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/change_pwd/change_pwd.vue @@ -0,0 +1,134 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/cropImage.vue b/uni_modules/uni-id-pages/pages/userinfo/cropImage/cropImage.vue new file mode 100644 index 0000000..0a9e701 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/cropImage.vue @@ -0,0 +1,39 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/README.md b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/README.md new file mode 100644 index 0000000..9219f81 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/README.md @@ -0,0 +1,227 @@ +> 插件来源:[https://ext.dcloud.net.cn/plugin?id=3594](https://ext.dcloud.net.cn/plugin?id=3594) +##### 以下是作者写的插件介绍: + +# Clipper 图片裁剪 +> uniapp 图片裁剪,可用于图片头像等裁剪处理 +> [查看更多](http://liangei.gitee.io/limeui/#/clipper)
+> Q群:458377637 + + +## 平台兼容 + +| H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ 小程序 | App | +| --- | ---------- | ------------ | ---------- | ---------- | --------- | --- | +| √ | √ | √ | 未测 | √ | √ | √ | + + +## 代码演示 +### 基本用法 +`@success` 事件点击 👉 **确定** 后会返回生成的图片信息,包含 `url`、`width`、`height` + +```html + + + +``` + +```js +// 非uni_modules引入 +import lClipper from '@/components/lime-clipper/' +// uni_modules引入 +import lClipper from '@/uni_modules/lime-clipper/components/lime-clipper/' +export default { + components: {lClipper}, + data() { + return { + show: false, + url: '', + } + } +} +``` + + +### 传入图片 +`image-url`可传入**相对路径**、**临时路径**、**本地路径**、**网络图片**
+ +* **当为网络地址时** +* H5:👉 需要解决跨域问题。
+* 小程序:👉 需要配置 downloadFile 域名
+ + +```html + + + +``` + +```js +export default { + components: {lClipper}, + data() { + return { + imageUrl: 'https://img12.360buyimg.com/pop/s1180x940_jfs/t1/97205/26/1142/87801/5dbac55aEf795d962/48a4d7a63ff80b8b.jpg', + show: false, + url: '', + } + } +} +``` + + +### 确定按钮颜色 +样式变量名:`--l-clipper-confirm-color` +可放到全局样式的 `page` 里或节点的 `style` +```html + +``` +```css +// css 中为组件设置 CSS 变量 +.clipper { + --l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24) +} +// 全局 +page { + --l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24) +} +``` + + +### 使用插槽 +共五个插槽 `cancel` 取消按钮、 `photo` 选择图片按钮、 `rotate` 旋转按钮、 `confirm` 确定按钮和默认插槽。 + +```html + + + + 取消 + 选择图片 + 旋转 + 确定 + + + 显示取消按钮 + + + 显示选择图片按钮 + + + 显示旋转按钮 + + + 显示确定按钮 + + + 锁定裁剪框宽度 + + + 锁定裁剪框高度 + + + 锁定裁剪框比例 + + + 限制移动范围 + + + 禁止缩放 + + + 禁止旋转 + + + + + +``` + +```js +export default { + components: {lClipper}, + data() { + return { + show: false, + url: '', + isLockWidth: false, + isLockHeight: false, + isLockRatio: true, + isLimitMove: false, + isDisableScale: false, + isDisableRotate: false, + isShowCancelBtn: true, + isShowPhotoBtn: true, + isShowRotateBtn: true, + isShowConfirmBtn: true + } + } +} +``` + + +## API + +### Props + +| 参数 | 说明 | 类型 | 默认值 | +| ------------- | ------------ | ---------------- | ------------ | +| image-url | 图片路径 | string | | +| quality | 图片的质量,取值范围为 [0, 1],不在范围内时当作1处理 | number | `1` | +| source | `{album: '从相册中选择'}`key为图片来源类型,value为选项说明 | Object | | +| width | 裁剪框宽度,单位为 `rpx` | number | `400` | +| height | 裁剪框高度 | number | `400` | +| min-width | 裁剪框最小宽度 | number | `200` | +| min-height |裁剪框最小高度 | number | `200` | +| max-width | 裁剪框最大宽度 | number | `600` | +| max-height | 裁剪框最大宽度 | number | `600` | +| min-ratio | 图片最小缩放比 | number | `0.5` | +| max-ratio | 图片最大缩放比 | number | `2` | +| rotate-angle | 旋转按钮每次旋转的角度 | number | `90` | +| scale-ratio | 生成图片相对于裁剪框的比例, **比例越高生成图片越清晰** | number | `1` | +| is-lock-width | 是否锁定裁剪框宽度 | boolean | `false` | +| is-lock-height | 是否锁定裁剪框高度上 | boolean | `false` | +| is-lock-ratio | 是否锁定裁剪框比例 | boolean | `true` | +| is-disable-scale | 是否禁止缩放 | boolean | `false` | +| is-disable-rotate | 是否禁止旋转 | boolean | `false` | +| is-limit-move | 是否限制移动范围 | boolean | `false` | +| is-show-photo-btn | 是否显示选择图片按钮 | boolean | `true` | +| is-show-rotate-btn | 是否显示转按钮 | boolean | `true` | +| is-show-confirm-btn | 是否显示确定按钮 | boolean | `true` | +| is-show-cancel-btn | 是否显示关闭按钮 | boolean | `true` | + + + +### 事件 Events + +| 事件名 | 说明 | 回调 | +| ------- | ------------ | -------------- | +| success | 生成图片成功 | {`width`, `height`, `url`} | +| fail | 生成图片失败 | `error` | +| cancel | 关闭 | `false` | +| ready | 图片加载完成 | {`width`, `height`, `path`, `orientation`, `type`} | +| change | 图片大小改变时触发 | {`width`, `height`} | +| rotate | 图片旋转时触发 | `angle` | + +## 常见问题 +> 1、H5端使用网络图片需要解决跨域问题。
+> 2、小程序使用网络图片需要去公众平台增加下载白名单!二级域名也需要配!
+> 3、H5端生成图片是base64,有时显示只有一半可以使用原生标签``
+> 4、IOS APP 请勿使用HBX2.9.3.20201014的版本!这个版本无法生成图片。
+> 5、APP端无成功反馈、也无失败反馈时,请更新基座和HBX。
+ + +## 打赏 +如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
+![输入图片说明](https://images.gitee.com/uploads/images/2020/1122/222521_bb543f96_518581.jpeg "微信图片编辑_20201122220352.jpg") \ No newline at end of file diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/photo.svg b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/photo.svg new file mode 100644 index 0000000..7b4b590 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/photo.svg @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/rotate.svg b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/rotate.svg new file mode 100644 index 0000000..0143706 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/rotate.svg @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/index.css b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/index.css new file mode 100644 index 0000000..ce542bf --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/index.css @@ -0,0 +1,160 @@ +.flex-auto { + flex: auto; +} +.bg-transparent { + background-color: rgba(0,0,0,0.9); + transition-duration: 0.35s; +} +.l-clipper { + width: 100vw; + height: calc(100vh - var(--window-top)); + background-color: rgba(0,0,0,0.9); + position: fixed; + top: var(--window-top); + left: 0; + z-index: 1; +} +.l-clipper-mask { + position: relative; + z-index: 2; + pointer-events: none; +} +.l-clipper__content { + pointer-events: none; + position: absolute; + border: 1rpx solid rgba(255,255,255,0.3); + box-sizing: border-box; + box-shadow: rgba(0,0,0,0.5) 0 0 0 80vh; + background: transparent; +} +.l-clipper__content::before, +.l-clipper__content::after { + content: ''; + position: absolute; + border: 1rpx dashed rgba(255,255,255,0.3); +} +.l-clipper__content::before { + width: 100%; + top: 33.33%; + height: 33.33%; + border-left: none; + border-right: none; +} +.l-clipper__content::after { + width: 33.33%; + left: 33.33%; + height: 100%; + border-top: none; + border-bottom: none; +} +.l-clipper__edge { + position: absolute; + width: 34rpx; + height: 34rpx; + border: 6rpx solid #fff; + pointer-events: auto; +} +.l-clipper__edge::before { + content: ''; + position: absolute; + width: 40rpx; + height: 40rpx; + background-color: transparent; +} +.l-clipper__edge:nth-child(1) { + left: -6rpx; + top: -6rpx; + border-bottom-width: 0 !important; + border-right-width: 0 !important; +} +.l-clipper__edge:nth-child(1):before { + top: -50%; + left: -50%; +} +.l-clipper__edge:nth-child(2) { + right: -6rpx; + top: -6rpx; + border-bottom-width: 0 !important; + border-left-width: 0 !important; +} +.l-clipper__edge:nth-child(2):before { + top: -50%; + left: 50%; +} +.l-clipper__edge:nth-child(3) { + left: -6rpx; + bottom: -6rpx; + border-top-width: 0 !important; + border-right-width: 0 !important; +} +.l-clipper__edge:nth-child(3):before { + bottom: -50%; + left: -50%; +} +.l-clipper__edge:nth-child(4) { + right: -6rpx; + bottom: -6rpx; + border-top-width: 0 !important; + border-left-width: 0 !important; +} +.l-clipper__edge:nth-child(4):before { + bottom: -50%; + left: 50%; +} +.l-clipper-image { + width: 100%; + border-style: none; + position: absolute; + top: 0; + left: 0; + z-index: 1; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + transform-origin: center; +} +.l-clipper-canvas { + position: fixed; + z-index: 10; + left: -200vw; + top: -200vw; + pointer-events: none; +} +.l-clipper-tools { + position: fixed; + left: 0; + bottom: 10px; + width: 100%; + z-index: 99; + color: #fff; +} +.l-clipper-tools__btns { + font-weight: bold; + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + padding: 20rpx 40rpx; + box-sizing: border-box; +} +.l-clipper-tools__btns .cancel { + width: 112rpx; + height: 60rpx; + text-align: center; + line-height: 60rpx; +} +.l-clipper-tools__btns .confirm { + width: 112rpx; + height: 60rpx; + line-height: 60rpx; + background-color: #07c160; + border-radius: 6rpx; + text-align: center; +} +.l-clipper-tools__btns image { + display: block; + width: 60rpx; + height: 60rpx; +} +.l-clipper-tools__btns { + flex-direction: row; +} diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/limeClipper.vue b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/limeClipper.vue new file mode 100644 index 0000000..8ae9389 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/limeClipper.vue @@ -0,0 +1,816 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/utils.js b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/utils.js new file mode 100644 index 0000000..980c439 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/utils.js @@ -0,0 +1,244 @@ +/** + * 判断手指触摸位置 + */ +export function determineDirection(clipX, clipY, clipWidth, clipHeight, currentX, currentY) { + /* + * (右下>>1 右上>>2 左上>>3 左下>>4) + */ + let corner; + /** + * 思路:(利用直角坐标系) + * 1.找出裁剪框中心点 + * 2.如点击坐标在上方点与左方点区域内,则点击为左上角 + * 3.如点击坐标在下方点与右方点区域内,则点击为右下角 + * 4.其他角同理 + */ + const mainPoint = [clipX + clipWidth / 2, clipY + clipHeight / 2]; // 中心点 + const currentPoint = [currentX, currentY]; // 触摸点 + + if (currentPoint[0] <= mainPoint[0] && currentPoint[1] <= mainPoint[1]) { + corner = 3; // 左上 + } else if (currentPoint[0] >= mainPoint[0] && currentPoint[1] <= mainPoint[1]) { + corner = 2; // 右上 + } else if (currentPoint[0] <= mainPoint[0] && currentPoint[1] >= mainPoint[1]) { + corner = 4; // 左下 + } else if (currentPoint[0] >= mainPoint[0] && currentPoint[1] >= mainPoint[1]) { + corner = 1; // 右下 + } + + return corner; +} + +/** + * 图片边缘检测检测时,计算图片偏移量 + */ +export function calcImageOffset(data, scale) { + let left = data.imageLeft; + let top = data.imageTop; + scale = scale || data.scale; + + let imageWidth = data.imageWidth; + let imageHeight = data.imageHeight; + if ((data.angle / 90) % 2) { + imageWidth = data.imageHeight; + imageHeight = data.imageWidth; + } + const { + clipX, + clipWidth, + clipY, + clipHeight + } = data; + + // 当前图片宽度/高度 + const currentImageSize = (size) => (size * scale) / 2; + const currentImageWidth = currentImageSize(imageWidth); + const currentImageHeight = currentImageSize(imageHeight); + + left = clipX + currentImageWidth >= left ? left : clipX + currentImageWidth; + left = clipX + clipWidth - currentImageWidth <= left ? left : clipX + clipWidth - currentImageWidth; + top = clipY + currentImageHeight >= top ? top : clipY + currentImageHeight; + top = clipY + clipHeight - currentImageHeight <= top ? top : clipY + clipHeight - currentImageHeight; + return { + left, + top, + scale + }; +} + +/** + * 图片边缘检测时,计算图片缩放比例 + */ +export function calcImageScale(data, scale) { + scale = scale || data.scale; + let { + imageWidth, + imageHeight, + clipWidth, + clipHeight, + angle + } = data + if ((angle / 90) % 2) { + imageWidth = imageHeight; + imageHeight = imageWidth; + } + if (imageWidth * scale < clipWidth) { + scale = clipWidth / imageWidth; + } + if (imageHeight * scale < clipHeight) { + scale = Math.max(scale, clipHeight / imageHeight); + } + return scale; +} + +/** + * 计算图片尺寸 + */ +export function calcImageSize(width, height, data) { + let imageWidth = width, + imageHeight = height; + let { + clipWidth, + clipHeight, + sysinfo, + width: originWidth, + height: originHeight + } = data + if (imageWidth && imageHeight) { + if (imageWidth / imageHeight > (clipWidth || originWidth) / (clipWidth || originHeight)) { + imageHeight = clipHeight || originHeight; + imageWidth = (width / height) * imageHeight; + } else { + imageWidth = clipWidth || originWidth; + imageHeight = (height / width) * imageWidth; + } + } else { + let sys = sysinfo || uni.getSystemInfoSync(); + imageWidth = sys.windowWidth; + imageHeight = 0; + } + return { + imageWidth, + imageHeight + }; +} + +/** + * 勾股定理求斜边 + */ +export function calcPythagoreanTheorem(width, height) { + return Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)); +} + +/** + * 拖动裁剪框时计算 + */ +export function clipTouchMoveOfCalculate(data, event) { + const clientX = event.touches[0].clientX; + const clientY = event.touches[0].clientY; + + let { + clipWidth, + clipHeight, + clipY: oldClipY, + clipX: oldClipX, + clipStart, + isLockRatio, + maxWidth, + minWidth, + maxHeight, + minHeight + } = data; + maxWidth = maxWidth / 2; + minWidth = minWidth / 2; + minHeight = minHeight / 2; + maxHeight = maxHeight / 2; + + let width = clipWidth, + height = clipHeight, + clipY = oldClipY, + clipX = oldClipX, + // 获取裁剪框实际宽度/高度 + // 如果大于最大值则使用最大值 + // 如果小于最小值则使用最小值 + sizecorrect = () => { + width = width <= maxWidth ? (width >= minWidth ? width : minWidth) : maxWidth; + height = height <= maxHeight ? (height >= minHeight ? height : minHeight) : maxHeight; + }, + sizeinspect = () => { + sizecorrect(); + if ((width > maxWidth || width < minWidth || height > maxHeight || height < minHeight) && isLockRatio) { + return false; + } else { + return true; + } + }; + //if (clipStart.corner) { + height = clipStart.height + (clipStart.corner > 1 && clipStart.corner < 4 ? 1 : -1) * (clipStart.y - clientY); + //} + switch (clipStart.corner) { + case 1: + width = clipStart.width - clipStart.x + clientX; + if (isLockRatio) { + height = width / (clipWidth / clipHeight); + } + if (!sizeinspect()) return; + break; + case 2: + width = clipStart.width - clipStart.x + clientX; + if (isLockRatio) { + height = width / (clipWidth / clipHeight); + } + if (!sizeinspect()) { + return; + } else { + clipY = clipStart.clipY - (height - clipStart.height); + } + + break; + case 3: + width = clipStart.width + clipStart.x - clientX; + if (isLockRatio) { + height = width / (clipWidth / clipHeight); + } + if (!sizeinspect()) { + return; + } else { + clipY = clipStart.clipY - (height - clipStart.height); + clipX = clipStart.clipX - (width - clipStart.width); + } + + break; + case 4: + width = clipStart.width + clipStart.x - clientX; + if (isLockRatio) { + height = width / (clipWidth / clipHeight); + } + if (!sizeinspect()) { + return; + } else { + clipX = clipStart.clipX - (width - clipStart.width); + } + break; + default: + break; + } + return { + width, + height, + clipX, + clipY + }; +} + +/** + * 单指拖动图片计算偏移 + */ +export function imageTouchMoveOfCalcOffset(data, clientXForLeft, clientYForLeft) { + let left = clientXForLeft - data.touchRelative[0].x, + top = clientYForLeft - data.touchRelative[0].y; + return { + left, + top + }; +} diff --git a/uni_modules/uni-id-pages/pages/userinfo/deactivate/deactivate.vue b/uni_modules/uni-id-pages/pages/userinfo/deactivate/deactivate.vue new file mode 100644 index 0000000..d1d24d6 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/deactivate/deactivate.vue @@ -0,0 +1,119 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/userinfo/userinfo.vue b/uni_modules/uni-id-pages/pages/userinfo/userinfo.vue new file mode 100644 index 0000000..9fb17c9 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/userinfo.vue @@ -0,0 +1,253 @@ + + + + diff --git a/uni_modules/uni-id-pages/readme.md b/uni_modules/uni-id-pages/readme.md new file mode 100644 index 0000000..1650e45 --- /dev/null +++ b/uni_modules/uni-id-pages/readme.md @@ -0,0 +1,15 @@ +# 文档已移至uni-id-pages文档[https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html) + + + +关于插件更新的说明: + +所有uni_modules,在HBuilderX里点右键都可以直接升级。或者在插件市场导入覆盖。 + +覆盖时HBuilderX会弹出代码差异比对,可以决定接受哪些更改、拒绝哪些更改。 + +当拒绝局部修改时,注意可能产生兼容性问题。 + +你需要二次开发uni-id-pages的前端页面, +- 如果改动不大,那么每次更新uni-id-pages时,在HBuilderX的对比界面对比一下就好 +- 如果改动较大,建议复制一套前端页面到自己工程的pages目录下,pages.json里只引用根目录pages下的页面,不引用uni_modules下的页面。然后每次uni-id-pages更新,你对比下比上一版uni-id-pages改了什么,看你是否需要再合并到你自己的pages里。pages.json里不引用uni_modules里的页面的话,打包时不会把这些页面打包进去,不影响发行后的包体积 \ No newline at end of file diff --git a/uni_modules/uni-id-pages/static/limeClipper/photo.svg b/uni_modules/uni-id-pages/static/limeClipper/photo.svg new file mode 100644 index 0000000..7b4b590 --- /dev/null +++ b/uni_modules/uni-id-pages/static/limeClipper/photo.svg @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/uni_modules/uni-id-pages/static/limeClipper/rotate.svg b/uni_modules/uni-id-pages/static/limeClipper/rotate.svg new file mode 100644 index 0000000..0143706 --- /dev/null +++ b/uni_modules/uni-id-pages/static/limeClipper/rotate.svg @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/uni_modules/uni-id-pages/static/login/apple.png b/uni_modules/uni-id-pages/static/login/apple.png new file mode 100644 index 0000000000000000000000000000000000000000..04a3579cbd143037161da2779fb695f731818d81 GIT binary patch literal 18205 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 literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/static/uni-center/grey.png b/uni_modules/uni-id-pages/static/uni-center/grey.png new file mode 100644 index 0000000000000000000000000000000000000000..2aae15a5d0b9eea8451df6395d53775bcc676f78 GIT binary patch literal 6669 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 X90PicW&Nka#%63_p2KrU;E<}T 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

n2IMnjSG$0n4EneSAGzt1 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 TKV^xU00000NkvXXu0mjf)B54Y literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/static/uni-fab-login/alipay.png b/uni_modules/uni-id-pages/static/uni-fab-login/alipay.png new file mode 100644 index 0000000000000000000000000000000000000000..adc0417f86720d9a0702186412ec1a735865ac86 GIT binary patch literal 6184 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 Hv7G+_b1q+7 literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/static/uni-fab-login/apple.png b/uni_modules/uni-id-pages/static/uni-fab-login/apple.png new file mode 100644 index 0000000000000000000000000000000000000000..4f0840fe2ccb9873bd986dc046813ae7d50cb22d GIT binary patch literal 9231 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 F{{wBB`Ah%+ literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/static/uni-fab-login/douyin.png b/uni_modules/uni-id-pages/static/uni-fab-login/douyin.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9f299aa5490d42ca36278b42db6364202b75ce GIT binary patch literal 5911 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 literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/static/uni-fab-login/sinaweibo.png b/uni_modules/uni-id-pages/static/uni-fab-login/sinaweibo.png new file mode 100644 index 0000000000000000000000000000000000000000..4424c7e124f8c901888540ff56e01fcbd858ee51 GIT binary patch literal 7920 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

-0;Ojr@ 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 Xrl*gZhxLB{-!}?!s*pk%(>MPMyHc1> literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/static/uni-fab-login/taobao.png b/uni_modules/uni-id-pages/static/uni-fab-login/taobao.png new file mode 100644 index 0000000000000000000000000000000000000000..8f0944092327135b88686f39f6b247814e9a825a GIT binary patch literal 12011 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 CXXO9@ literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/static/uni-fab-login/user.png b/uni_modules/uni-id-pages/static/uni-fab-login/user.png new file mode 100644 index 0000000000000000000000000000000000000000..5f330e7b72484c8e00e24c0f890e849717d73aa1 GIT binary patch literal 8175 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 ITfX}L0IZ|bqW}N^ literal 0 HcmV?d00001 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 new file mode 100644 index 0000000..f5888c4 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/constants.js @@ -0,0 +1,90 @@ +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' +} + +const LOG_TYPE = { + LOGOUT: 'logout', + LOGIN: 'login', + REGISTER: 'register', + RESET_PWD_BY_SMS: 'reset-pwd', + RESET_PWD_BY_EMAIL: 'reset-pwd', + BIND_MOBILE: 'bind-mobile', + BIND_WEIXIN: 'bind-weixin', + BIND_QQ: 'bind-qq', + BIND_APPLE: 'bind-apple', + BIND_ALIPAY: 'bind-alipay', + UNBIND_WEIXIN: 'unbind-weixin', + UNBIND_QQ: 'unbind-qq', + UNBIND_ALIPAY: 'unbind-alipay', + UNBIND_APPLE: 'unbind-apple' +} + +const SMS_SCENE = { + LOGIN_BY_SMS: 'login-by-sms', + RESET_PWD_BY_SMS: 'reset-pwd-by-sms', + BIND_MOBILE_BY_SMS: 'bind-mobile-by-sms' +} + +const EMAIL_SCENE = { + REGISTER: 'register', + LOGIN_BY_EMAIL: 'login-by-email', + RESET_PWD_BY_EMAIL: 'reset-pwd-by-email', + BIND_EMAIL: 'bind-email' +} + +module.exports = { + db, + dbCmd, + userCollection, + verifyCollection, + deviceCollection, + 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 new file mode 100644 index 0000000..e49306e --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/error.js @@ -0,0 +1,57 @@ +const ERROR = { + ACCOUNT_EXISTS: 'uni-id-account-exists', + ACCOUNT_NOT_EXISTS: 'uni-id-account-not-exists', + ACCOUNT_CONFLICT: 'uni-id-account-conflict', + ACCOUNT_BANNED: 'uni-id-account-banned', + ACCOUNT_AUDITING: 'uni-id-account-auditing', + ACCOUNT_AUDIT_FAILED: 'uni-id-account-audit-failed', + ACCOUNT_CLOSED: 'uni-id-account-closed', + CAPTCHA_REQUIRED: 'uni-id-captcha-required', + PASSWORD_ERROR: 'uni-id-password-error', + PASSWORD_ERROR_EXCEED_LIMIT: 'uni-id-password-error-exceed-limit', + INVALID_USERNAME: 'uni-id-invalid-username', + INVALID_PASSWORD: 'uni-id-invalid-password', + INVALID_PASSWORD_SUPER: 'uni-id-invalid-password-super', + INVALID_PASSWORD_STRONG: 'uni-id-invalid-password-strong', + INVALID_PASSWORD_MEDIUM: 'uni-id-invalid-password-medium', + INVALID_PASSWORD_WEAK: 'uni-id-invalid-password-weak', + INVALID_MOBILE: 'uni-id-invalid-mobile', + INVALID_EMAIL: 'uni-id-invalid-email', + INVALID_NICKNAME: 'uni-id-invalid-nickname', + INVALID_PARAM: 'uni-id-invalid-param', + PARAM_REQUIRED: 'uni-id-param-required', + GET_THIRD_PARTY_ACCOUNT_FAILED: 'uni-id-get-third-party-account-failed', + GET_THIRD_PARTY_USER_INFO_FAILED: 'uni-id-get-third-party-user-info-failed', + MOBILE_VERIFY_CODE_ERROR: 'uni-id-mobile-verify-code-error', + EMAIL_VERIFY_CODE_ERROR: 'uni-id-email-verify-code-error', + ADMIN_EXISTS: 'uni-id-admin-exists', + PERMISSION_ERROR: 'uni-id-permission-error', + SYSTEM_ERROR: 'uni-id-system-error', + SET_INVITE_CODE_FAILED: 'uni-id-set-invite-code-failed', + INVALID_INVITE_CODE: 'uni-id-invalid-invite-code', + CHANGE_INVITER_FORBIDDEN: 'uni-id-change-inviter-forbidden', + BIND_CONFLICT: 'uni-id-bind-conflict', + UNBIND_FAIL: 'uni-id-unbind-failed', + UNBIND_NOT_SUPPORTED: 'uni-id-unbind-not-supported', + UNBIND_UNIQUE_LOGIN: 'uni-id-unbind-unique-login', + UNBIND_PASSWORD_NOT_EXISTS: 'uni-id-unbind-password-not-exists', + UNBIND_MOBILE_NOT_EXISTS: 'uni-id-unbind-mobile-not-exists' +} + +function isUniIdError (errCode) { + return Object.values(ERROR).includes(errCode) +} + +class UniCloudError extends Error { + constructor (options) { + super(options.message) + this.errMsg = options.message || '' + this.errCode = options.code + } +} + +module.exports = { + ERROR, + isUniIdError, + UniCloudError +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/utils.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/utils.js new file mode 100644 index 0000000..2609242 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/utils.js @@ -0,0 +1,197 @@ +function batchFindObjctValue (obj = {}, keys = []) { + const values = {} + for (let i = 0; i < keys.length; i++) { + const key = keys[i] + const keyPath = key.split('.') + let currentKey = keyPath.shift() + let result = obj + while (currentKey) { + if (!result) { + break + } + result = result[currentKey] + currentKey = keyPath.shift() + } + values[key] = result + } + return values +} + +function getType (val) { + return Object.prototype.toString.call(val).slice(8, -1).toLowerCase() +} + +function hasOwn (obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key) +} + +function isValidString (val) { + return val && getType(val) === 'string' +} + +function isPlainObject (obj) { + return getType(obj) === 'object' +} + +function isFn (fn) { + // 务必注意AsyncFunction + return typeof fn === 'function' +} + +// 获取文件后缀,只添加几种图片类型供客服消息接口使用 +const mime2ext = { + 'image/png': 'png', + 'image/jpeg': 'jpg', + 'image/gif': 'gif', + 'image/svg+xml': 'svg', + 'image/bmp': 'bmp', + 'image/webp': 'webp' +} + +function getExtension (contentType) { + return mime2ext[contentType] +} + +const isSnakeCase = /_(\w)/g +const isCamelCase = /[A-Z]/g + +function snake2camel (value) { + return value.replace(isSnakeCase, (_, c) => (c ? c.toUpperCase() : '')) +} + +function camel2snake (value) { + return value.replace(isCamelCase, str => '_' + str.toLowerCase()) +} + +function parseObjectKeys (obj, type) { + let parserReg, parser + switch (type) { + case 'snake2camel': + parser = snake2camel + parserReg = isSnakeCase + break + case 'camel2snake': + parser = camel2snake + parserReg = isCamelCase + break + } + for (const key in obj) { + if (hasOwn(obj, key)) { + if (parserReg.test(key)) { + const keyCopy = parser(key) + obj[keyCopy] = obj[key] + delete obj[key] + if (isPlainObject(obj[keyCopy])) { + obj[keyCopy] = parseObjectKeys(obj[keyCopy], type) + } else if (Array.isArray(obj[keyCopy])) { + obj[keyCopy] = obj[keyCopy].map((item) => { + return parseObjectKeys(item, type) + }) + } + } + } + } + return obj +} + +function snake2camelJson (obj) { + return parseObjectKeys(obj, 'snake2camel') +} + +function camel2snakeJson (obj) { + return parseObjectKeys(obj, 'camel2snake') +} + +function getOffsetDate (offset) { + return new Date( + Date.now() + (new Date().getTimezoneOffset() + (offset || 0) * 60) * 60000 + ) +} + +function getDateStr (date, separator = '-') { + date = date || new Date() + const dateArr = [] + dateArr.push(date.getFullYear()) + dateArr.push(('00' + (date.getMonth() + 1)).substr(-2)) + dateArr.push(('00' + date.getDate()).substr(-2)) + return dateArr.join(separator) +} + +function getTimeStr (date, separator = ':') { + date = date || new Date() + const timeArr = [] + timeArr.push(('00' + date.getHours()).substr(-2)) + timeArr.push(('00' + date.getMinutes()).substr(-2)) + timeArr.push(('00' + date.getSeconds()).substr(-2)) + return timeArr.join(separator) +} + +function getFullTimeStr (date) { + date = date || new Date() + return getDateStr(date) + ' ' + getTimeStr(date) +} + +function getDistinctArray (arr) { + return Array.from(new Set(arr)) +} + +/** + * 拼接url + * @param {string} base 基础路径 + * @param {string} path 在基础路径上拼接的路径 + * @returns + */ +function resolveUrl (base, path) { + if (/^https?:/.test(path)) { + return path + } + return base + path +} + +function getVerifyCode (len = 6) { + let code = '' + for (let i = 0; i < len; i++) { + code += Math.floor(Math.random() * 10) + } + return code +} + +function coverMobile (mobile) { + if (typeof mobile !== 'string') { + return mobile + } + return mobile.slice(0, 3) + '****' + mobile.slice(7) +} + +function getNonceStr (length = 16) { + let str = '' + while (str.length < length) { + str += Math.random().toString(32).substring(2) + } + return str.substring(0, length) +} + +try { + require('lodash.merge') +} catch (error) { + console.error('uni-id-co缺少依赖,请在uniCloud/cloudfunctions/common/uni-id-co目录执行 npm install 安装依赖') + throw error +} + +module.exports = { + getType, + isValidString, + batchFindObjctValue, + isPlainObject, + isFn, + getDistinctArray, + getFullTimeStr, + resolveUrl, + getOffsetDate, + camel2snakeJson, + snake2camelJson, + getExtension, + getVerifyCode, + coverMobile, + getNonceStr +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/validator.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/validator.js new file mode 100644 index 0000000..34878ca --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/validator.js @@ -0,0 +1,432 @@ +const { + isValidString, + getType +} = require('./utils.js') +const { + ERROR +} = require('./error') + +const baseValidator = Object.create(null) + +baseValidator.username = function (username) { + const errCode = ERROR.INVALID_USERNAME + if (!isValidString(username)) { + return { + errCode + } + } + if (/^\d+$/.test(username)) { + // 用户名不能为纯数字 + return { + errCode + } + }; + if (!/^[a-zA-Z0-9_-]+$/.test(username)) { + // 用户名仅能使用数字、字母、“_”及“-” + return { + errCode + } + } +} + +baseValidator.password = function (password) { + const errCode = ERROR.INVALID_PASSWORD + if (!isValidString(password)) { + return { + errCode + } + } + if (password.length < 6) { + // 密码长度不能小于6 + return { + errCode + } + } +} + +baseValidator.mobile = function (mobile) { + const errCode = ERROR.INVALID_MOBILE + if (!isValidString(mobile)) { + return { + errCode + } + } + if (!/^1\d{10}$/.test(mobile)) { + return { + errCode + } + } +} + +baseValidator.email = function (email) { + const errCode = ERROR.INVALID_EMAIL + if (!isValidString(email)) { + return { + errCode + } + } + if (!/@/.test(email)) { + return { + errCode + } + } +} + +baseValidator.nickname = function (nickname) { + const errCode = ERROR.INVALID_NICKNAME + if (nickname.indexOf('@') !== -1) { + // 昵称不允许含@ + return { + errCode + } + }; + if (/^\d+$/.test(nickname)) { + // 昵称不能为纯数字 + return { + errCode + } + }; + if (nickname.length > 100) { + // 昵称不可超过100字符 + return { + errCode + } + } +} + +const baseType = ['string', 'boolean', 'number', 'null'] // undefined不会由客户端提交上来 + +baseType.forEach((type) => { + baseValidator[type] = function (val) { + if (getType(val) === type) { + return + } + return { + errCode: ERROR.INVALID_PARAM + } + } +}) + +function tokenize(name) { + let i = 0 + const result = [] + let token = '' + while (i < name.length) { + const char = name[i] + switch (char) { + case '|': + case '<': + case '>': + token && result.push(token) + result.push(char) + token = '' + break + default: + token += char + break + } + i++ + if (i === name.length && token) { + result.push(token) + } + } + return result +} + +/** + * 处理validator名 + * @param {string} name + */ +function parseValidatorName(name) { + const tokenList = tokenize(name) + let i = 0 + let currentToken = tokenList[i] + const result = { + type: 'root', + children: [], + parent: null + } + let lastRealm = result + while (currentToken) { + switch (currentToken) { + case 'array': { + const currentRealm = { + type: 'array', + children: [], + parent: lastRealm + } + lastRealm.children.push(currentRealm) + lastRealm = currentRealm + break + } + case '<': + if (lastRealm.type !== 'array') { + throw new Error('Invalid validator token "<"') + } + break + case '>': + if (lastRealm.type !== 'array') { + throw new Error('Invalid validator token ">"') + } + lastRealm = lastRealm.parent + break + case '|': + if (lastRealm.type !== 'array' && lastRealm.type !== 'root') { + throw new Error('Invalid validator token "|"') + } + break + default: + lastRealm.children.push({ + type: currentToken + }) + break + } + i++ + currentToken = tokenList[i] + } + return result +} + +function getRuleCategory(rule) { + switch (rule.type) { + case 'array': + return 'array' + case 'root': + return 'root' + default: + return 'base' + } +} + +function isMatchUnionType(val, rule) { + if (!rule.children || rule.children.length === 0) { + return true + } + const children = rule.children + for (let i = 0; i < children.length; i++) { + const child = children[i] + const category = getRuleCategory(child) + let pass = false + switch (category) { + case 'base': + pass = isMatchBaseType(val, child) + break + case 'array': + pass = isMatchArrayType(val, child) + break + default: + break + } + if (pass) { + return true + } + } + return false +} + +function isMatchBaseType(val, rule) { + if (typeof baseValidator[rule.type] !== 'function') { + throw new Error(`invalid schema type: ${rule.type}`) + } + const validateRes = baseValidator[rule.type](val) + if (validateRes && validateRes.errCode) { + return false + } + return true +} + +function isMatchArrayType(arr, rule) { + if (getType(arr) !== 'array') { + return false + } + if (rule.children && rule.children.length && arr.some(item => !isMatchUnionType(item, rule))) { + return false + } + return true +} + +// 特殊符号 https://www.ibm.com/support/pages/password-strength-rules ~!@#$%^&*_-+=`|\(){}[]:;"'<>,.?/ +// const specialChar = '~!@#$%^&*_-+=`|\(){}[]:;"\'<>,.?/' +// const specialCharRegExp = /^[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]$/ +// for (let i = 0, arr = specialChar.split(''); i < arr.length; i++) { +// const char = arr[i] +// if (!specialCharRegExp.test(char)) { +// throw new Error('check special character error: ' + char) +// } +// } + +// 密码强度表达式 +const passwordRules = { + // 密码必须包含大小写字母、数字和特殊符号 + super: /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/, + // 密码必须包含字母、数字和特殊符号 + strong: /^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/, + // 密码必须为字母、数字和特殊符号任意两种的组合 + medium: /^(?![0-9]+$)(?![a-zA-Z]+$)(?![~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]+$)[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/, + // 密码必须包含字母和数字 + weak: /^(?=.*[0-9])(?=.*[a-zA-Z])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{6,16}$/, + +} + +function createPasswordVerifier({ + passwordStrength = '' +} = {}) { + return function (password) { + const passwordRegExp = passwordRules[passwordStrength] + if (!passwordRegExp) { + throw new Error('Invalid password strength config: ' + passwordStrength) + } + const errCode = ERROR.INVALID_PASSWORD + if (!isValidString(password)) { + return { + errCode + } + } + if (!passwordRegExp.test(password)) { + return { + errCode: errCode + '-' + passwordStrength + } + } + } +} + +class Validator { + constructor({ + passwordStrength = '' + } = {}) { + this.baseValidator = baseValidator + this.customValidator = Object.create(null) + if (passwordStrength) { + this.mixin( + 'password', + createPasswordVerifier({ + passwordStrength + }) + ) + } + } + + mixin(type, handler) { + this.customValidator[type] = handler + } + + getRealBaseValidator(type) { + return this.customValidator[type] || this.baseValidator[type] + } + + get validator() { + return new Proxy({}, { + get: (_, prop) => { + if (typeof prop !== 'string') { + return + } + const realBaseValidator = this.getRealBaseValidator(prop) + if (realBaseValidator) { + return realBaseValidator + } + const rule = parseValidatorName(prop) + return function (val) { + if (!isMatchUnionType(val, rule)) { + return { + errCode: ERROR.INVALID_PARAM + } + } + } + } + }) + } + + validate(value = {}, schema = {}) { + for (const schemaKey in schema) { + let schemaValue = schema[schemaKey] + if (getType(schemaValue) === 'string') { + schemaValue = { + required: true, + type: schemaValue + } + } + const { + required, + type + } = schemaValue + // value内未传入了schemaKey或对应值为undefined + if (value[schemaKey] === undefined) { + if (required) { + return { + errCode: ERROR.PARAM_REQUIRED, + errMsgValue: { + param: schemaKey + }, + schemaKey + } + } else { + continue + } + } + const validateMethod = this.validator[type] + if (!validateMethod) { + throw new Error(`invalid schema type: ${type}`) + } + const validateRes = validateMethod(value[schemaKey]) + if (validateRes) { + validateRes.schemaKey = schemaKey + return validateRes + } + } + } +} + +function checkClientInfo(clientInfo) { + const stringNotRequired = { + required: false, + type: 'string' + } + const numberNotRequired = { + required: false, + type: 'number' + } + const numberOrStringNotRequired = { + required: false, + type: 'number|string' + } + const schema = { + uniPlatform: 'string', + appId: 'string', + deviceId: stringNotRequired, + osName: stringNotRequired, + locale: stringNotRequired, + clientIP: stringNotRequired, + appName: stringNotRequired, + appVersion: stringNotRequired, + appVersionCode: numberOrStringNotRequired, + channel: numberOrStringNotRequired, + userAgent: stringNotRequired, + uniIdToken: stringNotRequired, + deviceBrand: stringNotRequired, + deviceModel: stringNotRequired, + osVersion: stringNotRequired, + osLanguage: stringNotRequired, + osTheme: stringNotRequired, + romName: stringNotRequired, + romVersion: stringNotRequired, + devicePixelRatio: numberNotRequired, + windowWidth: numberNotRequired, + windowHeight: numberNotRequired, + screenWidth: numberNotRequired, + screenHeight: numberNotRequired + } + const validateRes = new Validator().validate(clientInfo, schema) + if (validateRes) { + if (validateRes.errCode === ERROR.PARAM_REQUIRED) { + console.warn('- 如果使用HBuilderX运行本地云函数/云对象功能时出现此提示,请改为使用客户端调用本地云函数方式调试,或更新HBuilderX到3.4.12及以上版本。\n- 如果是缺少clientInfo.appId,请检查项目manifest.json内是否配置了DCloud AppId') + throw new Error(`"clientInfo.${validateRes.schemaKey}" is required.`) + } else { + throw new Error(`Invalid client info: clienInfo.${validateRes.schemaKey}`) + } + } +} + +module.exports = { + Validator, + checkClientInfo +} 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 new file mode 100644 index 0000000..4d69441 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/config/permission.js @@ -0,0 +1,78 @@ +// 各接口权限配置,未配置接口表示允许任何用户访问(包括未登录用户) +module.exports = { + // 管理接口 + addUser: { + // auth: true // 已登录用户方可操作,配置角色或权限时此项可不写 + role: ['admin'] // 允许进行此操作的角色,包含任一角色均可操作。 + // permission: [] // 允许进行此操作的权限,包含任一权限均可操作。 + // 权限角色均配置时,用户拥有任一权限或任一角色均可操作 + }, + updateUser: { + role: ['admin'] + }, + authorizeAppLogin: { + role: ['admin'] + }, + removeAuthorizedApp: { + role: ['admin'] + }, + setAuthorizedApp: { + role: ['admin'] + }, + + // 用户接口 + closeAccount: { + auth: true + }, + updatePwd: { + auth: true + }, + logout: { + auth: true + }, + bindMobileBySms: { + auth: true + }, + bindMobileByUniverify: { + auth: true + }, + bindMobileByMpWeixin: { + auth: true + }, + bindAlipay: { + auth: true + }, + bindApple: { + auth: true + }, + bindQQ: { + auth: true + }, + bindWeixin: { + auth: true + }, + acceptInvite: { + auth: true + }, + getInvitedUser: { + auth: true + }, + setPushCid: { + auth: true + }, + getAccountInfo: { + auth: true + }, + unbindWeixin: { + auth: true + }, + unbindAlipay: { + auth: true + }, + unbindQQ: { + auth: true + }, + unbindApple: { + auth: true + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/index.obj.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/index.obj.js new file mode 100644 index 0000000..dd5303c --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/index.obj.js @@ -0,0 +1,585 @@ +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 { + 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 { + 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') + +module.exports = { + async _before () { + const clientInfo = this.getClientInfo() + /** + * 检查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.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 +} 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 new file mode 100644 index 0000000..01109e0 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/en.js @@ -0,0 +1,49 @@ +const word = { + login: 'login', + 'verify-mobile': 'verify phone number' +} + +const sentence = { + 'uni-id-account-exists': 'Account exists', + 'uni-id-account-not-exists': 'Account does not exists', + 'uni-id-account-conflict': 'User account conflict', + 'uni-id-account-banned': 'Account has been banned', + 'uni-id-account-auditing': 'Account audit in progress', + 'uni-id-account-audit-failed': 'Account audit failed', + 'uni-id-account-closed': 'Account has been closed', + 'uni-id-captcha-required': 'Captcha required', + 'uni-id-password-error': 'Password error', + 'uni-id-password-error-exceed-limit': 'The number of password errors is excessive', + 'uni-id-invalid-username': 'Invalid username', + 'uni-id-invalid-password': 'invalid password', + 'uni-id-invalid-password-super': 'Passwords must have 8-16 characters and contain uppercase letters, lowercase letters, numbers, and symbols.', + 'uni-id-invalid-password-strong': 'Passwords must have 8-16 characters and contain letters, numbers and symbols.', + 'uni-id-invalid-password-medium': 'Passwords must have 8-16 characters and contain at least two of the following: letters, numbers, and symbols.', + 'uni-id-invalid-password-weak': 'Passwords must have 6-16 characters and contain letters and numbers.', + 'uni-id-invalid-mobile': 'Invalid mobile phone number', + 'uni-id-invalid-email': 'Invalid email address', + 'uni-id-invalid-nickname': 'Invalid nickname', + 'uni-id-invalid-param': 'Invalid parameter', + 'uni-id-param-required': 'Parameter required: {param}', + 'uni-id-get-third-party-account-failed': 'Get third party account failed', + 'uni-id-get-third-party-user-info-failed': 'Get third party user info failed', + 'uni-id-mobile-verify-code-error': 'Verify code error or expired', + 'uni-id-email-verify-code-error': 'Verify code error or expired', + 'uni-id-admin-exists': 'Administrator exists', + 'uni-id-permission-error': 'Permission denied', + 'uni-id-system-error': 'System error', + 'uni-id-set-invite-code-failed': 'Set invite code failed', + 'uni-id-invalid-invite-code': 'Invalid invite code', + 'uni-id-change-inviter-forbidden': 'Change inviter is not allowed', + 'uni-id-bind-conflict': 'This account has been bound', + 'uni-id-admin-exist-in-other-apps': 'Administrator is registered in other consoles', + 'uni-id-unbind-failed': 'Please bind first and then unbind', + 'uni-id-unbind-not-supported': 'Unbinding is not supported', + 'uni-id-unbind-mobile-not-exists': 'This is the only way to login at the moment, please bind your phone number and then try to unbind', + 'uni-id-unbind-password-not-exists': 'Please set a password first' +} + +module.exports = { + ...word, + ...sentence +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/index.js new file mode 100644 index 0000000..1f22998 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/index.js @@ -0,0 +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 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 new file mode 100644 index 0000000..f346e49 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/zh-hans.js @@ -0,0 +1,49 @@ +const word = { + login: '登录', + 'verify-mobile': '验证手机号' +} + +const sentence = { + 'uni-id-account-exists': '此账号已注册', + 'uni-id-account-not-exists': '此账号未注册', + 'uni-id-account-conflict': '用户账号冲突', + 'uni-id-account-banned': '此账号已封禁', + 'uni-id-account-auditing': '此账号正在审核中', + 'uni-id-account-audit-failed': '此账号审核失败', + 'uni-id-account-closed': '此账号已注销', + 'uni-id-captcha-required': '请输入图形验证码', + 'uni-id-password-error': '密码错误', + 'uni-id-password-error-exceed-limit': '密码错误次数过多,请稍后再试', + 'uni-id-invalid-username': '用户名不合法', + 'uni-id-invalid-password': '密码不合法', + 'uni-id-invalid-password-super': '密码必须包含大小写字母、数字和特殊符号,长度8-16位', + 'uni-id-invalid-password-strong': '密码必须包含字母、数字和特殊符号,长度8-16位不合法', + 'uni-id-invalid-password-medium': '密码必须为字母、数字和特殊符号任意两种的组合,长度8-16位', + 'uni-id-invalid-password-weak': '密码必须包含字母和数字,长度6-16位', + 'uni-id-invalid-mobile': '手机号码不合法', + 'uni-id-invalid-email': '邮箱不合法', + 'uni-id-invalid-nickname': '昵称不合法', + 'uni-id-invalid-param': '参数错误', + 'uni-id-param-required': '缺少参数: {param}', + 'uni-id-get-third-party-account-failed': '获取第三方账号失败', + 'uni-id-get-third-party-user-info-failed': '获取用户信息失败', + 'uni-id-mobile-verify-code-error': '手机验证码错误或已过期', + 'uni-id-email-verify-code-error': '邮箱验证码错误或已过期', + 'uni-id-admin-exists': '超级管理员已存在', + 'uni-id-permission-error': '权限错误', + 'uni-id-system-error': '系统错误', + 'uni-id-set-invite-code-failed': '设置邀请码失败', + 'uni-id-invalid-invite-code': '邀请码不可用', + 'uni-id-change-inviter-forbidden': '禁止修改邀请人', + 'uni-id-bind-conflict': '此账号已被绑定', + 'uni-id-admin-exist-in-other-apps': '超级管理员已在其他控制台注册', + 'uni-id-unbind-failed': '请先绑定后再解绑', + 'uni-id-unbind-not-supported': '不支持解绑', + 'uni-id-unbind-mobile-not-exists': '这是当前唯一登录方式,请绑定手机号后再尝试解绑', + 'uni-id-unbind-password-not-exists': '请先设置密码在尝试解绑' +} + +module.exports = { + ...word, + ...sentence +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/README.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/README.md new file mode 100644 index 0000000..47d8c4c --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/README.md @@ -0,0 +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 new file mode 100644 index 0000000..dbec081 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/index.js @@ -0,0 +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 + } +} 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 new file mode 100644 index 0000000..cff351d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/protocols.js @@ -0,0 +1,10 @@ +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 new file mode 100644 index 0000000..1462b04 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/alipayBase.js @@ -0,0 +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 + } +} 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 new file mode 100644 index 0000000..0e51b4d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/account/index.js @@ -0,0 +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 + } +} 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 new file mode 100644 index 0000000..e1dbb31 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/rsa-public-key-pem.js @@ -0,0 +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 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 new file mode 100644 index 0000000..149c7de --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/index.js @@ -0,0 +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 + }) + } +} 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 new file mode 100644 index 0000000..9b4879a --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/account/index.js @@ -0,0 +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 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/account/protocol.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/account/protocol.js new file mode 100644 index 0000000..e69de29 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 new file mode 100644 index 0000000..fcfdc1e --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/normalize.js @@ -0,0 +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 +} 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 new file mode 100644 index 0000000..c58f1e8 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/share/create-api.js @@ -0,0 +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 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 new file mode 100644 index 0000000..7ecea84 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/account/index.js @@ -0,0 +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 + } + } +} 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 new file mode 100644 index 0000000..908d916 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/normalize.js @@ -0,0 +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 +} 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 new file mode 100644 index 0000000..c141016 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/utils.js @@ -0,0 +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 +} 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 new file mode 100644 index 0000000..c62e3eb --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/account.js @@ -0,0 +1,130 @@ +const { + db, + dbCmd, + userCollection +} = require('../../common/constants') +const { + USER_IDENTIFIER +} = require('../../common/constants') +const { + batchFindObjctValue, + getType +} = require('../../common/utils') + +/** + * 查询满足条件的用户 + * @param {Object} params + * @param {Object} params.userQuery 用户唯一标识组成的查询条件 + * @param {Object} params.authorizedApp 用户允许登录的应用 + * @returns userMatched 满足条件的用户列表 + */ +async function findUser (params = {}) { + const { + userQuery, + authorizedApp = [] + } = params + const condition = getUserQueryCondition(userQuery) + if (condition.length === 0) { + throw new Error('Invalid user query') + } + const authorizedAppType = getType(authorizedApp) + let appQuery = null + if (authorizedAppType === 'string') { + // 传入authorizedApp为单个appId时 + appQuery = dbCmd.or( + { + dcloud_appid: authorizedApp + }, + { + dcloud_appid: dbCmd.exists(false) + } + ) + } else if (authorizedAppType === 'array') { + if (authorizedApp.length === 0) { + // 传入空数组表示希望获取不能登录任一客户端的用户 + appQuery = { + dcloud_appid: [] + } + } else if (authorizedApp.length === 1) { + appQuery = dbCmd.or( + { + dcloud_appid: authorizedApp[0] + }, + { + dcloud_appid: dbCmd.exists(false) + } + ) + } else { + appQuery = dbCmd.or( + { + dcloud_appid: db.command.in(authorizedApp) + }, + { + dcloud_appid: dbCmd.exists(false) + } + ) + } + } else { + throw new Error('Invalid authorized app') + } + + let finalQuery + + if (condition.length === 1) { + finalQuery = dbCmd.and(condition[0], appQuery) + } else { + finalQuery = dbCmd.and( + dbCmd.or(condition), + appQuery + ) + } + const userQueryRes = await userCollection.where(finalQuery).get() + return userQueryRes.data +} + +function getUserIdentifier (userRecord = {}) { + const keys = Object.keys(USER_IDENTIFIER) + return batchFindObjctValue(userRecord, keys) +} + +function getUserQueryCondition (userRecord = {}) { + const userIdentifier = getUserIdentifier(userRecord) + const condition = [] + for (const key in userIdentifier) { + const value = userIdentifier[key] + if (!value) { + // 过滤所有value为假值的条件,在查询用户时没有意义 + continue + } + const queryItem = { + [key]: value + } + // 为兼容用户老数据用户名及邮箱需要同时查小写及原始大小写数据 + if (key === 'mobile') { + queryItem.mobile_confirmed = 1 + } else if (key === 'email') { + queryItem.email_confirmed = 1 + const email = userIdentifier.email + if (email.toLowerCase() !== email) { + condition.push({ + email: email.toLowerCase(), + email_confirmed: 1 + }) + } + } else if (key === 'username') { + const username = userIdentifier.username + if (username.toLowerCase() !== username) { + condition.push({ + username: username.toLowerCase() + }) + } + } + condition.push(queryItem) + } + return condition +} + +module.exports = { + findUser, + getUserIdentifier +} 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 new file mode 100644 index 0000000..4618fa5 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/captcha.js @@ -0,0 +1,76 @@ +const { + ERROR +} = require('../../common/error') + +async function getNeedCaptcha ({ + uid, + username, + mobile, + email, + type = 'login', + limitDuration = 7200000, // 两小时 + limitTimes = 3 // 记录次数 +} = {}) { + const db = uniCloud.database() + const dbCmd = db.command + // 当用户最近“2小时内(limitDuration)”登录失败达到3次(limitTimes)时。要求用户提交验证码 + const now = Date.now() + const uniIdLogCollection = db.collection('uni-id-log') + const userIdentifier = { + user_id: uid, + username, + mobile, + email + } + + let totalKey = 0; let deleteKey = 0 + for (const key in userIdentifier) { + totalKey++ + if (!userIdentifier[key] || typeof userIdentifier[key] !== 'string') { + deleteKey++ + delete userIdentifier[key] + } + } + + if (deleteKey === totalKey) { + throw new Error('System error') // 正常情况下不会进入此条件,但是考虑到后续会有其他开发者修改此云对象,在此处做一个判断 + } + + const { + data: recentRecord + } = await uniIdLogCollection.where({ + ip: this.getClientInfo().clientIP, + ...userIdentifier, + type, + create_date: dbCmd.gt(now - limitDuration) + }) + .orderBy('create_date', 'desc') + .limit(limitTimes) + .get() + return recentRecord.length === limitTimes && recentRecord.every(item => item.state === 0) +} + +async function verifyCaptcha (params = {}) { + const { + captcha, + scene + } = params + if (!captcha) { + throw { + errCode: ERROR.CAPTCHA_REQUIRED + } + } + const payload = await this.uniCaptcha.verify({ + deviceId: this.getClientInfo().deviceId, + captcha, + scene + }) + if (payload.errCode) { + throw payload + } +} + +module.exports = { + getNeedCaptcha, + verifyCaptcha +} 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 new file mode 100644 index 0000000..fdc7160 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/config.js @@ -0,0 +1,135 @@ +const { + getWeixinPlatform +} = require('./weixin') +const createConfig = require('uni-config-center') + +const requiredConfig = { + 'web.weixin-h5': ['appid', 'appsecret'], + 'web.weixin-web': ['appid', 'appsecret'], + 'app.weixin': ['appid', 'appsecret'], + 'mp-weixin.weixin': ['appid', 'appsecret'], + 'app.qq': ['appid', 'appsecret'], + 'mp-alipay.alipay': ['appid', 'privateKey'], + 'app.apple': ['bundleId'] +} + +const uniIdConfig = createConfig({ + pluginId: 'uni-id' +}) + +class ConfigUtils { + constructor ({ + context + } = {}) { + this.context = context + this.clientInfo = context.getClientInfo() + const { + appId, + uniPlatform + } = this.clientInfo + this.appId = appId + switch (uniPlatform) { + case 'app': + case 'app-plus': + this.platform = 'app' + break + case 'web': + case 'h5': + this.platform = 'web' + break + default: + this.platform = uniPlatform + break + } + } + + getConfigArray () { + let configContent + try { + configContent = require('uni-config-center/uni-id/config.json') + } catch (error) { + throw new Error('Invalid config file\n' + error.message) + } + if (configContent[0]) { + return Object.values(configContent) + } + configContent.isDefaultConfig = true + return [configContent] + } + + getAppConfig () { + const configArray = this.getConfigArray() + return configArray.find(item => item.dcloudAppid === this.appId) || configArray.find(item => item.isDefaultConfig) + } + + getPlatformConfig () { + const appConfig = this.getAppConfig() + if (!appConfig) { + throw new Error( + `Config for current app (${this.appId}) was not found, please check your config file or client appId`) + } + const platform = this.platform + if ( + (this.platform === 'app' && appConfig['app-plus']) || + (this.platform === 'web' && appConfig.h5) + ) { + throw new Error( + `Client platform is ${this.platform}, but ${this.platform === 'web' ? 'h5' : 'app-plus'} was found in config. Please refer to: https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary?id=m-to-co` + ) + } + + const defaultConfig = { + tokenExpiresIn: 7200, + tokenExpiresThreshold: 1200, + passwordErrorLimit: 6, + passwordErrorRetryTime: 3600 + } + return Object.assign(defaultConfig, appConfig, appConfig[platform]) + } + + getOauthProvider ({ + provider + } = {}) { + const clientPlatform = this.platform + let oatuhProivder = provider + if (provider === 'weixin' && clientPlatform === 'web') { + const weixinPlatform = getWeixinPlatform.call(this.context) + if (weixinPlatform === 'h5' || weixinPlatform === 'web') { + oatuhProivder = 'weixin-' + weixinPlatform // weixin-h5 公众号,weixin-web pc端 + } + } + return oatuhProivder + } + + getOauthConfig ({ + provider + } = {}) { + const config = this.getPlatformConfig() + const clientPlatform = this.platform + const oatuhProivder = this.getOauthProvider({ + provider + }) + const requireConfigKey = requiredConfig[`${clientPlatform}.${oatuhProivder}`] || [] + if (!config.oauth || !config.oauth[oatuhProivder]) { + throw new Error(`Config param required: ${clientPlatform}.oauth.${oatuhProivder}`) + } + const oauthConfig = config.oauth[oatuhProivder] + requireConfigKey.forEach((item) => { + if (!oauthConfig[item]) { + throw new Error(`Config param required: ${clientPlatform}.oauth.${oatuhProivder}.${item}`) + } + }) + return oauthConfig + } + + getHooks () { + if (uniIdConfig.hasFile('hooks/index.js')) { + return require( + uniIdConfig.resolve('hooks/index.js') + ) + } + return {} + } +} + +module.exports = ConfigUtils 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 new file mode 100644 index 0000000..84233c3 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/fission.js @@ -0,0 +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 +} 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 new file mode 100644 index 0000000..8ef5c40 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/login.js @@ -0,0 +1,232 @@ +const { + findUser +} = require('./account') +const { + userCollection, + LOG_TYPE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + logout +} = require('./logout') +const PasswordUtils = require('./password') + +async function realPreLogin (params = {}) { + const { + user + } = params + const appId = this.getClientInfo().appId + const userMatched = await findUser({ + userQuery: user, + authorizedApp: appId + }) + if (userMatched.length === 0) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } else if (userMatched.length > 1) { + throw { + errCode: ERROR.ACCOUNT_CONFLICT + } + } + const userRecord = userMatched[0] + checkLoginUserRecord(userRecord) + return userRecord +} + +async function preLogin (params = {}) { + const { + user + } = params + try { + const user = await realPreLogin.call(this, params) + return user + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + data: user, + type: LOG_TYPE.LOGIN + }) + throw error + } +} + +async function preLoginWithPassword (params = {}) { + const { + user, + password + } = params + try { + const userRecord = await realPreLogin.call(this, params) + const { + passwordErrorLimit, + passwordErrorRetryTime + } = this.config + const { + clientIP + } = this.getClientInfo() + // 根据ip地址,密码错误次数过多,锁定登录 + let loginIPLimit = userRecord.login_ip_limit || [] + // 清理无用记录 + loginIPLimit = loginIPLimit.filter(item => item.last_error_time > Date.now() - passwordErrorRetryTime * 1000) + let currentIPLimit = loginIPLimit.find(item => item.ip === clientIP) + if (currentIPLimit && currentIPLimit.error_times >= passwordErrorLimit) { + throw { + errCode: ERROR.PASSWORD_ERROR_EXCEED_LIMIT + } + } + const passwordUtils = new PasswordUtils({ + passwordSecret: this.config.passwordSecret + }) + + const { + success: checkPasswordSuccess, + refreshPasswordInfo + } = passwordUtils.checkUserPassword({ + password, + passwordHash: userRecord.password, + passwordSecretVersion: userRecord.password_secret_version + }) + if (!checkPasswordSuccess) { + // 更新用户ip对应的密码错误记录 + if (!currentIPLimit) { + currentIPLimit = { + ip: clientIP, + error_times: 1, + last_error_time: Date.now() + } + loginIPLimit.push(currentIPLimit) + } else { + currentIPLimit.error_times++ + currentIPLimit.last_error_time = Date.now() + } + await userCollection.doc(userRecord._id).update({ + login_ip_limit: loginIPLimit + }) + throw { + errCode: ERROR.PASSWORD_ERROR + } + } + const extraData = {} + if (refreshPasswordInfo) { + extraData.password = refreshPasswordInfo.passwordHash + extraData.password_secret_version = refreshPasswordInfo.version + } + + const currentIPLimitIndex = loginIPLimit.indexOf(currentIPLimit) + if (currentIPLimitIndex > -1) { + loginIPLimit.splice(currentIPLimitIndex, 1) + } + extraData.login_ip_limit = loginIPLimit + return { + user: userRecord, + extraData + } + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + data: user, + type: LOG_TYPE.LOGIN + }) + throw error + } +} + +function checkLoginUserRecord (user) { + switch (user.status) { + case undefined: + case 0: + break + case 1: + throw { + errCode: ERROR.ACCOUNT_BANNED + } + case 2: + throw { + errCode: ERROR.ACCOUNT_AUDITING + } + case 3: + throw { + errCode: ERROR.ACCOUNT_AUDIT_FAILED + } + case 4: + throw { + errCode: ERROR.ACCOUNT_CLOSED + } + default: + break + } +} + +async function thirdPartyLogin (params = {}) { + const { + user + } = params + return { + mobileComfirmd: user.mobile_comfirmd, + emailComfirmd: user.email_comfirmd + } +} + +async function postLogin (params = {}) { + const { + user, + extraData, + isThirdParty = false + } = params + const { + clientIP, + uniIdToken + } = this.getClientInfo() + const uid = user._id + const updateData = { + last_login_date: Date.now(), + last_login_ip: clientIP, + ...extraData + } + const { + token, + tokenExpired + } = await this.uniIdCommon.createToken({ + uid + }) + + if (uniIdToken) { + try { + await logout.call(this) + } catch (error) {} + } + + await userCollection.doc(uid).update(updateData) + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: LOG_TYPE.LOGIN + }) + return { + errCode: 0, + newToken: { + token, + tokenExpired + }, + uid, + ...( + isThirdParty + ? thirdPartyLogin({ + user + }) + : {} + ), + 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 new file mode 100644 index 0000000..dc49fc7 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/logout.js @@ -0,0 +1,47 @@ +const { + dbCmd, + LOG_TYPE, + deviceCollection, + userCollection +} = require('../../common/constants') + +async function logout() { + const { + uniIdToken, + deviceId + } = this.getClientInfo() + const { + uid + } = await this.uniIdCommon.checkToken( + uniIdToken, + { + autoRefresh: false + } + ) + + // 删除token + await userCollection.doc(uid).update({ + token: dbCmd.pull(uniIdToken) + }) + + // 仅当device表的device_id和user_id均对应时才进行更新 + await deviceCollection.where({ + device_id: deviceId, + user_id: uid + }).update({ + token_expired: 0 + }) + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: LOG_TYPE.LOGOUT + }) + return { + errCode: 0 + } +} + +module.exports = { + logout +} \ No newline at end of file diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js new file mode 100644 index 0000000..19ee920 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js @@ -0,0 +1,116 @@ +const { + getType +} = require('../../common/utils') +const crypto = require('crypto') + +const PasswordHashMethod = { + 'hmac-sha1': function (content, secret) { + const hmac = crypto.createHmac('sha1', secret.toString('ascii')) + hmac.update(content) + return hmac.digest('hex') + } +} + +class PasswordUtils { + constructor ({ + passwordSecret + } = {}) { + const passwordSecretType = getType(passwordSecret) + if (passwordSecretType === 'array') { + this.passwordSecret = passwordSecret.sort((a, b) => { + return a.version - b.version + }) + } else if (passwordSecretType === 'string') { + this.passwordSecret = [{ value: passwordSecret }] + } else { + throw new Error('Invalid password secret') + } + } + + getSecretByVersion (params = {}) { + const { + version + } = params + if (!version && version !== 0) { + return this.getOldestSecret() + } + if (this.passwordSecret.length === 1) { + return this.passwordSecret[0] + } + return this.passwordSecret.find(item => item.version === version) + } + + getLastestSecret () { + return this.passwordSecret[this.passwordSecret.length - 1] + } + + getOldestSecret () { + return this.passwordSecret[0] + } + + checkUserPassword (params = {}) { + const { + password, + passwordHash: passwordHashToCheck, + passwordSecretVersion, + autoRefresh = true + } = params + const currentPasswordSecret = this.getSecretByVersion({ + version: passwordSecretVersion + }) + if (!currentPasswordSecret) { + throw new Error('Invalid password version') + } + const { + value: passwordSecret + } = currentPasswordSecret + const { + passwordHash + } = this.generatePasswordHash({ + password, + passwordSecret, + passwordSecretVersion + }) + if (passwordHashToCheck !== passwordHash) { + return { + success: false + } + } + let refreshPasswordInfo + if (autoRefresh && passwordSecretVersion !== this.getLastestSecret().version) { + refreshPasswordInfo = this.generatePasswordHash({ + password + }) + } + return { + success: true, + refreshPasswordInfo + } + } + + generatePasswordHash (params = {}) { + let { + password, + passwordSecret, + passwordSecretVersion + } = params + if (getType(password) !== 'string') { + throw new Error('Invalid password') + } + password = password && password.trim() + if (!password) { + throw new Error('Invalid password') + } + if (!passwordSecret) { + const lastestSecret = this.getLastestSecret() + passwordSecret = lastestSecret.value + passwordSecretVersion = lastestSecret.version + } + return { + passwordHash: PasswordHashMethod['hmac-sha1'](password, passwordSecret), + version: passwordSecretVersion + } + } +} + +module.exports = PasswordUtils 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 new file mode 100644 index 0000000..ebacbb1 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/qq.js @@ -0,0 +1,152 @@ +const { + userCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +function getQQPlatform() { + const platform = this.clientPlatform + switch (platform) { + case 'app': + case 'app-plus': + return 'app' + case 'mp-qq': + return 'mp' + default: + throw new Error('Unsupported qq platform') + } +} + +async function saveQQUserKey({ + openid, + sessionKey, // QQ小程序用户sessionKey + accessToken, // App端QQ用户accessToken + accessTokenExpired // App端QQ用户accessToken过期时间 +} = {}) { + // 微信公众平台、开放平台refreshToken有效期均为30天(微信没有在网络请求里面返回30天这个值,务必注意未来可能出现调整,需及时更新此处逻辑)。 + // 此前QQ开放平台有调整过accessToken的过期时间:[access_token有效期由90天缩短至30天](https://wiki.connect.qq.com/%E3%80%90qq%E4%BA%92%E8%81%94%E3%80%91access_token%E6%9C%89%E6%95%88%E6%9C%9F%E8%B0%83%E6%95%B4) + const appId = this.getClientInfo().appId + const qqPlatform = getQQPlatform.call(this) + const keyObj = { + dcloudAppid: appId, + openid, + platform: 'qq-' + qqPlatform + } + switch (qqPlatform) { + case 'mp': + await this.uniOpenBridge.setSessionKey(keyObj, { + session_key: sessionKey + }, 30 * 24 * 60 * 60) + break + case 'app': + case 'h5': + case 'web': + await this.uniOpenBridge.setUserAccessToken(keyObj, { + access_token: accessToken, + access_token_expired: accessTokenExpired + }, accessTokenExpired ? + Math.floor((accessTokenExpired - Date.now()) / 1000) : + 30 * 24 * 60 * 60 + ) + break + default: + break + } +} + +function generateQQCache({ + sessionKey, // QQ小程序用户sessionKey + accessToken, // App端QQ用户accessToken + accessTokenExpired // App端QQ用户accessToken过期时间 +} = {}) { + const platform = getQQPlatform.call(this) + let cache + switch (platform) { + case 'app': + cache = { + access_token: accessToken, + access_token_expired: accessTokenExpired + } + break + case 'mp': + cache = { + session_key: sessionKey + } + break + default: + throw new Error('Unsupported qq platform') + } + return { + third_party: { + [`${platform}_qq`]: cache + } + } +} + +function getQQOpenid({ + userRecord +} = {}) { + const qqPlatform = getQQPlatform.call(this) + const appId = this.getClientInfo().appId + const qqOpenidObj = userRecord.qq_openid + if (!qqOpenidObj) { + return + } + return qqOpenidObj[`${qqPlatform}_${appId}`] || qqOpenidObj[qqPlatform] +} + +async function getQQCacheFallback({ + userRecord, + key +} = {}) { + const platform = getQQPlatform.call(this) + const thirdParty = userRecord && userRecord.third_party + if (!thirdParty) { + return + } + const qqCache = thirdParty[`${platform}_qq`] + return qqCache && qqCache[key] +} + +async function getQQCache({ + uid, + userRecord, + key +} = {}) { + const qqPlatform = getQQPlatform.call(this) + const appId = this.getClientInfo().appId + + if (!userRecord) { + const getUserRes = await userCollection.doc(uid).get() + userRecord = getUserRes.data[0] + } + if (!userRecord) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + const openid = getQQOpenid.call(this, { + userRecord + }) + const getCacheMethod = qqPlatform === 'mp' ? 'getSessionKey' : 'getUserAccessToken' + const userKey = await this.uniOpenBridge[getCacheMethod]({ + dcloudAppid: appId, + platform: 'qq-' + qqPlatform, + openid + }) + if (userKey) { + return userKey[key] + } + return getQQCacheFallback({ + userRecord, + key + }) +} + +module.exports = { + getQQPlatform, + generateQQCache, + getQQCache, + saveQQUserKey +} 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 new file mode 100644 index 0000000..2ecd186 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/register.js @@ -0,0 +1,211 @@ +const { + userCollection, + LOG_TYPE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + findUser +} = require('./account') +const { + getValidInviteCode, + generateInviteInfo +} = require('./fission') +const { + logout +} = require('./logout') +const PasswordUtils = require('./password') +const merge = require('lodash.merge') + +async function realPreRegister(params = {}) { + const { + user + } = params + const userMatched = await findUser({ + userQuery: user, + authorizedApp: this.getClientInfo().appId + }) + if (userMatched.length > 0) { + throw { + errCode: ERROR.ACCOUNT_EXISTS + } + } +} + +async function preRegister(params = {}) { + try { + await realPreRegister.call(this, params) + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.REGISTER + }) + throw error + } +} + +async function preRegisterWithPassword(params = {}) { + const { + user, + password + } = params + await preRegister.call(this, { + user + }) + const passwordUtils = new PasswordUtils({ + passwordSecret: this.config.passwordSecret + }) + const { + passwordHash, + version + } = passwordUtils.generatePasswordHash({ + password + }) + const extraData = { + password: passwordHash, + password_secret_version: version + } + return { + user, + extraData + } +} + +async function thirdPartyRegister({ + user = {} +} = {}) { + return { + mobileConfirmed: !!(user.mobile && user.mobile_confirmed) || false, + emailConfirmed: !!(user.email && user.email_confirmed) || false + } +} + +async function postRegister(params = {}) { + const { + user, + extraData = {}, + isThirdParty = false, + inviteCode + } = params + const { + appId, + appName, + appVersion, + appVersionCode, + channel, + scene, + clientIP, + osName, + uniIdToken + } = this.getClientInfo() + + merge(user, extraData) + + const registerChannel = channel || scene + user.register_env = { + appid: appId || '', + uni_platform: this.clientPlatform || '', + os_name: osName || '', + app_name: appName || '', + app_version: appVersion || '', + app_version_code: appVersionCode || '', + channel: registerChannel ? registerChannel + '' : '', // channel可能为数字,统一存为字符串 + client_ip: clientIP || '' + } + + user.register_date = Date.now() + user.dcloud_appid = [appId] + + if (user.username) { + user.username = user.username.toLowerCase() + } + if (user.email) { + user.email = user.email.toLowerCase() + } + + const { + autoSetInviteCode, // 注册时自动设置邀请码 + forceInviteCode // 必须有邀请码才允许注册,注意此逻辑不可对admin生效 + } = this.config + if (autoSetInviteCode) { + user.my_invite_code = await getValidInviteCode() + } + + const isAdmin = user.role && user.role.includes('admin') + + if (forceInviteCode && !isAdmin && !inviteCode) { + throw { + errCode: ERROR.INVALID_INVITE_CODE + } + } + + if (inviteCode) { + const { + inviterUid, + inviteTime + } = await generateInviteInfo({ + inviteCode + }) + user.inviter_uid = inviterUid + user.invite_time = inviteTime + } + + if (uniIdToken) { + try { + await logout.call(this) + } catch (error) {} + } + + const beforeRegister = this.hooks.beforeRegister + let userRecord = user + if (beforeRegister) { + userRecord = await beforeRegister({ + userRecord, + clientInfo: this.getClientInfo() + }) + } + + const { + id: uid + } = await userCollection.add(userRecord) + + const { + token, + tokenExpired + } = await this.uniIdCommon.createToken({ + uid + }) + + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: LOG_TYPE.REGISTER + }) + + return { + errCode: 0, + uid, + newToken: { + token, + tokenExpired + }, + ...( + isThirdParty + ? thirdPartyRegister({ + user: { + ...userRecord, + _id: uid + } + }) + : {} + ) + } +} + +module.exports = { + preRegister, + preRegisterWithPassword, + postRegister +} 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 new file mode 100644 index 0000000..360519a --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/relate.js @@ -0,0 +1,162 @@ +const { + findUser +} = require('./account') +const { + ERROR +} = require('../../common/error') +const { + userCollection, dbCmd, USER_IDENTIFIER +} = require('../../common/constants') +const { + getUserIdentifier +} = require('../../lib/utils/account') + +const { + batchFindObjctValue +} = require('../../common/utils') +const merge = require('lodash.merge') + +/** + * + * @param {object} param + * @param {string} param.uid 用户id + * @param {string} param.bindAccount 要绑定的三方账户、手机号或邮箱 + */ +async function preBind ({ + uid, + bindAccount, + logType +} = {}) { + const userMatched = await findUser({ + userQuery: bindAccount, + authorizedApp: this.getClientInfo().appId + }) + if (userMatched.length > 0) { + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: logType, + success: false + }) + throw { + errCode: ERROR.BIND_CONFLICT + } + } +} + +async function postBind ({ + uid, + extraData = {}, + bindAccount, + logType +} = {}) { + await userCollection.doc(uid).update(merge(bindAccount, extraData)) + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: logType + }) + return { + errCode: 0 + } +} + +async function preUnBind ({ + uid, + unBindAccount, + logType +}) { + const notUnBind = ['username', 'mobile', 'email'] + const userIdentifier = getUserIdentifier(unBindAccount) + const condition = Object.keys(userIdentifier).reduce((res, key) => { + if (userIdentifier[key]) { + if (notUnBind.includes(key)) { + throw { + errCode: ERROR.UNBIND_NOT_SUPPORTED + } + } + + res.push({ + [key]: userIdentifier[key] + }) + } + + return res + }, []) + const currentUnBindAccount = Object.keys(userIdentifier).reduce((res, key) => { + if (userIdentifier[key]) { + res.push(key) + } + return res + }, []) + const { data: users } = await userCollection.where(dbCmd.and( + { _id: uid }, + dbCmd.or(condition) + )).get() + + if (users.length <= 0) { + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: logType, + success: false + }) + throw { + errCode: ERROR.UNBIND_FAIL + } + } + + const [user] = users + const otherAccounts = batchFindObjctValue(user, Object.keys(USER_IDENTIFIER).filter(key => !notUnBind.includes(key) && !currentUnBindAccount.includes(key))) + let hasOtherAccountBind = false + + for (const key in otherAccounts) { + if (otherAccounts[key]) { + hasOtherAccountBind = true + break + } + } + + // 如果没有其他第三方登录方式 + if (!hasOtherAccountBind) { + // 存在用户名或者邮箱但是没有设置过没密码就提示设置密码 + if ((user.username || user.email) && !user.password) { + throw { + errCode: ERROR.UNBIND_PASSWORD_NOT_EXISTS + } + } + // 账号任何登录方式都没有就优先绑定手机号 + if (!user.mobile) { + throw { + errCode: ERROR.UNBIND_MOBILE_NOT_EXISTS + } + } + } +} + +async function postUnBind ({ + uid, + unBindAccount, + logType +}) { + await userCollection.doc(uid).update(unBindAccount) + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: logType + }) + return { + errCode: 0 + } +} + +module.exports = { + preBind, + postBind, + preUnBind, + postUnBind +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/sms.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/sms.js new file mode 100644 index 0000000..21c70e9 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/sms.js @@ -0,0 +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 +} 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 new file mode 100644 index 0000000..cd758fe --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/unified-login.js @@ -0,0 +1,98 @@ +const { + checkLoginUserRecord, + postLogin +} = require('./login') +const { + postRegister +} = require('./register') +const { + findUser +} = require('./account') +const { + ERROR +} = require('../../common/error') + +async function realPreUnifiedLogin (params = {}) { + const { + user, + type + } = params + const appId = this.getClientInfo().appId + const userMatched = await findUser({ + userQuery: user, + authorizedApp: appId + }) + if (userMatched.length === 0) { + if (type === 'login') { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + return { + type: 'register', + user + } + } if (userMatched.length === 1) { + if (type === 'register') { + throw { + errCode: ERROR.ACCOUNT_EXISTS + } + } + const userRecord = userMatched[0] + checkLoginUserRecord(userRecord) + return { + type: 'login', + user: userRecord + } + } else if (userMatched.length > 1) { + throw { + errCode: ERROR.ACCOUNT_CONFLICT + } + } +} + +async function preUnifiedLogin (params = {}) { + try { + const result = await realPreUnifiedLogin.call(this, params) + return result + } catch (error) { + await this.middleware.uniIdLog({ + success: false + }) + throw error + } +} + +async function postUnifiedLogin (params = {}) { + const { + user, + extraData = {}, + isThirdParty = false, + type, + inviteCode + } = params + let result + if (type === 'login') { + result = await postLogin.call(this, { + user, + extraData, + isThirdParty + }) + } else if (type === 'register') { + result = await postRegister.call(this, { + user, + extraData, + isThirdParty, + inviteCode + }) + } + return { + ...result, + type + } +} + +module.exports = { + preUnifiedLogin, + postUnifiedLogin +} 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 new file mode 100644 index 0000000..ba3cb44 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/univerify.js @@ -0,0 +1,27 @@ +async function getPhoneNumber ({ + // eslint-disable-next-line camelcase + access_token, + openid +} = {}) { + const requiredParams = ['apiKey', 'apiSecret'] + const univerifyConfig = (this.config.service && this.config.service.univerify) || {} + for (let i = 0; i < requiredParams.length; i++) { + const key = requiredParams[i] + if (!univerifyConfig[key]) { + throw new Error(`Missing config param: service.univerify.${key}`) + } + } + return uniCloud.getPhoneNumber({ + provider: 'univerify', + appid: this.getClientInfo().appId, + apiKey: univerifyConfig.apiKey, + apiSecret: univerifyConfig.apiSecret, + // eslint-disable-next-line camelcase + access_token, + openid + }) +} + +module.exports = { + getPhoneNumber +} 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 new file mode 100644 index 0000000..ced33b9 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/update-user-info.js @@ -0,0 +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 +} 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 new file mode 100644 index 0000000..7d3e0f3 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/utils.js @@ -0,0 +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 +} \ 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 new file mode 100644 index 0000000..acebc6b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/verify-code.js @@ -0,0 +1,152 @@ +const { + dbCmd, + verifyCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + getVerifyCode +} = require('../../common/utils') + +async function setVerifyCode ({ + mobile, + email, + code, + expiresIn, + scene +} = {}) { + const now = Date.now() + const record = { + mobile, + email, + scene, + code: code || getVerifyCode(), + state: 0, + ip: this.getClientInfo().clientIP, + created_date: now, + expired_date: now + expiresIn * 1000 + } + await verifyCollection.add(record) + return { + errCode: 0 + } +} + +async function setEmailVerifyCode ({ + email, + code, + expiresIn, + scene +} = {}) { + email = email && email.trim() + if (!email) { + throw { + errCode: ERROR.INVALID_EMAIL + } + } + email = email.toLowerCase() + return setVerifyCode.call(this, { + email, + code, + expiresIn, + scene + }) +} + +async function setMobileVerifyCode ({ + mobile, + code, + expiresIn, + scene +} = {}) { + mobile = mobile && mobile.trim() + if (!mobile) { + throw { + errCode: ERROR.INVALID_MOBILE + } + } + return setVerifyCode.call(this, { + mobile, + code, + expiresIn, + scene + }) +} + +async function verifyEmailCode ({ + email, + code, + scene +} = {}) { + email = email && email.trim() + if (!email) { + throw { + errCode: ERROR.INVALID_EMAIL + } + } + email = email.toLowerCase() + const { + data: codeRecord + } = await verifyCollection.where({ + email, + scene, + code, + state: 0, + expired_date: dbCmd.gt(Date.now()) + }).limit(1).get() + + if (codeRecord.length === 0) { + throw { + errCode: ERROR.EMAIL_VERIFY_CODE_ERROR + } + } + await verifyCollection.doc(codeRecord[0]._id).update({ + state: 1 + }) + return { + errCode: 0 + } +} + +async function verifyMobileCode ({ + mobile, + code, + scene +} = {}) { + mobile = mobile && mobile.trim() + if (!mobile) { + throw { + errCode: ERROR.INVALID_MOBILE + } + } + const { + data: codeRecord + } = await verifyCollection.where({ + mobile, + scene, + code, + state: 0, + expired_date: dbCmd.gt(Date.now()) + }).limit(1).get() + + if (codeRecord.length === 0) { + throw { + errCode: ERROR.MOBILE_VERIFY_CODE_ERROR + } + } + + await verifyCollection.doc(codeRecord[0]._id).update({ + state: 1 + }) + return { + errCode: 0 + } +} + +module.exports = { + verifyEmailCode, + verifyMobileCode, + setEmailVerifyCode, + setMobileVerifyCode +} 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 new file mode 100644 index 0000000..a01435d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/weixin.js @@ -0,0 +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.getClientInfo().userAgent + switch (platform) { + case 'app': + case 'app-plus': + return 'app' + case 'mp-weixin': + return 'mp' + case 'h5': + case 'web': + return userAgent.indexOf('MicroMessenger') > -1 ? 'h5' : 'web' + default: + throw new Error('Unsupported weixin platform') + } +} + +async function saveWeixinUserKey({ + openid, + sessionKey, // 微信小程序用户sessionKey + accessToken, // App端微信用户accessToken + refreshToken, // App端微信用户refreshToken + accessTokenExpired // App端微信用户accessToken过期时间 +} = {}) { + // 微信公众平台、开放平台refreshToken有效期均为30天(微信没有在网络请求里面返回30天这个值,务必注意未来可能出现调整,需及时更新此处逻辑)。 + // 此前QQ开放平台有调整过accessToken的过期时间:[access_token有效期由90天缩短至30天](https://wiki.connect.qq.com/%E3%80%90qq%E4%BA%92%E8%81%94%E3%80%91access_token%E6%9C%89%E6%95%88%E6%9C%9F%E8%B0%83%E6%95%B4) + + const appId = this.getClientInfo().appId + const weixinPlatform = getWeixinPlatform.call(this) + const keyObj = { + dcloudAppid: appId, + openid, + platform: 'weixin-' + weixinPlatform + } + switch (weixinPlatform) { + case 'mp': + await this.uniOpenBridge.setSessionKey(keyObj, { + session_key: sessionKey + }, 30 * 24 * 60 * 60) + break + case 'app': + case 'h5': + case 'web': + await this.uniOpenBridge.setUserAccessToken(keyObj, { + access_token: accessToken, + refresh_token: refreshToken, + access_token_expired: accessTokenExpired + }, 30 * 24 * 60 * 60) + break + default: + break + } +} + +async function saveSecureNetworkCache({ + code, + openid, + unionid, + sessionKey +}) { + const { + appId + } = this.getClientInfo() + 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.getClientInfo().appId + const wxOpenidObj = userRecord.wx_openid + if (!wxOpenidObj) { + return + } + return wxOpenidObj[`${weixinPlatform}_${appId}`] || wxOpenidObj[weixinPlatform] +} + +async function getWeixinCacheFallback({ + userRecord, + key +} = {}) { + const platform = getWeixinPlatform.call(this) + const thirdParty = userRecord && userRecord.third_party + if (!thirdParty) { + return + } + const weixinCache = thirdParty[`${platform}_weixin`] + return weixinCache && weixinCache[key] +} + +async function getWeixinCache({ + uid, + userRecord, + key +} = {}) { + const weixinPlatform = getWeixinPlatform.call(this) + const appId = this.getClientInfo().appId + if (!userRecord) { + const getUserRes = await userCollection.doc(uid).get() + userRecord = getUserRes.data[0] + } + if (!userRecord) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + const openid = getWeixinOpenid.call(this, { + userRecord + }) + const getCacheMethod = weixinPlatform === 'mp' ? 'getSessionKey' : 'getUserAccessToken' + const userKey = await this.uniOpenBridge[getCacheMethod]({ + dcloudAppid: appId, + platform: 'weixin-' + weixinPlatform, + openid + }) + if (userKey) { + return userKey[key] + } + return getWeixinCacheFallback({ + userRecord, + key + }) +} + +async function getWeixinAccessToken() { + const weixinPlatform = getWeixinPlatform.call(this) + const appId = this.getClientInfo().appId + + const cache = await this.uniOpenBridge.getAccessToken({ + dcloudAppid: appId, + platform: 'weixin-' + weixinPlatform + }) + + return cache.access_token +} +module.exports = { + decryptWeixinData, + getWeixinPlatform, + generateWeixinCache, + getWeixinCache, + saveWeixinUserKey, + getWeixinAccessToken, + 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 new file mode 100644 index 0000000..e333fe0 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/access-control.js @@ -0,0 +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 + }) +} 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 new file mode 100644 index 0000000..4c78b24 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/auth.js @@ -0,0 +1,17 @@ +module.exports = async function () { + if (this.authInfo) { // 多次执行auth时如果第一次成功后续不再执行 + return + } + const token = this.getUniIdToken() + const payload = await this.uniIdCommon.checkToken(token) + if (payload.errCode) { + throw payload + } + this.authInfo = payload + if (payload.token) { + this.response.newToken = { + token: payload.token, + tokenExpired: payload.tokenExpired + } + } +} 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 new file mode 100644 index 0000000..0af498a --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/index.js @@ -0,0 +1,7 @@ +module.exports = { + auth: require('./auth'), + uniIdLog: require('./uni-id-log'), + validate: require('./validate'), + accessControl: require('./access-control'), + ...require('./rbac') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/rbac.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/rbac.js new file mode 100644 index 0000000..f42ef8d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/rbac.js @@ -0,0 +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 +} 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 new file mode 100644 index 0000000..37ce655 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/uni-id-log.js @@ -0,0 +1,39 @@ +const db = uniCloud.database() +module.exports = async function ({ + data = {}, + success = true, + type = 'login' +} = {}) { + const now = Date.now() + const uniIdLogCollection = db.collection('uni-id-log') + const requiredDataKeyList = ['user_id', 'username', 'email', 'mobile'] + const dataCopy = {} + for (let i = 0; i < requiredDataKeyList.length; i++) { + const key = requiredDataKeyList[i] + if (key in data && typeof data[key] === 'string') { + dataCopy[key] = data[key] + } + } + const { + appId, + clientIP, + deviceId, + userAgent + } = this.getClientInfo() + const logData = { + appid: appId, + device_id: deviceId, + ip: clientIP, + type, + ua: userAgent, + create_date: now, + ...dataCopy + } + + if (success) { + logData.state = 1 + } else { + logData.state = 0 + } + return uniIdLogCollection.add(logData) +} 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 new file mode 100644 index 0000000..52ff047 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/validate.js @@ -0,0 +1,7 @@ +module.exports = function (value = {}, schema = {}) { + const validateRes = this.validator.validate(value, schema) + if (validateRes) { + delete validateRes.schemaKey + throw validateRes + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/close-account.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/close-account.js new file mode 100644 index 0000000..f1bdf96 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/close-account.js @@ -0,0 +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) +} 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 new file mode 100644 index 0000000..7b8599a --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/get-account-info.js @@ -0,0 +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) + } +} 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 new file mode 100644 index 0000000..f43cd27 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/index.js @@ -0,0 +1,7 @@ +module.exports = { + updatePwd: require('./update-pwd'), + resetPwdBySms: require('./reset-pwd-by-sms'), + resetPwdByEmail: require('./reset-pwd-by-email'), + closeAccount: require('./close-account'), + getAccountInfo: require('./get-account-info') +} 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 new file mode 100644 index 0000000..914a05e --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-email.js @@ -0,0 +1,119 @@ +const { + ERROR +} = require('../../common/error') +const { + getNeedCaptcha, + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + verifyEmailCode +} = require('../../lib/utils/verify-code') +const { + userCollection, + EMAIL_SCENE, + CAPTCHA_SCENE, + LOG_TYPE +} = require('../../common/constants') +const { + findUser +} = require('../../lib/utils/account') +const PasswordUtils = require('../../lib/utils/password') + +/** + * 通过邮箱验证码重置密码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#reset-pwd-by-email + * @param {object} params + * @param {string} params.email 邮箱 + * @param {string} params.code 邮箱验证码 + * @param {string} params.password 密码 + * @param {string} params.captcha 图形验证码 + * @returns {object} + */ +module.exports = async function (params = {}) { + const schema = { + email: 'email', + code: 'string', + password: 'password', + captcha: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + const { + email, + code, + password, + captcha + } = params + + const needCaptcha = await getNeedCaptcha.call(this, { + email, + type: LOG_TYPE.RESET_PWD_BY_EMAIL + }) + if (needCaptcha) { + await verifyCaptcha.call(this, { + captcha, + scene: CAPTCHA_SCENE.RESET_PWD_BY_EMAIL + }) + } + try { + // 验证手机号验证码,验证不通过时写入失败日志 + await verifyEmailCode({ + email, + code, + scene: EMAIL_SCENE.RESET_PWD_BY_EMAIL + }) + } catch (error) { + await this.middleware.uniIdLog({ + data: { + email + }, + type: LOG_TYPE.RESET_PWD_BY_EMAIL, + success: false + }) + throw error + } + // 根据手机号查找匹配的用户 + const userMatched = await findUser.call(this, { + userQuery: { + email + }, + authorizedApp: [this.getClientInfo().appId] + }) + if (userMatched.length === 0) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } else if (userMatched.length > 1) { + throw { + errCode: ERROR.ACCOUNT_CONFLICT + } + } + const { _id: uid } = userMatched[0] + const { + passwordHash, + version + } = new PasswordUtils({ + passwordSecret: this.config.passwordSecret + }).generatePasswordHash({ + password + }) + // 更新用户密码 + await userCollection.doc(uid).update({ + password: passwordHash, + password_secret_version: version, + valid_token_date: Date.now() + }) + + // 写入成功日志 + await this.middleware.uniIdLog({ + data: { + email + }, + type: LOG_TYPE.RESET_PWD_BY_SMS + }) + return { + errCode: 0 + } +} 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 new file mode 100644 index 0000000..c05b385 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-sms.js @@ -0,0 +1,119 @@ +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 userMatched = await findUser.call(this, { + userQuery: { + mobile + }, + authorizedApp: [this.getClientInfo().appId] + }) + if (userMatched.length === 0) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } else if (userMatched.length > 1) { + throw { + errCode: ERROR.ACCOUNT_CONFLICT + } + } + const { _id: uid } = userMatched[0] + const { + passwordHash, + version + } = new PasswordUtils({ + passwordSecret: this.config.passwordSecret + }).generatePasswordHash({ + password + }) + // 更新用户密码 + await userCollection.doc(uid).update({ + password: passwordHash, + password_secret_version: version, + valid_token_date: Date.now() + }) + + // 写入成功日志 + await this.middleware.uniIdLog({ + data: { + 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/update-pwd.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/update-pwd.js new file mode 100644 index 0000000..1faafc5 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/update-pwd.js @@ -0,0 +1,67 @@ +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({ + passwordSecret: this.config.passwordSecret + }) + const { + success: checkPasswordSuccess + } = passwordUtils.checkUserPassword({ + password: oldPassword, + passwordHash: userRecord.password, + passwordSecretVersion: userRecord.password_secret_version, + 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 new file mode 100644 index 0000000..6baa575 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/add-user.js @@ -0,0 +1,118 @@ +const { + findUser +} = require('../../lib/utils/account') +const { + ERROR +} = require('../../common/error') +const { + userCollection +} = require('../../common/constants') +const PasswordUtils = require('../../lib/utils/password') + +/** + * 新增用户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#add-user + * @param {Object} params + * @param {String} params.username 用户名 + * @param {String} params.password 密码 + * @param {String} params.nickname 昵称 + * @param {Array} params.authorizedApp 允许登录的AppID列表 + * @param {Array} params.role 用户角色列表 + * @param {String} params.mobile 手机号 + * @param {String} params.email 邮箱 + * @param {Array} params.tags 用户标签 + * @param {Number} params.status 用户状态 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + username: 'username', + password: 'password', + authorizedApp: { + required: false, + type: 'array' + }, // 指定允许登录的app,传空数组或不传时表示可以不可以在任何端登录 + nickname: { + required: false, + type: 'nickname' + }, + role: { + require: false, + type: 'array' + }, + mobile: { + required: false, + type: 'mobile' + }, + email: { + required: false, + type: 'email' + }, + tags: { + required: false, + type: 'array' + }, + status: { + required: false, + type: 'number' + } + } + this.middleware.validate(params, schema) + const { + username, + password, + authorizedApp, + nickname, + role, + mobile, + email, + tags, + status + } = params + const userMatched = await findUser({ + userQuery: { + username, + mobile, + email + }, + authorizedApp + }) + if (userMatched.length) { + throw { + errCode: ERROR.ACCOUNT_EXISTS + } + } + const passwordUtils = new PasswordUtils({ + passwordSecret: this.config.passwordSecret + }) + const { + passwordHash, + version + } = passwordUtils.generatePasswordHash({ + password + }) + const data = { + username, + password: passwordHash, + password_secret_version: version, + dcloud_appid: authorizedApp || [], + nickname, + role: role || [], + mobile, + email, + tags: tags || [], + status + } + if (email) { + data.email_confirmed = 1 + } + if (mobile) { + data.mobile_confirmed = 1 + } + + await userCollection.add(data) + return { + errCode: 0, + errMsg: '' + } +} 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 new file mode 100644 index 0000000..c8830f5 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/index.js @@ -0,0 +1,4 @@ +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 new file mode 100644 index 0000000..87d3152 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/update-user.js @@ -0,0 +1,128 @@ +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 + } + + // 更新用户名时验证用户名是否重新 + 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({ + passwordSecret: this.config.passwordSecret + }) + const { + passwordHash, + version + } = passwordUtils.generatePasswordHash({ + password + }) + + data.password = passwordHash + data.password_secret_version = version + } + + await userCollection.doc(uid).update(data) + + 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 new file mode 100644 index 0000000..476e234 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/get-supported-login-type.js @@ -0,0 +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 + } +} 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 new file mode 100644 index 0000000..e22f9f2 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/index.js @@ -0,0 +1,3 @@ +module.exports = { + getSupportedLoginType: require('./get-supported-login-type') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/accept-invite.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/accept-invite.js new file mode 100644 index 0000000..2461e06 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/accept-invite.js @@ -0,0 +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 + }) +} 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 new file mode 100644 index 0000000..93d4671 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/get-invited-user.js @@ -0,0 +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 +} 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 new file mode 100644 index 0000000..4a9bee1 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/index.js @@ -0,0 +1,4 @@ +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 new file mode 100644 index 0000000..f65f58b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/index.js @@ -0,0 +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') +} 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 new file mode 100644 index 0000000..d5d4631 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-alipay.js @@ -0,0 +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 + }) +} 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 new file mode 100644 index 0000000..5f39e62 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-apple.js @@ -0,0 +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 + }) +} 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 new file mode 100644 index 0000000..856449d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-baidu.js @@ -0,0 +1,9 @@ +/** + * 百度登录 + * @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 new file mode 100644 index 0000000..afe1f01 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-dingtalk.js @@ -0,0 +1,9 @@ +/** + * 钉钉登录 + * @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 new file mode 100644 index 0000000..8cd4ab5 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-douyin.js @@ -0,0 +1,9 @@ +/** + * 抖音登录 + * @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 new file mode 100644 index 0000000..c3af08f --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-code.js @@ -0,0 +1,9 @@ +/** + * 邮箱验证码登录 + * @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 new file mode 100644 index 0000000..0ebbf3a --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-link.js @@ -0,0 +1,9 @@ +/** + * 邮箱点击链接登录 + * @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 new file mode 100644 index 0000000..5c93bd4 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-facebook.js @@ -0,0 +1,9 @@ +/** + * 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 new file mode 100644 index 0000000..8054ece --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-google.js @@ -0,0 +1,9 @@ +/** + * 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 new file mode 100644 index 0000000..13379d7 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-qq.js @@ -0,0 +1,164 @@ +const { + initQQ +} = require('../../lib/third-party/index') +const { + ERROR +} = require('../../common/error') +const { + preUnifiedLogin, + postUnifiedLogin +} = require('../../lib/utils/unified-login') +const { + LOG_TYPE +} = require('../../common/constants') +const { + getQQPlatform, + generateQQCache, + saveQQUserKey +} = require('../../lib/utils/qq') +const url = require('url') + +/** + * QQ登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-qq + * @param {Object} params + * @param {String} params.code QQ小程序登录返回的code参数 + * @param {String} params.accessToken App端QQ登录返回的accessToken参数 + * @param {String} params.accessTokenExpired accessToken过期时间,由App端QQ登录返回的expires_in参数计算而来,单位:毫秒 + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + code: { + type: 'string', + required: false + }, + accessToken: { + type: 'string', + required: false + }, + accessTokenExpired: { + type: 'number', + required: false + }, + inviteCode: { + type: 'string', + required: false + } + } + this.middleware.validate(params, schema) + const { + code, + accessToken, + accessTokenExpired, + inviteCode + } = params + const { + appId + } = this.getClientInfo() + const qqApi = initQQ.call(this) + const qqPlatform = getQQPlatform.call(this) + let apiName + switch (qqPlatform) { + case 'mp': + apiName = 'code2Session' + break + case 'app': + apiName = 'getOpenidByToken' + break + default: + throw new Error('Unsupported qq platform') + } + let getQQAccountResult + try { + getQQAccountResult = await qqApi[apiName]({ + code, + accessToken + }) + } catch (error) { + console.error(error) + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.LOGIN + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + + const { + openid, + unionid, + // 保存下面的字段 + sessionKey // QQ小程序用户sessionKey + } = getQQAccountResult + + const { + type, + user + } = await preUnifiedLogin.call(this, { + user: { + qq_openid: { + [qqPlatform]: openid + }, + qq_unionid: unionid + } + }) + const extraData = { + qq_openid: { + [`${qqPlatform}_${appId}`]: openid + } + } + if (type === 'register' && qqPlatform !== 'mp') { + const { + nickname, + avatar + } = await qqApi.getUserInfo({ + accessToken, + openid + }) + // eslint-disable-next-line n/no-deprecated-api + const extName = url.parse(avatar).pathname.split('.').pop() + const cloudPath = `user/avatar/${openid.slice(-8) + Date.now()}-avatar.${extName}` + const getAvatarRes = await uniCloud.httpclient.request(avatar) + if (getAvatarRes.status >= 400) { + throw { + errCode: ERROR.GET_THIRD_PARTY_USER_INFO_FAILED + } + } + const { + fileID + } = await uniCloud.uploadFile({ + cloudPath, + fileContent: getAvatarRes.data + }) + extraData.nickname = nickname + extraData.avatar_file = { + name: cloudPath, + extname: extName, + url: fileID + } + } + await saveQQUserKey.call(this, { + openid, + sessionKey, + accessToken, + accessTokenExpired + }) + return postUnifiedLogin.call(this, { + user, + extraData: { + ...extraData, + ...generateQQCache.call(this, { + openid, + sessionKey, // QQ小程序用户sessionKey + accessToken, // App端QQ用户accessToken + accessTokenExpired // App端QQ用户accessToken过期时间 + }) + }, + isThirdParty: true, + type, + inviteCode + }) +} 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 new file mode 100644 index 0000000..915e9b6 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-sms.js @@ -0,0 +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 + }) +} 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 new file mode 100644 index 0000000..6a6d599 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-taobao.js @@ -0,0 +1,9 @@ +/** + * 淘宝登录 + * @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 new file mode 100644 index 0000000..133aadb --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-toutiao.js @@ -0,0 +1,9 @@ +/** + * 头条登录 + * @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 new file mode 100644 index 0000000..53e681c --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-univerify.js @@ -0,0 +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 + }) +} 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 new file mode 100644 index 0000000..496cdb4 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weibo.js @@ -0,0 +1,9 @@ +/** + * 微博登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByWeibo] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin-mobile.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin-mobile.js new file mode 100644 index 0000000..c27c2b2 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin-mobile.js @@ -0,0 +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 + }) +} 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 new file mode 100644 index 0000000..21d6071 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin.js @@ -0,0 +1,169 @@ +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.getClientInfo() + const weixinApi = initWeixin.call(this) + const weixinPlatform = getWeixinPlatform.call(this) + let apiName + switch (weixinPlatform) { + case 'mp': + apiName = 'code2Session' + break + case 'app': + case 'h5': + case 'web': + apiName = 'getOauthAccessToken' + break + default: + throw new Error('Unsupported weixin platform') + } + let getWeixinAccountResult + try { + getWeixinAccountResult = await weixinApi[apiName](code) + } catch (error) { + console.error(error) + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.LOGIN + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + + const { + openid, + unionid, + // 保存下面四个字段 + sessionKey, // 微信小程序用户sessionKey + accessToken, // App端微信用户accessToken + refreshToken, // App端微信用户refreshToken + expired: accessTokenExpired // App端微信用户accessToken过期时间 + } = getWeixinAccountResult + + 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 + }) + // eslint-disable-next-line n/no-deprecated-api + const avatarPath = url.parse(avatar).pathname + const extName = avatarPath.indexOf('.') > -1 ? url.parse(avatar).pathname.split('.').pop() : 'jpg' + const cloudPath = `user/avatar/${openid.slice(-8) + Date.now()}-avatar.${extName}` + const getAvatarRes = await uniCloud.httpclient.request(avatar) + if (getAvatarRes.status >= 400) { + throw { + errCode: ERROR.GET_THIRD_PARTY_USER_INFO_FAILED + } + } + const { + fileID + } = await uniCloud.uploadFile({ + cloudPath, + fileContent: getAvatarRes.data + }) + extraData.nickname = nickname + extraData.avatar_file = { + name: cloudPath, + extname: extName, + url: fileID + } + } + await saveWeixinUserKey.call(this, { + openid, + sessionKey, + accessToken, + refreshToken, + accessTokenExpired + }) + return postUnifiedLogin.call(this, { + user, + extraData: { + ...extraData, + ...generateWeixinCache.call(this, { + openid, + sessionKey, // 微信小程序用户sessionKey + accessToken, // App端微信用户accessToken + refreshToken, // App端微信用户refreshToken + accessTokenExpired // App端微信用户accessToken过期时间 + }) + }, + isThirdParty: true, + type, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login.js new file mode 100644 index 0000000..97e9cfe --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login.js @@ -0,0 +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 + }) +} 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 new file mode 100644 index 0000000..544be2b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/index.js @@ -0,0 +1,3 @@ +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 new file mode 100644 index 0000000..7d491c6 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/logout.js @@ -0,0 +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 + } +} 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 new file mode 100644 index 0000000..8f8a167 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/authorize-app-login.js @@ -0,0 +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 + } +} 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 new file mode 100644 index 0000000..ce9cc7b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/index.js @@ -0,0 +1,5 @@ +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 new file mode 100644 index 0000000..df82184 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/remove-authorized-app.js @@ -0,0 +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 + } +} 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 new file mode 100644 index 0000000..a438ef9 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/set-authorized-app.js @@ -0,0 +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 + } +} 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 new file mode 100644 index 0000000..0c0eb85 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/utils.js @@ -0,0 +1,36 @@ +const { + userCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + findUser +} = require('../../lib/utils/account') + +async function isAuthorizeApproved ({ + uid, + appIdList +} = {}) { + const getUserRes = await userCollection.doc(uid).get() + const userRecord = getUserRes.data[0] + if (!userRecord) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + const userMatched = await findUser({ + userQuery: userRecord, + authorizedApp: appIdList + }) + + if (userMatched.some(item => item._id !== uid)) { + throw { + errCode: ERROR.ACCOUNT_CONFLICT + } + } +} + +module.exports = { + isAuthorizeApproved +} 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 new file mode 100644 index 0000000..64ff603 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/index.js @@ -0,0 +1,5 @@ +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 new file mode 100644 index 0000000..4e2ff4a --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-admin.js @@ -0,0 +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.getClientInfo().appId + + if (!admin.dcloud_appid || (admin.dcloud_appid && admin.dcloud_appid.includes(appId))) { + return { + errCode: ERROR.ADMIN_EXISTS, + errMsg: this.t('uni-id-admin-exists') + } + } else { + return { + errCode: ERROR.ADMIN_EXISTS, + errMsg: this.t('uni-id-admin-exist-in-other-apps') + } + } + } + const { + user, + extraData + } = await preRegisterWithPassword.call(this, { + user: { + username + }, + password + }) + return postRegister.call(this, { + user, + extraData: { + ...extraData, + nickname, + role: ['admin'] + } + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user-by-email.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user-by-email.js new file mode 100644 index 0000000..b52c1d2 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user-by-email.js @@ -0,0 +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 + }) +} 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 new file mode 100644 index 0000000..130dece --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user.js @@ -0,0 +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 + }) +} 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 new file mode 100644 index 0000000..bdb451b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-alipay.js @@ -0,0 +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 + }) +} 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 new file mode 100644 index 0000000..eb87f8b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-apple.js @@ -0,0 +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 + }) +} 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 new file mode 100644 index 0000000..f4c2bd0 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-mp-weixin.js @@ -0,0 +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 + } +} 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 new file mode 100644 index 0000000..1640c2d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-sms.js @@ -0,0 +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 + } +} 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 new file mode 100644 index 0000000..2970c61 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-univerify.js @@ -0,0 +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 + } +} 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 new file mode 100644 index 0000000..ef801a2 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-qq.js @@ -0,0 +1,110 @@ +const { + preBind, + postBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + initQQ +} = require('../../lib/third-party/index') +const { + generateQQCache, + getQQPlatform, + saveQQUserKey +} = require('../../lib/utils/qq') + +/** + * 绑定QQ + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-qq + * @param {Object} params + * @param {String} params.code 小程序端QQ登录返回的code + * @param {String} params.accessToken APP端QQ登录返回的accessToken + * @param {String} params.accessTokenExpired accessToken过期时间,由App端QQ登录返回的expires_in参数计算而来,单位:毫秒 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + code: { + type: 'string', + required: false + }, + accessToken: { + type: 'string', + required: false + }, + accessTokenExpired: { + type: 'number', + required: false + } + } + this.middleware.validate(params, schema) + const uid = this.authInfo.uid + const { + code, + accessToken, + accessTokenExpired + } = params + const qqPlatform = getQQPlatform.call(this) + const appId = this.getClientInfo().appId + const qqApi = initQQ.call(this) + const clientPlatform = this.clientPlatform + const apiName = clientPlatform === 'mp-qq' ? 'code2Session' : 'getOpenidByToken' + let getQQAccountResult + try { + getQQAccountResult = await qqApi[apiName]({ + code, + accessToken + }) + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.BIND_QQ + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + + const { + openid, + unionid, + // 保存下面四个字段 + sessionKey // 微信小程序用户sessionKey + } = getQQAccountResult + + const bindAccount = { + qq_openid: { + [clientPlatform]: openid + }, + qq_unionid: unionid + } + await preBind.call(this, { + uid, + bindAccount, + logType: LOG_TYPE.BIND_QQ + }) + await saveQQUserKey.call(this, { + openid, + sessionKey, + accessToken, + accessTokenExpired + }) + return postBind.call(this, { + uid, + bindAccount, + extraData: { + qq_openid: { + [`${qqPlatform}_${appId}`]: openid + }, + ...generateQQCache.call(this, { + openid, + sessionKey + }) + }, + logType: LOG_TYPE.BIND_QQ + }) +} 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 new file mode 100644 index 0000000..b016507 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-weixin.js @@ -0,0 +1,100 @@ +const { + preBind, + postBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE +} = require('../../common/constants') +const { + generateWeixinCache, + saveWeixinUserKey, + getWeixinPlatform +} = require('../../lib/utils/weixin') +const { + initWeixin +} = require('../../lib/third-party/index') +const { + ERROR +} = require('../../common/error') + +/** + * 绑定微信 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-weixin + * @param {Object} params + * @param {String} params.code 微信登录返回的code + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + code: 'string' + } + this.middleware.validate(params, schema) + const uid = this.authInfo.uid + const { + code + } = params + const weixinPlatform = getWeixinPlatform.call(this) + const appId = this.getClientInfo().appId + + const weixinApi = initWeixin.call(this) + const clientPlatform = this.clientPlatform + const apiName = clientPlatform === 'mp-weixin' ? 'code2Session' : 'getOauthAccessToken' + let getWeixinAccountResult + try { + getWeixinAccountResult = await weixinApi[apiName](code) + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.BIND_WEIXIN + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + + const { + openid, + unionid, + // 保存下面四个字段 + sessionKey, // 微信小程序用户sessionKey + accessToken, // App端微信用户accessToken + refreshToken, // App端微信用户refreshToken + expired: accessTokenExpired // App端微信用户accessToken过期时间 + } = getWeixinAccountResult + + const bindAccount = { + wx_openid: { + [clientPlatform]: openid + }, + wx_unionid: unionid + } + await preBind.call(this, { + uid, + bindAccount, + logType: LOG_TYPE.BIND_WEIXIN + }) + await saveWeixinUserKey.call(this, { + openid, + sessionKey, + accessToken, + refreshToken, + accessTokenExpired + }) + return postBind.call(this, { + uid, + bindAccount, + extraData: { + wx_openid: { + [`${weixinPlatform}_${appId}`]: openid + }, + ...generateWeixinCache.call(this, { + openid, + sessionKey, // 微信小程序用户sessionKey + accessToken, // App端微信用户accessToken + refreshToken, // App端微信用户refreshToken + accessTokenExpired // App端微信用户accessToken过期时间 + }) + }, + logType: LOG_TYPE.BIND_WEIXIN + }) +} 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 new file mode 100644 index 0000000..4d99c02 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/index.js @@ -0,0 +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') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-alipay.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-alipay.js new file mode 100644 index 0000000..67bb43b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-alipay.js @@ -0,0 +1,32 @@ +const { + preUnBind, + postUnBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE, dbCmd +} = require('../../common/constants') + +/** + * 解绑支付宝 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-alipay + * @returns + */ +module.exports = async function () { + const { uid } = this.authInfo + + await preUnBind.call(this, { + uid, + unBindAccount: { + ali_openid: dbCmd.exists(true) + }, + logType: LOG_TYPE.UNBIND_ALIPAY + }) + + return await postUnBind.call(this, { + uid, + unBindAccount: { + ali_openid: dbCmd.remove() + }, + logType: LOG_TYPE.UNBIND_ALIPAY + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-apple.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-apple.js new file mode 100644 index 0000000..111c1bf --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-apple.js @@ -0,0 +1,32 @@ +const { + preUnBind, + postUnBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE, dbCmd +} = require('../../common/constants') + +/** + * 解绑apple + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-apple + * @returns + */ +module.exports = async function () { + const { uid } = this.authInfo + + await preUnBind.call(this, { + uid, + unBindAccount: { + apple_openid: dbCmd.exists(true) + }, + logType: LOG_TYPE.UNBIND_APPLE + }) + + return await postUnBind.call(this, { + uid, + unBindAccount: { + apple_openid: dbCmd.remove() + }, + logType: LOG_TYPE.UNBIND_APPLE + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-qq.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-qq.js new file mode 100644 index 0000000..c9c80b8 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-qq.js @@ -0,0 +1,46 @@ +const { + preUnBind, + postUnBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE, dbCmd +} = require('../../common/constants') +const { + getQQPlatform +} = require('../../lib/utils/qq') + +/** + * 解绑QQ + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-qq + * @returns + */ +module.exports = async function () { + const { uid } = this.authInfo + const { appId } = this.getClientInfo() + const qqPlatform = getQQPlatform.call(this) + + await preUnBind.call(this, { + uid, + unBindAccount: { + qq_openid: dbCmd.or([ + { + [qqPlatform]: dbCmd.exists(true) + }, + { + [`${qqPlatform}_${appId}`]: dbCmd.exists(true) + } + ]), + qq_unionid: dbCmd.exists(true) + }, + logType: LOG_TYPE.UNBIND_QQ + }) + + return await postUnBind.call(this, { + uid, + unBindAccount: { + qq_openid: dbCmd.remove(), + qq_unionid: dbCmd.remove() + }, + logType: LOG_TYPE.UNBIND_QQ + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-weixin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-weixin.js new file mode 100644 index 0000000..8770bbd --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-weixin.js @@ -0,0 +1,40 @@ +const { + preUnBind, + postUnBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE, dbCmd +} = require('../../common/constants') +const { + getWeixinPlatform +} = require('../../lib/utils/weixin') + +/** + * 解绑微信 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-weixin + * @returns + */ +module.exports = async function () { + const { uid } = this.authInfo + const weixinPlatform = getWeixinPlatform.call(this) + + await preUnBind.call(this, { + uid, + unBindAccount: { + wx_openid: { + [weixinPlatform]: dbCmd.exists(true) + }, + wx_unionid: dbCmd.exists(true) + }, + logType: LOG_TYPE.UNBIND_WEIXIN + }) + + return await postUnBind.call(this, { + uid, + unBindAccount: { + wx_openid: dbCmd.remove(), + wx_unionid: dbCmd.remove() + }, + logType: LOG_TYPE.UNBIND_WEIXIN + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/index.js new file mode 100644 index 0000000..0ec67a5 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/index.js @@ -0,0 +1,5 @@ +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 new file mode 100644 index 0000000..0c1837e --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/refresh-token.js @@ -0,0 +1,19 @@ +/** + * 刷新token + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#refresh-token + */ +module.exports = async function () { + const { + token, + tokenExpired + } = await this.uniIdCommon.refreshToken({ + token: this.getUniIdToken() + }) + return { + errCode: 0, + newToken: { + token, + tokenExpired + } + } +} 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 new file mode 100644 index 0000000..82ea0b3 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/secure-network-handshake-by-weixin.js @@ -0,0 +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 + } +} 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 new file mode 100644 index 0000000..68c18c6 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/set-push-cid.js @@ -0,0 +1,141 @@ +const { + deviceCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +async function setOpendbDevice ({ + pushClientId +} = {}) { + // 仅新增,如果存在进行更新操作 + const { + appId, + deviceId, + deviceBrand, + deviceModel, + osName, + osVersion, + osLanguage, + osTheme, + devicePixelRatio, + windowWidth, + windowHeight, + screenWidth, + screenHeight, + romName, + romVersion + } = this.getClientInfo() + const platform = this.clientPlatform + const now = Date.now() + + const db = uniCloud.database() + const opendbDeviceCollection = db.collection('opendb-device') + const getDeviceRes = await opendbDeviceCollection.where({ + device_id: deviceId + }).get() + const data = { + appid: appId, + device_id: deviceId, + vendor: deviceBrand, + model: deviceModel, + uni_platform: platform, + os_name: osName, + os_version: osVersion, + os_language: osLanguage, + os_theme: osTheme, + pixel_ratio: devicePixelRatio, + window_width: windowWidth, + window_height: windowHeight, + screen_width: screenWidth, + screen_height: screenHeight, + rom_name: romName, + rom_version: romVersion, + last_update_date: now, + push_clientid: pushClientId + } + if (getDeviceRes.data.length > 0) { + await opendbDeviceCollection.where({ + device_id: deviceId + }).update(data) + return + } + data.create_date = now + await opendbDeviceCollection.add(data) +} + +/** + * 更新device表的push_clien_id + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-push-cid + * @param {object} params + * @param {string} params.pushClientId 客户端pushClientId + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + pushClientId: 'string' + } + this.middleware.validate(params, schema) + const { + deviceId, + appId, + osName + } = this.getClientInfo() + let platform = this.clientPlatform + if (platform === 'app') { + platform += osName + } + + const { + uid, + exp + } = this.authInfo + const { pushClientId } = params + const tokenExpired = exp * 1000 + const getDeviceRes = await deviceCollection.where({ + device_id: deviceId + }).get() + console.log(getDeviceRes) + if (getDeviceRes.data.length > 1) { + return { + errCode: ERROR.SYSTEM_ERROR + } + } + const deviceRecord = getDeviceRes.data[0] + await setOpendbDevice.call(this, { + pushClientId + }) + if (!deviceRecord) { + await deviceCollection.add({ + user_id: uid, + device_id: deviceId, + token_expired: tokenExpired, + push_clientid: pushClientId, + appid: appId + }) + return { + errCode: 0 + } + } + // 同一用户允许更新token_expired,不同用户在token_expired小于Date.now()时允许更新。搭配逻辑:用户退出登录时将token_expired置0 + if ( + deviceRecord.user_id === uid || + (deviceRecord.token_expired < Date.now()) + ) { + await deviceCollection.where({ + device_id: deviceId + }).update({ + user_id: uid, + token_expired: tokenExpired, + push_clientid: pushClientId, + appid: appId + }) + return { + errCode: 0 + } + } + + return { + errCode: ERROR.SYSTEM_ERROR + } +} 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 new file mode 100644 index 0000000..1d77f5e --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/create-captcha.js @@ -0,0 +1,34 @@ +const { + CAPTCHA_SCENE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +/** + * 创建图形验证码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#create-captcha + * @param {Object} params + * @param {String} params.scene 图形验证码使用场景 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + scene: 'string' + } + this.middleware.validate(params, schema) + + const deviceId = this.getClientInfo().deviceId + const { + scene + } = params + if (!(Object.values(CAPTCHA_SCENE).includes(scene))) { + throw { + errCode: ERROR.INVALID_PARAM + } + } + return this.uniCaptcha.create({ + deviceId, + scene + }) +} 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 new file mode 100644 index 0000000..fba3524 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/index.js @@ -0,0 +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') +} 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 new file mode 100644 index 0000000..e5df246 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/refresh-captcha.js @@ -0,0 +1,34 @@ +const { + CAPTCHA_SCENE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +/** + * 刷新图形验证码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#refresh-captcha + * @param {Object} params + * @param {String} params.scene 图形验证码使用场景 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + scene: 'string' + } + this.middleware.validate(params, schema) + + const deviceId = this.getClientInfo().deviceId + const { + scene + } = params + if (!(Object.values(CAPTCHA_SCENE).includes(scene))) { + throw { + errCode: ERROR.INVALID_PARAM + } + } + return this.uniCaptcha.refresh({ + deviceId, + scene + }) +} 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 new file mode 100644 index 0000000..5ed867c --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-code.js @@ -0,0 +1,60 @@ +const { + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + EMAIL_SCENE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +/** + * 发送邮箱验证码,可用于登录、注册、绑定邮箱、修改密码等操作 + * @tutorial + * @param {Object} params + * @param {String} params.email 邮箱 + * @param {String} params.captcha 图形验证码 + * @param {String} params.scene 使用场景 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + email: 'email', + captcha: 'string', + scene: 'string' + } + this.middleware.validate(params, schema) + + const { + email, + captcha, + scene + } = params + + if (!(Object.values(EMAIL_SCENE).includes(scene))) { + throw { + errCode: ERROR.INVALID_PARAM + } + } + + await verifyCaptcha.call(this, { + scene: 'send-email-code', + captcha + }) + + // -- 测试代码 + require('../../lib/utils/verify-code') + .setEmailVerifyCode.call(this, { + email, + code: '123456', + expiresIn: 180, + scene + }) + return { + errCode: 'uni-id-invalid-mail-template', + errMsg: `已启动测试模式,直接使用:123456作为邮箱验证码即可。\n如果是正式项目,需自行实现发送邮件的相关功能` + } + // -- 测试代码 + + + //发送邮件--需自行实现 +} 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 new file mode 100644 index 0000000..f643434 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-link.js @@ -0,0 +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') +} 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 new file mode 100644 index 0000000..a29c101 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-sms-code.js @@ -0,0 +1,71 @@ +const { + sendSmsCode +} = require('../../lib/utils/sms') +const { + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + SMS_SCENE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +/** + * 发送短信验证码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#send-sms-code + * @param {Object} params + * @param {String} params.mobile 手机号 + * @param {String} params.captcha 图形验证码 + * @param {String} params.scene 短信验证码使用场景 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + mobile: 'mobile', + captcha: 'string', + scene: 'string' + } + this.middleware.validate(params, schema) + const { + mobile, + captcha, + scene + } = params + if (!(Object.values(SMS_SCENE).includes(scene))) { + throw { + errCode: ERROR.INVALID_PARAM + } + } + await verifyCaptcha.call(this, { + scene: 'send-sms-code', + captcha + }) + + // -- 测试代码 + const { + templateId + } = (this.config.service && + this.config.service.sms && + this.config.service.sms.scene && + this.config.service.sms.scene[scene]) || {} + if (!templateId) { + require('../../lib/utils/verify-code') + .setMobileVerifyCode.call(this, { + mobile: params.mobile, + code: '123456', + expiresIn: 180, + scene + }) + return { + errCode: 'uni-id-invalid-sms-template-id', + errMsg: `未找到scene=${scene},的短信模版templateId。\n已启动测试模式,直接使用:123456作为短信验证码即可。\n如果是正式项目,请在路径:/common/uni-config-center/uni-id/config.json中service->sms中配置密钥等信息\n更多详情:https://uniapp.dcloud.io/uniCloud/uni-id.html#config` + } + } + // -- 测试代码 + + return sendSmsCode.call(this, { + mobile, + scene + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/.bin/semver b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/.bin/semver new file mode 100644 index 0000000..10497aa --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/.bin/semver @@ -0,0 +1,15 @@ +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;; +esac + +if [ -x "$basedir/node" ]; then + "$basedir/node" "$basedir/../semver/bin/semver" "$@" + ret=$? +else + node "$basedir/../semver/bin/semver" "$@" + ret=$? +fi +exit $ret diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/.bin/semver.cmd b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/.bin/semver.cmd new file mode 100644 index 0000000..eb3aaa1 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/.bin/semver.cmd @@ -0,0 +1,17 @@ +@ECHO off +SETLOCAL +CALL :find_dp0 + +IF EXIST "%dp0%\node.exe" ( + SET "_prog=%dp0%\node.exe" +) ELSE ( + SET "_prog=node" + SET PATHEXT=%PATHEXT:;.JS;=;% +) + +"%_prog%" "%dp0%\..\semver\bin\semver" %* +ENDLOCAL +EXIT /b %errorlevel% +:find_dp0 +SET dp0=%~dp0 +EXIT /b diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/.bin/semver.ps1 b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/.bin/semver.ps1 new file mode 100644 index 0000000..a3315ff --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/.bin/semver.ps1 @@ -0,0 +1,18 @@ +#!/usr/bin/env pwsh +$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent + +$exe="" +if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { + # Fix case when both the Windows and Linux builds of Node + # are installed in the same directory + $exe=".exe" +} +$ret=0 +if (Test-Path "$basedir/node$exe") { + & "$basedir/node$exe" "$basedir/../semver/bin/semver" $args + $ret=$LASTEXITCODE +} else { + & "node$exe" "$basedir/../semver/bin/semver" $args + $ret=$LASTEXITCODE +} +exit $ret diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/.npmignore b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/.npmignore new file mode 100644 index 0000000..34e4f5c --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/.npmignore @@ -0,0 +1,2 @@ +.*.sw[mnop] +node_modules/ diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/.travis.yml b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/.travis.yml new file mode 100644 index 0000000..78e1c01 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: +- "0.11" +- "0.10" diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/LICENSE.txt b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/LICENSE.txt new file mode 100644 index 0000000..9a064f3 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/LICENSE.txt @@ -0,0 +1,12 @@ +Copyright (c) 2013, GoInstant Inc., a salesforce.com company +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +* Neither the name of salesforce.com, nor GoInstant, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/README.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/README.md new file mode 100644 index 0000000..4f227f5 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/README.md @@ -0,0 +1,50 @@ +# buffer-equal-constant-time + +Constant-time `Buffer` comparison for node.js. Should work with browserify too. + +[![Build Status](https://travis-ci.org/goinstant/buffer-equal-constant-time.png?branch=master)](https://travis-ci.org/goinstant/buffer-equal-constant-time) + +```sh + npm install buffer-equal-constant-time +``` + +# Usage + +```js + var bufferEq = require('buffer-equal-constant-time'); + + var a = new Buffer('asdf'); + var b = new Buffer('asdf'); + if (bufferEq(a,b)) { + // the same! + } else { + // different in at least one byte! + } +``` + +If you'd like to install an `.equal()` method onto the node.js `Buffer` and +`SlowBuffer` prototypes: + +```js + require('buffer-equal-constant-time').install(); + + var a = new Buffer('asdf'); + var b = new Buffer('asdf'); + if (a.equal(b)) { + // the same! + } else { + // different in at least one byte! + } +``` + +To get rid of the installed `.equal()` method, call `.restore()`: + +```js + require('buffer-equal-constant-time').restore(); +``` + +# Legal + +© 2013 GoInstant Inc., a salesforce.com company + +Licensed under the BSD 3-clause license. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/index.js new file mode 100644 index 0000000..5462c1f --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/index.js @@ -0,0 +1,41 @@ +/*jshint node:true */ +'use strict'; +var Buffer = require('buffer').Buffer; // browserify +var SlowBuffer = require('buffer').SlowBuffer; + +module.exports = bufferEq; + +function bufferEq(a, b) { + + // shortcutting on type is necessary for correctness + if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { + return false; + } + + // buffer sizes should be well-known information, so despite this + // shortcutting, it doesn't leak any information about the *contents* of the + // buffers. + if (a.length !== b.length) { + return false; + } + + var c = 0; + for (var i = 0; i < a.length; i++) { + /*jshint bitwise:false */ + c |= a[i] ^ b[i]; // XOR + } + return c === 0; +} + +bufferEq.install = function() { + Buffer.prototype.equal = SlowBuffer.prototype.equal = function equal(that) { + return bufferEq(this, that); + }; +}; + +var origBufEqual = Buffer.prototype.equal; +var origSlowBufEqual = SlowBuffer.prototype.equal; +bufferEq.restore = function() { + Buffer.prototype.equal = origBufEqual; + SlowBuffer.prototype.equal = origSlowBufEqual; +}; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/package.json new file mode 100644 index 0000000..fef3789 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/package.json @@ -0,0 +1,55 @@ +{ + "_from": "buffer-equal-constant-time@1.0.1", + "_id": "buffer-equal-constant-time@1.0.1", + "_inBundle": false, + "_integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "_location": "/buffer-equal-constant-time", + "_phantomChildren": {}, + "_requested": { + "type": "version", + "registry": true, + "raw": "buffer-equal-constant-time@1.0.1", + "name": "buffer-equal-constant-time", + "escapedName": "buffer-equal-constant-time", + "rawSpec": "1.0.1", + "saveSpec": null, + "fetchSpec": "1.0.1" + }, + "_requiredBy": [ + "/jwa" + ], + "_resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "_shasum": "f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819", + "_spec": "buffer-equal-constant-time@1.0.1", + "_where": "D:\\xm\\online-code\\hellounicloud\\uni_modules\\uni-id-pages\\uniCloud\\cloudfunctions\\uni-id-co\\node_modules\\jwa", + "author": { + "name": "GoInstant Inc., a salesforce.com company" + }, + "bugs": { + "url": "https://github.com/goinstant/buffer-equal-constant-time/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "Constant-time comparison of Buffers", + "devDependencies": { + "mocha": "~1.15.1" + }, + "homepage": "https://github.com/goinstant/buffer-equal-constant-time#readme", + "keywords": [ + "buffer", + "equal", + "constant-time", + "crypto" + ], + "license": "BSD-3-Clause", + "main": "index.js", + "name": "buffer-equal-constant-time", + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/goinstant/buffer-equal-constant-time.git" + }, + "scripts": { + "test": "mocha test.js" + }, + "version": "1.0.1" +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/test.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/test.js new file mode 100644 index 0000000..0bc972d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/buffer-equal-constant-time/test.js @@ -0,0 +1,42 @@ +/*jshint node:true */ +'use strict'; + +var bufferEq = require('./index'); +var assert = require('assert'); + +describe('buffer-equal-constant-time', function() { + var a = new Buffer('asdfasdf123456'); + var b = new Buffer('asdfasdf123456'); + var c = new Buffer('asdfasdf'); + + describe('bufferEq', function() { + it('says a == b', function() { + assert.strictEqual(bufferEq(a, b), true); + }); + + it('says a != c', function() { + assert.strictEqual(bufferEq(a, c), false); + }); + }); + + describe('install/restore', function() { + before(function() { + bufferEq.install(); + }); + after(function() { + bufferEq.restore(); + }); + + it('installed an .equal method', function() { + var SlowBuffer = require('buffer').SlowBuffer; + assert.ok(Buffer.prototype.equal); + assert.ok(SlowBuffer.prototype.equal); + }); + + it('infected existing Buffers', function() { + assert.strictEqual(a.equal(b), true); + assert.strictEqual(a.equal(c), false); + }); + }); + +}); diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/CODEOWNERS b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/CODEOWNERS new file mode 100644 index 0000000..4451d3d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/CODEOWNERS @@ -0,0 +1 @@ +* @omsmith diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/LICENSE b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/LICENSE new file mode 100644 index 0000000..8754ed6 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2015 D2L Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/README.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/README.md new file mode 100644 index 0000000..daa95d6 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/README.md @@ -0,0 +1,65 @@ +# ecdsa-sig-formatter + +[![Build Status](https://travis-ci.org/Brightspace/node-ecdsa-sig-formatter.svg?branch=master)](https://travis-ci.org/Brightspace/node-ecdsa-sig-formatter) [![Coverage Status](https://coveralls.io/repos/Brightspace/node-ecdsa-sig-formatter/badge.svg)](https://coveralls.io/r/Brightspace/node-ecdsa-sig-formatter) + +Translate between JOSE and ASN.1/DER encodings for ECDSA signatures + +## Install +```sh +npm install ecdsa-sig-formatter --save +``` + +## Usage +```js +var format = require('ecdsa-sig-formatter'); + +var derSignature = '..'; // asn.1/DER encoded ecdsa signature + +var joseSignature = format.derToJose(derSignature); + +``` + +### API + +--- + +#### `.derToJose(Buffer|String signature, String alg)` -> `String` + +Convert the ASN.1/DER encoded signature to a JOSE-style concatenated signature. +Returns a _base64 url_ encoded `String`. + +* If _signature_ is a `String`, it should be _base64_ encoded +* _alg_ must be one of _ES256_, _ES384_ or _ES512_ + +--- + +#### `.joseToDer(Buffer|String signature, String alg)` -> `Buffer` + +Convert the JOSE-style concatenated signature to an ASN.1/DER encoded +signature. Returns a `Buffer` + +* If _signature_ is a `String`, it should be _base64 url_ encoded +* _alg_ must be one of _ES256_, _ES384_ or _ES512_ + +## Contributing + +1. **Fork** the repository. Committing directly against this repository is + highly discouraged. + +2. Make your modifications in a branch, updating and writing new unit tests + as necessary in the `spec` directory. + +3. Ensure that all tests pass with `npm test` + +4. `rebase` your changes against master. *Do not merge*. + +5. Submit a pull request to this repository. Wait for tests to run and someone + to chime in. + +### Code Style + +This repository is configured with [EditorConfig][EditorConfig] and +[ESLint][ESLint] rules. + +[EditorConfig]: http://editorconfig.org/ +[ESLint]: http://eslint.org diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/package.json new file mode 100644 index 0000000..9f4ff66 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/package.json @@ -0,0 +1,73 @@ +{ + "_from": "ecdsa-sig-formatter@1.0.11", + "_id": "ecdsa-sig-formatter@1.0.11", + "_inBundle": false, + "_integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "_location": "/ecdsa-sig-formatter", + "_phantomChildren": {}, + "_requested": { + "type": "version", + "registry": true, + "raw": "ecdsa-sig-formatter@1.0.11", + "name": "ecdsa-sig-formatter", + "escapedName": "ecdsa-sig-formatter", + "rawSpec": "1.0.11", + "saveSpec": null, + "fetchSpec": "1.0.11" + }, + "_requiredBy": [ + "/jwa" + ], + "_resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "_shasum": "ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf", + "_spec": "ecdsa-sig-formatter@1.0.11", + "_where": "D:\\xm\\online-code\\hellounicloud\\uni_modules\\uni-id-pages\\uniCloud\\cloudfunctions\\uni-id-co\\node_modules\\jwa", + "author": { + "name": "D2L Corporation" + }, + "bugs": { + "url": "https://github.com/Brightspace/node-ecdsa-sig-formatter/issues" + }, + "bundleDependencies": false, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "deprecated": false, + "description": "Translate ECDSA signatures between ASN.1/DER and JOSE-style concatenation", + "devDependencies": { + "bench": "^0.3.6", + "chai": "^3.5.0", + "coveralls": "^2.11.9", + "eslint": "^2.12.0", + "eslint-config-brightspace": "^0.2.1", + "istanbul": "^0.4.3", + "jwk-to-pem": "^1.2.5", + "mocha": "^2.5.3", + "native-crypto": "^1.7.0" + }, + "homepage": "https://github.com/Brightspace/node-ecdsa-sig-formatter#readme", + "keywords": [ + "ecdsa", + "der", + "asn.1", + "jwt", + "jwa", + "jsonwebtoken", + "jose" + ], + "license": "Apache-2.0", + "main": "src/ecdsa-sig-formatter.js", + "name": "ecdsa-sig-formatter", + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/Brightspace/node-ecdsa-sig-formatter.git" + }, + "scripts": { + "check-style": "eslint .", + "pretest": "npm run check-style", + "report-cov": "cat ./coverage/lcov.info | coveralls", + "test": "istanbul cover --root src _mocha -- spec" + }, + "typings": "./src/ecdsa-sig-formatter.d.ts", + "version": "1.0.11" +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/src/ecdsa-sig-formatter.d.ts b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/src/ecdsa-sig-formatter.d.ts new file mode 100644 index 0000000..9693aa0 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/src/ecdsa-sig-formatter.d.ts @@ -0,0 +1,17 @@ +/// + +declare module "ecdsa-sig-formatter" { + /** + * Convert the ASN.1/DER encoded signature to a JOSE-style concatenated signature. Returns a base64 url encoded String. + * If signature is a String, it should be base64 encoded + * alg must be one of ES256, ES384 or ES512 + */ + export function derToJose(signature: Buffer | string, alg: string): string; + + /** + * Convert the JOSE-style concatenated signature to an ASN.1/DER encoded signature. Returns a Buffer + * If signature is a String, it should be base64 url encoded + * alg must be one of ES256, ES384 or ES512 + */ + export function joseToDer(signature: Buffer | string, alg: string): Buffer +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/src/ecdsa-sig-formatter.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/src/ecdsa-sig-formatter.js new file mode 100644 index 0000000..38eeb9b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/src/ecdsa-sig-formatter.js @@ -0,0 +1,187 @@ +'use strict'; + +var Buffer = require('safe-buffer').Buffer; + +var getParamBytesForAlg = require('./param-bytes-for-alg'); + +var MAX_OCTET = 0x80, + CLASS_UNIVERSAL = 0, + PRIMITIVE_BIT = 0x20, + TAG_SEQ = 0x10, + TAG_INT = 0x02, + ENCODED_TAG_SEQ = (TAG_SEQ | PRIMITIVE_BIT) | (CLASS_UNIVERSAL << 6), + ENCODED_TAG_INT = TAG_INT | (CLASS_UNIVERSAL << 6); + +function base64Url(base64) { + return base64 + .replace(/=/g, '') + .replace(/\+/g, '-') + .replace(/\//g, '_'); +} + +function signatureAsBuffer(signature) { + if (Buffer.isBuffer(signature)) { + return signature; + } else if ('string' === typeof signature) { + return Buffer.from(signature, 'base64'); + } + + throw new TypeError('ECDSA signature must be a Base64 string or a Buffer'); +} + +function derToJose(signature, alg) { + signature = signatureAsBuffer(signature); + var paramBytes = getParamBytesForAlg(alg); + + // the DER encoded param should at most be the param size, plus a padding + // zero, since due to being a signed integer + var maxEncodedParamLength = paramBytes + 1; + + var inputLength = signature.length; + + var offset = 0; + if (signature[offset++] !== ENCODED_TAG_SEQ) { + throw new Error('Could not find expected "seq"'); + } + + var seqLength = signature[offset++]; + if (seqLength === (MAX_OCTET | 1)) { + seqLength = signature[offset++]; + } + + if (inputLength - offset < seqLength) { + throw new Error('"seq" specified length of "' + seqLength + '", only "' + (inputLength - offset) + '" remaining'); + } + + if (signature[offset++] !== ENCODED_TAG_INT) { + throw new Error('Could not find expected "int" for "r"'); + } + + var rLength = signature[offset++]; + + if (inputLength - offset - 2 < rLength) { + throw new Error('"r" specified length of "' + rLength + '", only "' + (inputLength - offset - 2) + '" available'); + } + + if (maxEncodedParamLength < rLength) { + throw new Error('"r" specified length of "' + rLength + '", max of "' + maxEncodedParamLength + '" is acceptable'); + } + + var rOffset = offset; + offset += rLength; + + if (signature[offset++] !== ENCODED_TAG_INT) { + throw new Error('Could not find expected "int" for "s"'); + } + + var sLength = signature[offset++]; + + if (inputLength - offset !== sLength) { + throw new Error('"s" specified length of "' + sLength + '", expected "' + (inputLength - offset) + '"'); + } + + if (maxEncodedParamLength < sLength) { + throw new Error('"s" specified length of "' + sLength + '", max of "' + maxEncodedParamLength + '" is acceptable'); + } + + var sOffset = offset; + offset += sLength; + + if (offset !== inputLength) { + throw new Error('Expected to consume entire buffer, but "' + (inputLength - offset) + '" bytes remain'); + } + + var rPadding = paramBytes - rLength, + sPadding = paramBytes - sLength; + + var dst = Buffer.allocUnsafe(rPadding + rLength + sPadding + sLength); + + for (offset = 0; offset < rPadding; ++offset) { + dst[offset] = 0; + } + signature.copy(dst, offset, rOffset + Math.max(-rPadding, 0), rOffset + rLength); + + offset = paramBytes; + + for (var o = offset; offset < o + sPadding; ++offset) { + dst[offset] = 0; + } + signature.copy(dst, offset, sOffset + Math.max(-sPadding, 0), sOffset + sLength); + + dst = dst.toString('base64'); + dst = base64Url(dst); + + return dst; +} + +function countPadding(buf, start, stop) { + var padding = 0; + while (start + padding < stop && buf[start + padding] === 0) { + ++padding; + } + + var needsSign = buf[start + padding] >= MAX_OCTET; + if (needsSign) { + --padding; + } + + return padding; +} + +function joseToDer(signature, alg) { + signature = signatureAsBuffer(signature); + var paramBytes = getParamBytesForAlg(alg); + + var signatureBytes = signature.length; + if (signatureBytes !== paramBytes * 2) { + throw new TypeError('"' + alg + '" signatures must be "' + paramBytes * 2 + '" bytes, saw "' + signatureBytes + '"'); + } + + var rPadding = countPadding(signature, 0, paramBytes); + var sPadding = countPadding(signature, paramBytes, signature.length); + var rLength = paramBytes - rPadding; + var sLength = paramBytes - sPadding; + + var rsBytes = 1 + 1 + rLength + 1 + 1 + sLength; + + var shortLength = rsBytes < MAX_OCTET; + + var dst = Buffer.allocUnsafe((shortLength ? 2 : 3) + rsBytes); + + var offset = 0; + dst[offset++] = ENCODED_TAG_SEQ; + if (shortLength) { + // Bit 8 has value "0" + // bits 7-1 give the length. + dst[offset++] = rsBytes; + } else { + // Bit 8 of first octet has value "1" + // bits 7-1 give the number of additional length octets. + dst[offset++] = MAX_OCTET | 1; + // length, base 256 + dst[offset++] = rsBytes & 0xff; + } + dst[offset++] = ENCODED_TAG_INT; + dst[offset++] = rLength; + if (rPadding < 0) { + dst[offset++] = 0; + offset += signature.copy(dst, offset, 0, paramBytes); + } else { + offset += signature.copy(dst, offset, rPadding, paramBytes); + } + dst[offset++] = ENCODED_TAG_INT; + dst[offset++] = sLength; + if (sPadding < 0) { + dst[offset++] = 0; + signature.copy(dst, offset, paramBytes); + } else { + signature.copy(dst, offset, paramBytes + sPadding); + } + + return dst; +} + +module.exports = { + derToJose: derToJose, + joseToDer: joseToDer +}; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/src/param-bytes-for-alg.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/src/param-bytes-for-alg.js new file mode 100644 index 0000000..9fe67ac --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ecdsa-sig-formatter/src/param-bytes-for-alg.js @@ -0,0 +1,23 @@ +'use strict'; + +function getParamSize(keySize) { + var result = ((keySize / 8) | 0) + (keySize % 8 === 0 ? 0 : 1); + return result; +} + +var paramBytesForAlg = { + ES256: getParamSize(256), + ES384: getParamSize(384), + ES512: getParamSize(521) +}; + +function getParamBytesForAlg(alg) { + var paramBytes = paramBytesForAlg[alg]; + if (paramBytes) { + return paramBytes; + } + + throw new Error('Unknown algorithm "' + alg + '"'); +} + +module.exports = getParamBytesForAlg; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/CHANGELOG.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/CHANGELOG.md new file mode 100644 index 0000000..54364a2 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/CHANGELOG.md @@ -0,0 +1,476 @@ +# Change Log + + +All notable changes to this project will be documented in this file starting from version **v4.0.0**. +This project adheres to [Semantic Versioning](http://semver.org/). + +## 8.5.1 - 2019-03-18 + +### Bug fix + + - fix: ensure correct PS signing and verification (#585) ([e5874ae428ffc0465e6bd4e660f89f78b56a74a6](https://github.com/auth0/node-jsonwebtoken/commit/e5874ae428ffc0465e6bd4e660f89f78b56a74a6)), closes [#585](https://github.com/auth0/node-jsonwebtoken/issues/585) + +### Docs + + - README: fix markdown for algorithms table ([84e03ef70f9c44a3aef95a1dc122c8238854f683](https://github.com/auth0/node-jsonwebtoken/commit/84e03ef70f9c44a3aef95a1dc122c8238854f683)) + +## 8.5.0 - 2019-02-20 + +### New Functionality + + - feat: add PS JWA support for applicable node versions (#573) ([eefb9d9c6eec54718fa6e41306bda84788df7bec](https://github.com/auth0/node-jsonwebtoken/commit/eefb9d9c6eec54718fa6e41306bda84788df7bec)), closes [#573](https://github.com/auth0/node-jsonwebtoken/issues/573) + - Add complete option in jwt.verify (#522) ([8737789dd330cf9e7870f4df97fd52479adbac22](https://github.com/auth0/node-jsonwebtoken/commit/8737789dd330cf9e7870f4df97fd52479adbac22)), closes [#522](https://github.com/auth0/node-jsonwebtoken/issues/522) + + ### Test Improvements + + - Add tests for private claims in the payload (#555) ([5147852896755dc1291825e2e40556f964411fb2](https://github.com/auth0/node-jsonwebtoken/commit/5147852896755dc1291825e2e40556f964411fb2)), closes [#555](https://github.com/auth0/node-jsonwebtoken/issues/555) + - Force use_strict during testing (#577) ([7b60c127ceade36c33ff33be066e435802001c94](https://github.com/auth0/node-jsonwebtoken/commit/7b60c127ceade36c33ff33be066e435802001c94)), closes [#577](https://github.com/auth0/node-jsonwebtoken/issues/577) + - Refactor tests related to jti and jwtid (#544) ([7eebbc75ab89e01af5dacf2aae90fe05a13a1454](https://github.com/auth0/node-jsonwebtoken/commit/7eebbc75ab89e01af5dacf2aae90fe05a13a1454)), closes [#544](https://github.com/auth0/node-jsonwebtoken/issues/544) + - ci: remove nsp from tests (#569) ([da8f55c3c7b4dd0bfc07a2df228500fdd050242a](https://github.com/auth0/node-jsonwebtoken/commit/da8f55c3c7b4dd0bfc07a2df228500fdd050242a)), closes [#569](https://github.com/auth0/node-jsonwebtoken/issues/569) + +### Docs + +- Fix 'cert' token which isn't a cert (#554) ([0c24fe68cd2866cea6322016bf993cd897fefc98](https://github.com/auth0/node-jsonwebtoken/commit/0c24fe68cd2866cea6322016bf993cd897fefc98)), closes [#554](https://github.com/auth0/node-jsonwebtoken/issues/554) + + +## 8.4.0 - 2018-11-14 + +### New Functionality + + - Add verify option for nonce validation (#540) ([e7938f06fdf2ed3aa88745b72b8ae4ee66c2d0d0](https://github.com/auth0/node-jsonwebtoken/commit/e7938f06fdf2ed3aa88745b72b8ae4ee66c2d0d0)), closes [#540](https://github.com/auth0/node-jsonwebtoken/issues/540) + +### Bug Fixes + + - Updating Node version in Engines spec in package.json (#528) ([cfd1079305170a897dee6a5f55039783e6ee2711](https://github.com/auth0/node-jsonwebtoken/commit/cfd1079305170a897dee6a5f55039783e6ee2711)), closes [#528](https://github.com/auth0/node-jsonwebtoken/issues/528) [#509](https://github.com/auth0/node-jsonwebtoken/issues/509) + - Fixed error message when empty string passed as expiresIn or notBefore option (#531) ([7f9604ac98d4d0ff8d873c3d2b2ea64bd285cb76](https://github.com/auth0/node-jsonwebtoken/commit/7f9604ac98d4d0ff8d873c3d2b2ea64bd285cb76)), closes [#531](https://github.com/auth0/node-jsonwebtoken/issues/531) + +### Docs + + - Update README.md (#527) ([b76f2a80f5229ee5cde321dd2ff14aa5df16d283](https://github.com/auth0/node-jsonwebtoken/commit/b76f2a80f5229ee5cde321dd2ff14aa5df16d283)), closes [#527](https://github.com/auth0/node-jsonwebtoken/issues/527) + - Update README.md (#538) ([1956c4006472fd285b8a85074257cbdbe9131cbf](https://github.com/auth0/node-jsonwebtoken/commit/1956c4006472fd285b8a85074257cbdbe9131cbf)), closes [#538](https://github.com/auth0/node-jsonwebtoken/issues/538) + - Edited the README.md to make certain parts of the document for the api easier to read, emphasizing the examples. (#548) ([dc89a641293d42f72ecfc623ce2eabc33954cb9d](https://github.com/auth0/node-jsonwebtoken/commit/dc89a641293d42f72ecfc623ce2eabc33954cb9d)), closes [#548](https://github.com/auth0/node-jsonwebtoken/issues/548) + - Document NotBeforeError (#529) ([29cd654b956529e939ae8f8c30b9da7063aad501](https://github.com/auth0/node-jsonwebtoken/commit/29cd654b956529e939ae8f8c30b9da7063aad501)), closes [#529](https://github.com/auth0/node-jsonwebtoken/issues/529) + +### Test Improvements + + - Use lolex for faking date in tests (#491) ([677ead6d64482f2067b11437dda07309abe73cfa](https://github.com/auth0/node-jsonwebtoken/commit/677ead6d64482f2067b11437dda07309abe73cfa)), closes [#491](https://github.com/auth0/node-jsonwebtoken/issues/491) + - Update dependencies used for running tests (#518) ([5498bdc4865ffb2ba2fd44d889fad7e83873bb33](https://github.com/auth0/node-jsonwebtoken/commit/5498bdc4865ffb2ba2fd44d889fad7e83873bb33)), closes [#518](https://github.com/auth0/node-jsonwebtoken/issues/518) + - Minor test refactoring for recently added tests (#504) ([e2860a9d2a412627d79741a95bc7159971b923b9](https://github.com/auth0/node-jsonwebtoken/commit/e2860a9d2a412627d79741a95bc7159971b923b9)), closes [#504](https://github.com/auth0/node-jsonwebtoken/issues/504) + - Create and implement async/sync test helpers (#523) ([683d8a9b31ad6327948f84268bd2c8e4350779d1](https://github.com/auth0/node-jsonwebtoken/commit/683d8a9b31ad6327948f84268bd2c8e4350779d1)), closes [#523](https://github.com/auth0/node-jsonwebtoken/issues/523) + - Refactor tests related to audience and aud (#503) ([53d405e0223cce7c83cb51ecf290ca6bec1e9679](https://github.com/auth0/node-jsonwebtoken/commit/53d405e0223cce7c83cb51ecf290ca6bec1e9679)), closes [#503](https://github.com/auth0/node-jsonwebtoken/issues/503) + - Refactor tests related to expiresIn and exp (#501) ([72f0d9e5b11a99082250665d1200c58182903fa6](https://github.com/auth0/node-jsonwebtoken/commit/72f0d9e5b11a99082250665d1200c58182903fa6)), closes [#501](https://github.com/auth0/node-jsonwebtoken/issues/501) + - Refactor tests related to iat and maxAge (#507) ([877bd57ab2aca9b7d230805b21f921baed3da169](https://github.com/auth0/node-jsonwebtoken/commit/877bd57ab2aca9b7d230805b21f921baed3da169)), closes [#507](https://github.com/auth0/node-jsonwebtoken/issues/507) + - Refactor tests related to iss and issuer (#543) ([0906a3fa80f52f959ac1b6343d3024ce5c7e9dea](https://github.com/auth0/node-jsonwebtoken/commit/0906a3fa80f52f959ac1b6343d3024ce5c7e9dea)), closes [#543](https://github.com/auth0/node-jsonwebtoken/issues/543) + - Refactor tests related to kid and keyid (#545) ([88645427a0adb420bd3e149199a2a6bf1e17277e](https://github.com/auth0/node-jsonwebtoken/commit/88645427a0adb420bd3e149199a2a6bf1e17277e)), closes [#545](https://github.com/auth0/node-jsonwebtoken/issues/545) + - Refactor tests related to notBefore and nbf (#497) ([39adf87a6faef3df984140f88e6724ddd709fd89](https://github.com/auth0/node-jsonwebtoken/commit/39adf87a6faef3df984140f88e6724ddd709fd89)), closes [#497](https://github.com/auth0/node-jsonwebtoken/issues/497) + - Refactor tests related to subject and sub (#505) ([5a7fa23c0b4ac6c25304dab8767ef840b43a0eca](https://github.com/auth0/node-jsonwebtoken/commit/5a7fa23c0b4ac6c25304dab8767ef840b43a0eca)), closes [#505](https://github.com/auth0/node-jsonwebtoken/issues/505) + - Implement async/sync tests for exp claim (#536) ([9ae3f207ac64b7450ea0a3434418f5ca58d8125e](https://github.com/auth0/node-jsonwebtoken/commit/9ae3f207ac64b7450ea0a3434418f5ca58d8125e)), closes [#536](https://github.com/auth0/node-jsonwebtoken/issues/536) + - Implement async/sync tests for nbf claim (#537) ([88bc965061ed65299a395f42a100fb8f8c3c683e](https://github.com/auth0/node-jsonwebtoken/commit/88bc965061ed65299a395f42a100fb8f8c3c683e)), closes [#537](https://github.com/auth0/node-jsonwebtoken/issues/537) + - Implement async/sync tests for sub claim (#534) ([342b07bb105a35739eb91265ba5b9dd33c300fc6](https://github.com/auth0/node-jsonwebtoken/commit/342b07bb105a35739eb91265ba5b9dd33c300fc6)), closes [#534](https://github.com/auth0/node-jsonwebtoken/issues/534) + - Implement async/sync tests for the aud claim (#535) ([1c8ff5a68e6da73af2809c9d87faaf78602c99bb](https://github.com/auth0/node-jsonwebtoken/commit/1c8ff5a68e6da73af2809c9d87faaf78602c99bb)), closes [#535](https://github.com/auth0/node-jsonwebtoken/issues/535) + +### CI + + - Added Istanbul to check test-coverage (#468) ([9676a8306428a045e34c3987bd0680fb952b44e3](https://github.com/auth0/node-jsonwebtoken/commit/9676a8306428a045e34c3987bd0680fb952b44e3)), closes [#468](https://github.com/auth0/node-jsonwebtoken/issues/468) + - Complete ESLint conversion and cleanup (#490) ([cb1d2e1e40547f7ecf29fa6635041df6cbba7f40](https://github.com/auth0/node-jsonwebtoken/commit/cb1d2e1e40547f7ecf29fa6635041df6cbba7f40)), closes [#490](https://github.com/auth0/node-jsonwebtoken/issues/490) + - Make code-coverage mandatory when running tests (#495) ([fb0084a78535bfea8d0087c0870e7e3614a2cbe5](https://github.com/auth0/node-jsonwebtoken/commit/fb0084a78535bfea8d0087c0870e7e3614a2cbe5)), closes [#495](https://github.com/auth0/node-jsonwebtoken/issues/495) + + +## 8.3.0 - 2018-06-11 + + - docs: add some clarifications (#473) ([cd33cc81f06068b9df6c224d300dc6f70d8904ab](https://github.com/auth0/node-jsonwebtoken/commit/cd33cc81f06068b9df6c224d300dc6f70d8904ab)), closes [#473](https://github.com/auth0/node-jsonwebtoken/issues/473) + - ci: fix ci execution, remove not needed script (#472) ([c8ff7b2c3ffcd954a64a0273c20a7d1b22339aa5](https://github.com/auth0/node-jsonwebtoken/commit/c8ff7b2c3ffcd954a64a0273c20a7d1b22339aa5)), closes [#472](https://github.com/auth0/node-jsonwebtoken/issues/472) + - new feature: Secret callback revisited (#480) ([d01cc7bcbdeb606d997a580f967b3169fcc622ba](https://github.com/auth0/node-jsonwebtoken/commit/d01cc7bcbdeb606d997a580f967b3169fcc622ba)), closes [#480](https://github.com/auth0/node-jsonwebtoken/issues/480) + - docs:Update README.md (#461) ([f0e0954505f274da95a8d9603598e455b4d2c894](https://github.com/auth0/node-jsonwebtoken/commit/f0e0954505f274da95a8d9603598e455b4d2c894)), closes [#461](https://github.com/auth0/node-jsonwebtoken/issues/461) + + +## 8.2.2 - 2018-05-30 + + - security: deps: jws@3.1.5 (#477) ([ebde9b7cc75cb7ab5176de7ebc4a1d6a8f05bd51](https://github.com/auth0/node-jsonwebtoken/commit/ebde9b7cc75cb7ab5176de7ebc4a1d6a8f05bd51)), closes [#465](https://github.com/auth0/node-jsonwebtoken/issues/465) + - docs: add some clarifications (#473) ([cd33cc81f06068b9df6c224d300dc6f70d8904ab](https://github.com/auth0/node-jsonwebtoken/commit/cd33cc81f06068b9df6c224d300dc6f70d8904ab)), closes [#473](https://github.com/auth0/node-jsonwebtoken/issues/473) + - ci: fix ci execution, remove not needed script (#472) ([c8ff7b2c3ffcd954a64a0273c20a7d1b22339aa5](https://github.com/auth0/node-jsonwebtoken/commit/c8ff7b2c3ffcd954a64a0273c20a7d1b22339aa5)), closes [#472](https://github.com/auth0/node-jsonwebtoken/issues/472) + - docs: Update README.md (#461) ([f0e0954505f274da95a8d9603598e455b4d2c894](https://github.com/auth0/node-jsonwebtoken/commit/f0e0954505f274da95a8d9603598e455b4d2c894)), closes [#461](https://github.com/auth0/node-jsonwebtoken/issues/461) + + +## 8.2.1 - 2018-04-05 + + - bug fix: Check payload is not null when decoded. (#444) ([1232ae9352ce5fd1ca6c593291ce6ad0834a1ff5](https://github.com/auth0/node-jsonwebtoken/commit/1232ae9352ce5fd1ca6c593291ce6ad0834a1ff5)) + - docs: Clarify that buffer/string payloads must be JSON (#442) ([e8ac1be7565a3fd986d40cb5e31a9f6c4d9aed1b](https://github.com/auth0/node-jsonwebtoken/commit/e8ac1be7565a3fd986d40cb5e31a9f6c4d9aed1b)) + + +## 8.2.0 - 2018-03-02 + + - Add a new mutatePayload option (#446) ([d6d7c5e5103f05a92d3633ac190d3025a0455be0](https://github.com/auth0/node-jsonwebtoken/commit/d6d7c5e5103f05a92d3633ac190d3025a0455be0)) + + +## 8.1.1 - 2018-01-22 + + - ci: add newer node versions to build matrix (#428) ([83f3eee44e122da06f812d7da4ace1fa26c24d9d](https://github.com/auth0/node-jsonwebtoken/commit/83f3eee44e122da06f812d7da4ace1fa26c24d9d)) + - deps: Bump ms version to add support for negative numbers (#438) ([25e0e624545eaef76f3c324a134bf103bc394724](https://github.com/auth0/node-jsonwebtoken/commit/25e0e624545eaef76f3c324a134bf103bc394724)) + - docs: Minor typo (#424) ([dddcb73ac05de11b81feeb629f6cf78dd03d2047](https://github.com/auth0/node-jsonwebtoken/commit/dddcb73ac05de11b81feeb629f6cf78dd03d2047)) + - bug fix: Not Before (nbf) calculated based on iat/timestamp (#437) ([2764a64908d97c043d62eba0bf6c600674f9a6d6](https://github.com/auth0/node-jsonwebtoken/commit/2764a64908d97c043d62eba0bf6c600674f9a6d6)), closes [#435](https://github.com/auth0/node-jsonwebtoken/issues/435) + + +## 8.1.0 - 2017-10-09 + + - #402: Don't fail if captureStackTrace is not a function (#410) ([77ee965d9081faaf21650f266399f203f69533c5](https://github.com/auth0/node-jsonwebtoken/commit/77ee965d9081faaf21650f266399f203f69533c5)) + - #403: Clarify error wording for "Expected object" error. (#409) ([bb27eb346f0ff675a320b2de16b391a7cfeadc58](https://github.com/auth0/node-jsonwebtoken/commit/bb27eb346f0ff675a320b2de16b391a7cfeadc58)) + - Enhance audience check to verify against regular expressions (#398) ([81501a17da230af7b74a3f7535ab5cd3a19c8315](https://github.com/auth0/node-jsonwebtoken/commit/81501a17da230af7b74a3f7535ab5cd3a19c8315)) + + +## 8.0.1 - 2017-09-12 + + - Remove `lodash.isarray` dependency (#394) ([7508e8957cb1c778f72fa9a363a7b135b3c9c36d](https://github.com/auth0/node-jsonwebtoken/commit/7508e8957cb1c778f72fa9a363a7b135b3c9c36d)) + +## 8.0.0 - 2017-09-06 + + **Breaking changes: See [Migration notes from v7](https://github.com/auth0/node-jsonwebtoken/wiki/Migration-Notes:-v7-to-v8)** + + - docs: readme, migration notes ([12cd8f7f47224f904f6b8f39d1dee73775de4f6f](https://github.com/auth0/node-jsonwebtoken/commit/12cd8f7f47224f904f6b8f39d1dee73775de4f6f)) + - verify: remove process.nextTick (#302) ([3305cf04e3f674b9fb7e27c9b14ddd159650ff82](https://github.com/auth0/node-jsonwebtoken/commit/3305cf04e3f674b9fb7e27c9b14ddd159650ff82)) + - Reduce size of NPM package (#347) ([0be5409ac6592eeaae373dce91ec992fa101bd8a](https://github.com/auth0/node-jsonwebtoken/commit/0be5409ac6592eeaae373dce91ec992fa101bd8a)) + - Remove joi to shrink module size (#348) ([2e7e68dbd59e845cdd940afae0a296f48438445f](https://github.com/auth0/node-jsonwebtoken/commit/2e7e68dbd59e845cdd940afae0a296f48438445f)) + - maxAge: Add validation to timespan result ([66a4f8b996c8357727ce62a84605a005b2f5eb18](https://github.com/auth0/node-jsonwebtoken/commit/66a4f8b996c8357727ce62a84605a005b2f5eb18)) + +## 7.4.3 - 2017-08-17 + + - Fix breaking change on 7.4.2 for empty secret + "none" algorithm (sync code style) ([PR 386](https://github.com/auth0/node-jsonwebtoken/pull/386)) + +## 7.4.2 - 2017-08-04 + + - bugfix: sign: add check to be sure secret has a value ([c584d1cbc34b788977b36f17cd57ab2212f1230e](https://github.com/auth0/node-jsonwebtoken/commit/c584d1cbc34b788977b36f17cd57ab2212f1230e)) + - docs: about refreshing tokens ([016fc10b847bfbb76b82171cb530f32d7da2001b](https://github.com/auth0/node-jsonwebtoken/commit/016fc10b847bfbb76b82171cb530f32d7da2001b)) + - docs: verifying with base64 encoded secrets ([c25e9906801f89605080cc71b3ee23a5e45a5811](https://github.com/auth0/node-jsonwebtoken/commit/c25e9906801f89605080cc71b3ee23a5e45a5811)) + - tests: Add tests for ES256 ([89900ea00735f76b04f437c9f542285b420fa9cb](https://github.com/auth0/node-jsonwebtoken/commit/89900ea00735f76b04f437c9f542285b420fa9cb)) + - docs: document keyid as option (#361) ([00086c2c006d7fc1a47bae02fa87d194d79aa558](https://github.com/auth0/node-jsonwebtoken/commit/00086c2c006d7fc1a47bae02fa87d194d79aa558)) + - docs: readme: Using private key with passpharase (#353) ([27a7f1d4f35b662426ff0270526d48658da4c8b7](https://github.com/auth0/node-jsonwebtoken/commit/27a7f1d4f35b662426ff0270526d48658da4c8b7)) + +## 7.4.1 - 2017-05-17 + + - bump ms to v2 due a ReDoS vulnerability (#352) ([adcfd6ae4088c838769d169f8cd9154265aa13e0](https://github.com/auth0/node-jsonwebtoken/commit/adcfd6ae4088c838769d169f8cd9154265aa13e0)) + +## 7.4.0 - 2017-04-24 + + - Add docs about numeric date fields ([659f73119900a4d837650d9b3f5af4e64a2f843b](https://github.com/auth0/node-jsonwebtoken/commit/659f73119900a4d837650d9b3f5af4e64a2f843b)) + - Make Options object optional for callback-ish sign ([e202c4fd00c35a24e9ab606eab89186ade13d0cc](https://github.com/auth0/node-jsonwebtoken/commit/e202c4fd00c35a24e9ab606eab89186ade13d0cc)) + +## 7.3.0 - 2017-02-13 + + - Add more information to `maxAge` option in README ([1b0592e99cc8def293eed177e2575fa7f1cf7aa5](https://github.com/auth0/node-jsonwebtoken/commit/1b0592e99cc8def293eed177e2575fa7f1cf7aa5)) + - Add `clockTimestamp` option to `verify()` you can set the current time in seconds with it (#274) ([8fdc1504f4325e7003894ffea078da9cba5208d9](https://github.com/auth0/node-jsonwebtoken/commit/8fdc1504f4325e7003894ffea078da9cba5208d9)) + - Fix handling non string tokens on `verify()` input (#305) ([1b6ec8d466504f58c5a6e2dae3360c828bad92fb](https://github.com/auth0/node-jsonwebtoken/commit/1b6ec8d466504f58c5a6e2dae3360c828bad92fb)), closes [#305](https://github.com/auth0/node-jsonwebtoken/issues/305) + - Fixed a simple typo in docs (#287) ([a54240384e24e18c00e75884295306db311d0cb7](https://github.com/auth0/node-jsonwebtoken/commit/a54240384e24e18c00e75884295306db311d0cb7)), closes [#287](https://github.com/auth0/node-jsonwebtoken/issues/287) + - Raise jws.decode error to avoid confusion with "invalid token" error (#294) ([7f68fe06c88d5c5653785bd66bc68c5b20e1bd8e](https://github.com/auth0/node-jsonwebtoken/commit/7f68fe06c88d5c5653785bd66bc68c5b20e1bd8e)) + - rauchg/ms.js changed to zeit/ms (#303) ([35d84152a6b716d757cb5b1dd3c79fe3a1bc0628](https://github.com/auth0/node-jsonwebtoken/commit/35d84152a6b716d757cb5b1dd3c79fe3a1bc0628)) + +## 7.2.1 - 2016-12-07 + + - add nsp check to find vulnerabilities on npm test ([4219c34b5346811c07f520f10516cc495bcc70dd](https://github.com/auth0/node-jsonwebtoken/commit/4219c34b5346811c07f520f10516cc495bcc70dd)) + - revert to joi@^6 to keep ES5 compatibility ([51d4796c07344bf817687f7ccfeef78f00bf5b4f](https://github.com/auth0/node-jsonwebtoken/commit/51d4796c07344bf817687f7ccfeef78f00bf5b4f)) + +## 7.2.0 - 2016-12-06 + + - improve the documentation for expiration ([771e0b5f9bed90771fb79140eb38e51a3ecac8f0](https://github.com/auth0/node-jsonwebtoken/commit/771e0b5f9bed90771fb79140eb38e51a3ecac8f0)) + - Restructured a sentence ([ccc7610187a862f7a50177eadc9152eef26cd065](https://github.com/auth0/node-jsonwebtoken/commit/ccc7610187a862f7a50177eadc9152eef26cd065)) + - Allow `keyid` on `sign`. ([b412be91b89acb3a742bb609d3b54e47e1dfc441](https://github.com/auth0/node-jsonwebtoken/commit/b412be91b89acb3a742bb609d3b54e47e1dfc441)) + - upgrade joi ([715e3d928023d414d45c6dc3f096a7c8448139ae](https://github.com/auth0/node-jsonwebtoken/commit/715e3d928023d414d45c6dc3f096a7c8448139ae)) + - upgrade to latest nodes and Travis infrastructure ([3febcc1dd23ecdec1abbf89313959941d15eb47a](https://github.com/auth0/node-jsonwebtoken/commit/3febcc1dd23ecdec1abbf89313959941d15eb47a)) + + +## 7.1.10 - 2016-12-06 + + - Bump node-jws version number ([07813dd7194630c9f452684279178af76464a759](https://github.com/auth0/node-jsonwebtoken/commit/07813dd7194630c9f452684279178af76464a759)) + - improve the documentation for expiration ([771e0b5f9bed90771fb79140eb38e51a3ecac8f0](https://github.com/auth0/node-jsonwebtoken/commit/771e0b5f9bed90771fb79140eb38e51a3ecac8f0)) + +## 7.1.9 - 2016-08-11 + + - Revert "Merge branch 'venatir-master'" ([d06359ef3b4e619680e043ee7c16adda16598f52](https://github.com/auth0/node-jsonwebtoken/commit/d06359ef3b4e619680e043ee7c16adda16598f52)) + + + +## 7.1.8 - 2016-08-10 + + - Fixed tests, however typ: 'JWT' should not be in the options at all, so please review other tests ([01903bcdc61b4ed429acbbd1fe0ffe0db364473b](https://github.com/auth0/node-jsonwebtoken/commit/01903bcdc61b4ed429acbbd1fe0ffe0db364473b)) + - Removing unnecessary extra decoding. jwtString is already verified as valid and signature checked ([55d5834f7b637011e1d8b927ff78a92a5fd521cf](https://github.com/auth0/node-jsonwebtoken/commit/55d5834f7b637011e1d8b927ff78a92a5fd521cf)) + - update changelog ([5117aacd0118a10331889a64e61d8186112d8a23](https://github.com/auth0/node-jsonwebtoken/commit/5117aacd0118a10331889a64e61d8186112d8a23)) + + +## 7.1.7 - 2016-07-29 + + - Use lodash.once instead of unlicensed/unmaintained cb ([3ac95ad93ef3068a64e03d8d14deff231b1ed529](https://github.com/auth0/node-jsonwebtoken/commit/3ac95ad93ef3068a64e03d8d14deff231b1ed529)) + +## 7.1.6 - 2016-07-15 + + - fix issue with buffer payload. closes #216 ([6b50ff324b4dfd2cb0e49b666f14a6672d015b22](https://github.com/auth0/node-jsonwebtoken/commit/6b50ff324b4dfd2cb0e49b666f14a6672d015b22)), closes [#216](https://github.com/auth0/node-jsonwebtoken/issues/216) + + +## 7.1.5 - 2016-07-15 + + - update jws in package.json ([b6260951eefc68aae5f4ede359210761f901ff7a](https://github.com/auth0/node-jsonwebtoken/commit/b6260951eefc68aae5f4ede359210761f901ff7a)) + + +## 7.1.4 - 2016-07-14 + + - add redundant test ([bece8816096f324511c3efcb8db0e64b75d757a1](https://github.com/auth0/node-jsonwebtoken/commit/bece8816096f324511c3efcb8db0e64b75d757a1)) + - fix an issue of double callback on error ([758ca5eeca2f1b06c32c9fce70642bf488b2e52b](https://github.com/auth0/node-jsonwebtoken/commit/758ca5eeca2f1b06c32c9fce70642bf488b2e52b)) + +## 7.1.2 - 2016-07-12 + + - do not stringify the payload when signing async - closes #224 ([084f537d3dfbcef2bea411cc0a1515899cc8aa21](https://github.com/auth0/node-jsonwebtoken/commit/084f537d3dfbcef2bea411cc0a1515899cc8aa21)), closes [#224](https://github.com/auth0/node-jsonwebtoken/issues/224) + +## 7.1.1 - 2016-07-12 + + - do not mutate options in jwt.verify, closes #227 ([63263a28a268624dab0927b9ad86fffa44a10f84](https://github.com/auth0/node-jsonwebtoken/commit/63263a28a268624dab0927b9ad86fffa44a10f84)), closes [#227](https://github.com/auth0/node-jsonwebtoken/issues/227) + - refactor into multiple files ([e11d505207fa33501298300c9accbfb809d8748d](https://github.com/auth0/node-jsonwebtoken/commit/e11d505207fa33501298300c9accbfb809d8748d)) + +## 7.1.0 - 2016-07-12 + + - Exp calculated based on iat. fix #217 ([757a16e0e35ad19f9e456820f55d5d9f3fc76aee](https://github.com/auth0/node-jsonwebtoken/commit/757a16e0e35ad19f9e456820f55d5d9f3fc76aee)), closes [#217](https://github.com/auth0/node-jsonwebtoken/issues/217) + +## 7.0.0 - 2016-05-19 + + - change jwt.sign to return errors on callback instead of throwing errors ([1e46c5a42aa3dab8478efa4081d8f8f5c5485d56](https://github.com/auth0/node-jsonwebtoken/commit/1e46c5a42aa3dab8478efa4081d8f8f5c5485d56)) + +## 6.2.0 - 2016-04-29 + + - add support for `options.clockTolerance` to `jwt.verify` ([65ddea934f226bf06bc9d6a55be9587515cfc38d](https://github.com/auth0/node-jsonwebtoken/commit/65ddea934f226bf06bc9d6a55be9587515cfc38d)) + +## 6.1.2 - 2016-04-29 + + - fix sign method for node.js 0.12. closes #193 ([9c38374142d3929be3c9314b5e9bc5d963c5955f](https://github.com/auth0/node-jsonwebtoken/commit/9c38374142d3929be3c9314b5e9bc5d963c5955f)), closes [#193](https://github.com/auth0/node-jsonwebtoken/issues/193) + - improve async test ([7b0981380ddc40a5f1208df520631785b5ffb85a](https://github.com/auth0/node-jsonwebtoken/commit/7b0981380ddc40a5f1208df520631785b5ffb85a)) + +## 6.1.0 - 2016-04-27 + + - verify unsigned tokens ([ec880791c10ed5ef7c8df7bf28ebb95c810479ed](https://github.com/auth0/node-jsonwebtoken/commit/ec880791c10ed5ef7c8df7bf28ebb95c810479ed)) + +## 6.0.1 - 2016-04-27 + +This was an immediate change after publishing 6.0.0. + + - throw error on invalid options when the payload is not an object ([304f1b33075f79ed66f784e27dc4f5307aa39e27](https://github.com/auth0/node-jsonwebtoken/commit/304f1b33075f79ed66f784e27dc4f5307aa39e27)) + +## 6.0.0 - 2016-04-27 + + - Change .sign to standard async callback ([50873c7d45d2733244d5da8afef3d1872e657a60](https://github.com/auth0/node-jsonwebtoken/commit/50873c7d45d2733244d5da8afef3d1872e657a60)) + - Improved the options for the `sign` method ([53c3987b3cc34e95eb396b26fc9b051276e2f6f9](https://github.com/auth0/node-jsonwebtoken/commit/53c3987b3cc34e95eb396b26fc9b051276e2f6f9)) + + - throw error on invalid options like `expiresIn` when the payload is not an object ([304f1b33075f79ed66f784e27dc4f5307aa39e27](https://github.com/auth0/node-jsonwebtoken/commit/304f1b33075f79ed66f784e27dc4f5307aa39e27)) + - `expiresInMinutes` and `expiresInSeconds` are deprecated and no longer supported. + - `notBeforeInMinutes` and `notBeforeInSeconds` are deprecated and no longer supported. + - `options` are strongly validated. + - `options.expiresIn`, `options.notBefore`, `options.audience`, `options.issuer`, `options.subject` and `options.jwtid` are mutually exclusive with `payload.exp`, `payload.nbf`, `payload.aud`, `payload.iss` + - `options.algorithm` is properly validated. + - `options.headers` is renamed to `options.header`. + + - update CHANGELOG to reflect most of the changes. closes #136 ([b87a1a8d2e2533fbfab518765a54f00077918eb7](https://github.com/auth0/node-jsonwebtoken/commit/b87a1a8d2e2533fbfab518765a54f00077918eb7)), closes [#136](https://github.com/auth0/node-jsonwebtoken/issues/136) + - update readme ([53a88ecf4494e30e1d62a1cf3cc354650349f486](https://github.com/auth0/node-jsonwebtoken/commit/53a88ecf4494e30e1d62a1cf3cc354650349f486)) + +## 5.7.0 - 2016-02-16 + + + - add support for validating multiples issuers. closes #163 ([39d9309ae05648dbd72e5fd1993df064ad0e8fa5](https://github.com/auth0/node-jsonwebtoken/commit/39d9309ae05648dbd72e5fd1993df064ad0e8fa5)), closes [#163](https://github.com/auth0/node-jsonwebtoken/issues/163) + + +## 5.6.1 - 2016-02-16 + + + - 5.6.1 ([06d8209d499dbc9a8dd978ab6cbb9c6818fde203](https://github.com/auth0/node-jsonwebtoken/commit/06d8209d499dbc9a8dd978ab6cbb9c6818fde203)) + - fix wrong error when setting expiration on non-object payload. closes #153 ([7f7d76edfd918d6afc7c7cead888caa42ccaceb4](https://github.com/auth0/node-jsonwebtoken/commit/7f7d76edfd918d6afc7c7cead888caa42ccaceb4)), closes [#153](https://github.com/auth0/node-jsonwebtoken/issues/153) + + + +## 5.6.0 - 2016-02-16 + + + - added missing validations of sub and jti ([a1affe960d0fc52e9042bcbdedb65734f8855580](https://github.com/auth0/node-jsonwebtoken/commit/a1affe960d0fc52e9042bcbdedb65734f8855580)) + - Fix tests in jwt.rs.tests.js which causes 4 to fail ([8aedf2b1f575b0d9575c1fc9f2ac7bc868f75ff1](https://github.com/auth0/node-jsonwebtoken/commit/8aedf2b1f575b0d9575c1fc9f2ac7bc868f75ff1)) + - Update README.md ([349b7cd00229789b138928ca060d3ef015aedaf9](https://github.com/auth0/node-jsonwebtoken/commit/349b7cd00229789b138928ca060d3ef015aedaf9)) + + + +## 5.5.4 - 2016-01-04 + + + - minor ([46552e7c45025c76e3f647680d7539a66bfac612](https://github.com/auth0/node-jsonwebtoken/commit/46552e7c45025c76e3f647680d7539a66bfac612)) + + + +## 5.5.3 - 2016-01-04 + + + - add a console.warn on invalid options for string payloads ([71200f14deba0533d3261266348338fac2d14661](https://github.com/auth0/node-jsonwebtoken/commit/71200f14deba0533d3261266348338fac2d14661)) + - minor ([65b1f580382dc58dd3da6f47a52713776fd7cdf2](https://github.com/auth0/node-jsonwebtoken/commit/65b1f580382dc58dd3da6f47a52713776fd7cdf2)) + + + +## 5.5.2 - 2016-01-04 + + + - fix signing method with sealed objects, do not modify the params object. closes #147 ([be9c09af83b09c9e72da8b2c6166fa51d92aeab6](https://github.com/auth0/node-jsonwebtoken/commit/be9c09af83b09c9e72da8b2c6166fa51d92aeab6)), closes [#147](https://github.com/auth0/node-jsonwebtoken/issues/147) + + + +## 5.5.1 - 2016-01-04 + + + - fix nbf verification. fix #152 ([786d37b299c67771b5e71a2ca476666ab0f97d98](https://github.com/auth0/node-jsonwebtoken/commit/786d37b299c67771b5e71a2ca476666ab0f97d98)), closes [#152](https://github.com/auth0/node-jsonwebtoken/issues/152) + + + +## 5.5.0 - 2015-12-28 + + + - improvements to nbf and jti claims ([46372e928f6d2e7398f9b88022ca617d2a3b0699](https://github.com/auth0/node-jsonwebtoken/commit/46372e928f6d2e7398f9b88022ca617d2a3b0699)) + - Remove duplicate payload line (fix bug in IE strict mode) ([8163d698e0c5ad8c44817a5dcd42a15d7e9c6bc8](https://github.com/auth0/node-jsonwebtoken/commit/8163d698e0c5ad8c44817a5dcd42a15d7e9c6bc8)) + - Remove duplicate require('ms') line ([7c00bcbcbf8f7503a1070b394a165eccd41de66f](https://github.com/auth0/node-jsonwebtoken/commit/7c00bcbcbf8f7503a1070b394a165eccd41de66f)) + - Update README to reflect addition of async sign ([d661d4b6f68eb417834c99b36769444723041ccf](https://github.com/auth0/node-jsonwebtoken/commit/d661d4b6f68eb417834c99b36769444723041ccf)) + + + +## 5.4.0 - 2015-10-02 + + + - deprecate expireInMinutes and expireInSeconds - in favor of expiresIn ([39ecc6f8f310f8462e082f1d53de0b4222b29b6f](https://github.com/auth0/node-jsonwebtoken/commit/39ecc6f8f310f8462e082f1d53de0b4222b29b6f)) + + +## 5.3.0 - 2015-10-02 + + + - 5.3.0 ([5d559ced3fbf10c1adae2e5792deda06ea89bcd3](https://github.com/auth0/node-jsonwebtoken/commit/5d559ced3fbf10c1adae2e5792deda06ea89bcd3)) + - minor ([6e81ff87a3799b0e56db09cbae42a97e784716c4](https://github.com/auth0/node-jsonwebtoken/commit/6e81ff87a3799b0e56db09cbae42a97e784716c4)) + + + +## 5.1.0 - 2015-10-02 + + + - added async signing ([9414fbcb15a1f9cf4fe147d070e9424c547dabba](https://github.com/auth0/node-jsonwebtoken/commit/9414fbcb15a1f9cf4fe147d070e9424c547dabba)) + - Update README.md ([40b2aaaa843442dfb8ee7b574f0a788177e7c904](https://github.com/auth0/node-jsonwebtoken/commit/40b2aaaa843442dfb8ee7b574f0a788177e7c904)) + + + +## 5.0.5 - 2015-08-19 + + + - add ms dep to package.json ([f13b3fb7f29dff787e7c91ebe2eb5adeeb05f251](https://github.com/auth0/node-jsonwebtoken/commit/f13b3fb7f29dff787e7c91ebe2eb5adeeb05f251)) + - add note to explain, related to #96 #101 #6 ([dd8969e0e6ed0bcb9cae905d2b1a96476bd85da3](https://github.com/auth0/node-jsonwebtoken/commit/dd8969e0e6ed0bcb9cae905d2b1a96476bd85da3)) + - add tests for options.headers ([7787dd74e705787c39a871ca29c75a2e0a3948ac](https://github.com/auth0/node-jsonwebtoken/commit/7787dd74e705787c39a871ca29c75a2e0a3948ac)) + - add tests for verify expires ([d7c5793d98c300603440ab460c11665f661ad3a0](https://github.com/auth0/node-jsonwebtoken/commit/d7c5793d98c300603440ab460c11665f661ad3a0)) + - add verify option maxAge (with tests) ([49d54e54f7e70b1c53a2e4ee67e116c907d75319](https://github.com/auth0/node-jsonwebtoken/commit/49d54e54f7e70b1c53a2e4ee67e116c907d75319)) + - fix spelling error in error message ([8078b11b224fa05ac9003ca5aa2c85e9f0128cfb](https://github.com/auth0/node-jsonwebtoken/commit/8078b11b224fa05ac9003ca5aa2c85e9f0128cfb)) + - Fix typo options.header is not a documented option + ([5feaa5b962ccbddeff054817a410f7b0c1e6ce7f](https://github.com/auth0/node-jsonwebtoken/commit/5feaa5b962ccbddeff054817a410f7b0c1e6ce7f)) + - update JWT spec link. closes #112 ([f5fa50f797456a12240589161835c7ea30807195](https://github.com/auth0/node-jsonwebtoken/commit/f5fa50f797456a12240589161835c7ea30807195)), closes [#112](https://github.com/auth0/node-jsonwebtoken/issues/112) + + +## 5.0.3 - 2015-07-15 + + - Added nbf support ([f26ba4e2fa197a20497632b63ffcd13ae93aacc4](https://github.com/auth0/node-jsonwebtoken/commit/f26ba4e2fa197a20497632b63ffcd13ae93aacc4)) + - Added support for subject and jwt id ([ab76ec5bc554e2d1e25376ddb7cea711d86af651](https://github.com/auth0/node-jsonwebtoken/commit/ab76ec5bc554e2d1e25376ddb7cea711d86af651)) + - Fix `this` referring to the global object instead of `module.exports` in `verify()` ([93f554312e37129027fcf4916f48cb8d1b53588c](https://github.com/auth0/node-jsonwebtoken/commit/93f554312e37129027fcf4916f48cb8d1b53588c)) + - Fix typo, line 139 README, complete option for .decode. ([59c110aeb8c7c1847ef2ffd77702d13627c89e10](https://github.com/auth0/node-jsonwebtoken/commit/59c110aeb8c7c1847ef2ffd77702d13627c89e10)) + - minor ([61ff1172272b582902313e958058ff22413494af](https://github.com/auth0/node-jsonwebtoken/commit/61ff1172272b582902313e958058ff22413494af)) + + + +## 5.0.2 - 2015-06-15 + + + - fix typo in docs . closes #86 ([3d3413221f36acef4dfd1cbed87f1f3565cd6f84](https://github.com/auth0/node-jsonwebtoken/commit/3d3413221f36acef4dfd1cbed87f1f3565cd6f84)), closes [#86](https://github.com/auth0/node-jsonwebtoken/issues/86) + + + +## 5.0.1 - 2015-05-15 + + + - Add option to return header and payload when decoding. ([7254e011b59f892d1947e6c11819281adac7069d](https://github.com/auth0/node-jsonwebtoken/commit/7254e011b59f892d1947e6c11819281adac7069d)) + - Avoid uncaught "SyntaxError: Unexpected token ͧ" error. ([0dc59cd6ee15d83a606acffa7909ee76176ae186](https://github.com/auth0/node-jsonwebtoken/commit/0dc59cd6ee15d83a606acffa7909ee76176ae186)) + - Document complete option in README. ([ec32b20241a74d9681ea26e1a7024b4642468c00](https://github.com/auth0/node-jsonwebtoken/commit/ec32b20241a74d9681ea26e1a7024b4642468c00)) + - Fix example in README, silence verbose logging. ([ba3174d10033c41e9c211a38f1cc67f74fbd7f69](https://github.com/auth0/node-jsonwebtoken/commit/ba3174d10033c41e9c211a38f1cc67f74fbd7f69)) + - Fix link to auth0.com in README ([1b3c5ff72c9bc25e9271646e679f3080f2a042a0](https://github.com/auth0/node-jsonwebtoken/commit/1b3c5ff72c9bc25e9271646e679f3080f2a042a0)) + - Immediate return if not decoded. ([851bda2b10168f3269c3da6e74d310742f31a193](https://github.com/auth0/node-jsonwebtoken/commit/851bda2b10168f3269c3da6e74d310742f31a193)) + - Prevent throw on undefined/null secret ([0fdf78d4dbf609455f3277d6169a987aef0384d4](https://github.com/auth0/node-jsonwebtoken/commit/0fdf78d4dbf609455f3277d6169a987aef0384d4)) + - Removed path from test ([d6240e24186732d368bffe21143becf44c38f0d6](https://github.com/auth0/node-jsonwebtoken/commit/d6240e24186732d368bffe21143becf44c38f0d6)) + - Simplified checking for missing key ([f1cffd033bffc44f20558eda4a797c3fa2f4ee05](https://github.com/auth0/node-jsonwebtoken/commit/f1cffd033bffc44f20558eda4a797c3fa2f4ee05)) + - Typo ([ffe68dbe0219bab535c1018448eb4c0b22f1f902](https://github.com/auth0/node-jsonwebtoken/commit/ffe68dbe0219bab535c1018448eb4c0b22f1f902)) + - Update CHANGELOG.md ([927cce0dad1bc9aad75aeef53e276cf4cfc0d776](https://github.com/auth0/node-jsonwebtoken/commit/927cce0dad1bc9aad75aeef53e276cf4cfc0d776)) + - Update CHANGELOG.md ([6879e0fdde222995c70a3a69a4af94993d9c667e](https://github.com/auth0/node-jsonwebtoken/commit/6879e0fdde222995c70a3a69a4af94993d9c667e)) + - Update CHANGELOG.md ([c5596c10e8705727fa13e0394184a606083078bc](https://github.com/auth0/node-jsonwebtoken/commit/c5596c10e8705727fa13e0394184a606083078bc)) + - Update CHANGELOG.md ([07541f0315f26d179e1cde92732b6124d6869b6f](https://github.com/auth0/node-jsonwebtoken/commit/07541f0315f26d179e1cde92732b6124d6869b6f)) + - Update CHANGELOG.md ([e6465d48ddd1dc2c3297229b28c78fd5490a2ba9](https://github.com/auth0/node-jsonwebtoken/commit/e6465d48ddd1dc2c3297229b28c78fd5490a2ba9)) + +## [5.0.0] - 2015-04-11 + +### Changed + + - [sign] Only set defautl `iat` if the user does not specify that argument. + + https://github.com/auth0/node-jsonwebtoken/commit/e900282a8d2dff1d4dec815f7e6aa7782e867d91 + https://github.com/auth0/node-jsonwebtoken/commit/35036b188b4ee6b42df553bbb93bc8a6b19eae9d + https://github.com/auth0/node-jsonwebtoken/commit/954bd7a312934f03036b6bb6f00edd41f29e54d9 + https://github.com/auth0/node-jsonwebtoken/commit/24a370080e0b75f11d4717cd2b11b2949d95fc2e + https://github.com/auth0/node-jsonwebtoken/commit/a77df6d49d4ec688dfd0a1cc723586bffe753516 + +### Security + + - [verify] Update to jws@^3.0.0 and renaming `header.alg` mismatch exception to `invalid algorithm` and adding more mismatch tests. + + As `jws@3.0.0` changed the verify method signature to be `jws.verify(signature, algorithm, secretOrKey)`, the token header must be decoded first in order to make sure that the `alg` field matches one of the allowed `options.algorithms`. After that, the now validated `header.alg` is passed to `jws.verify` + + As the order of steps has changed, the error that was thrown when the JWT was invalid is no longer the `jws` one: + ``` + { [Error: Invalid token: no header in signature 'a.b.c'] code: 'MISSING_HEADER', signature: 'a.b.c' } + ``` + + That old error (removed from jws) has been replaced by a `JsonWebTokenError` with message `invalid token`. + + > Important: versions >= 4.2.2 this library are safe to use but we decided to deprecate everything `< 5.0.0` to prevent security warnings from library `node-jws` when doing `npm install`. + + https://github.com/auth0/node-jsonwebtoken/commit/634b8ed0ff5267dc25da5c808634208af109824e + https://github.com/auth0/node-jsonwebtoken/commit/9f24ffd5791febb449d4d03ff58d7807da9b9b7e + https://github.com/auth0/node-jsonwebtoken/commit/19e6cc6a1f2fd90356f89b074223b9665f2aa8a2 + https://github.com/auth0/node-jsonwebtoken/commit/1e4623420159c6410616f02a44ed240f176287a9 + https://github.com/auth0/node-jsonwebtoken/commit/954bd7a312934f03036b6bb6f00edd41f29e54d9 + https://github.com/auth0/node-jsonwebtoken/commit/24a370080e0b75f11d4717cd2b11b2949d95fc2e + https://github.com/auth0/node-jsonwebtoken/commit/a77df6d49d4ec688dfd0a1cc723586bffe753516 + +## [4.2.2] - 2015-03-26 +### Fixed + + - [asymmetric-keys] Fix verify for RSAPublicKey formated keys (`jfromaniello - awlayton`) + https://github.com/auth0/node-jsonwebtoken/commit/402794663b9521bf602fcc6f2e811e7d3912f9dc + https://github.com/auth0/node-jsonwebtoken/commit/8df6aabbc7e1114c8fb3917931078254eb52c222 + +## [4.2.1] - 2015-03-17 +### Fixed + + - [asymmetric-keys] Fixed issue when public key starts with BEING PUBLIC KEY (https://github.com/auth0/node-jsonwebtoken/issues/70) (`jfromaniello`) + https://github.com/auth0/node-jsonwebtoken/commit/7017e74db9b194448ff488b3e16468ada60c4ee5 + +## [4.2.0] - 2015-03-16 +### Security + + - [asymmetric-keys] Making sure a token signed with an asymmetric key will be verified using a asymmetric key. + When the verification part was expecting a token digitally signed with an asymmetric key (RS/ES family) of algorithms an attacker could send a token signed with a symmetric algorithm (HS* family). + + The issue was caused because the same signature was used to verify both type of tokens (`verify` method parameter: `secretOrPublicKey`). + + This change adds a new parameter to the verify called `algorithms`. This can be used to specify a list of supported algorithms, but the default value depends on the secret used: if the secretOrPublicKey contains the string `BEGIN CERTIFICATE` the default is `[ 'RS256','RS384','RS512','ES256','ES384','ES512' ]` otherwise is `[ 'HS256','HS384','HS512' ]`. (`jfromaniello`) + https://github.com/auth0/node-jsonwebtoken/commit/c2bf7b2cd7e8daf66298c2d168a008690bc4bdd3 + https://github.com/auth0/node-jsonwebtoken/commit/1bb584bc382295eeb7ee8c4452a673a77a68b687 + +## [4.1.0] - 2015-03-10 +### Changed +- Assume the payload is JSON even when there is no `typ` property. [5290db1](https://github.com/auth0/node-jsonwebtoken/commit/5290db1bd74f74cd38c90b19e2355ef223a4d931) + +## [4.0.0] - 2015-03-06 +### Changed +- The default encoding is now utf8 instead of binary. [92d33bd](https://github.com/auth0/node-jsonwebtoken/commit/92d33bd99a3416e9e5a8897d9ad8ff7d70a00bfd) +- Add `encoding` as a new option to `sign`. [1fc385e](https://github.com/auth0/node-jsonwebtoken/commit/1fc385ee10bd0018cd1441552dce6c2e5a16375f) +- Add `ignoreExpiration` to `verify`. [8d4da27](https://github.com/auth0/node-jsonwebtoken/commit/8d4da279e1b351ac71ace276285c9255186d549f) +- Add `expiresInSeconds` to `sign`. [dd156cc](https://github.com/auth0/node-jsonwebtoken/commit/dd156cc30f17028744e60aec0502897e34609329) + +### Fixed +- Fix wrong error message when the audience doesn't match. [44e3c8d](https://github.com/auth0/node-jsonwebtoken/commit/44e3c8d757e6b4e2a57a69a035f26b4abec3e327) +- Fix wrong error message when the issuer doesn't match. [44e3c8d](https://github.com/auth0/node-jsonwebtoken/commit/44e3c8d757e6b4e2a57a69a035f26b4abec3e327) +- Fix wrong `iat` and `exp` values when signing with `noTimestamp`. [331b7bc](https://github.com/auth0/node-jsonwebtoken/commit/331b7bc9cc335561f8806f2c4558e105cb53e0a6) diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/LICENSE b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/LICENSE new file mode 100644 index 0000000..bcd1854 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Auth0, Inc. (http://auth0.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/README.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/README.md new file mode 100644 index 0000000..f966435 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/README.md @@ -0,0 +1,375 @@ +# jsonwebtoken + +| **Build** | **Dependency** | +|-----------|---------------| +| [![Build Status](https://secure.travis-ci.org/auth0/node-jsonwebtoken.svg?branch=master)](http://travis-ci.org/auth0/node-jsonwebtoken) | [![Dependency Status](https://david-dm.org/auth0/node-jsonwebtoken.svg)](https://david-dm.org/auth0/node-jsonwebtoken) | + + +An implementation of [JSON Web Tokens](https://tools.ietf.org/html/rfc7519). + +This was developed against `draft-ietf-oauth-json-web-token-08`. It makes use of [node-jws](https://github.com/brianloveswords/node-jws) + +# Install + +```bash +$ npm install jsonwebtoken +``` + +# Migration notes + +* [From v7 to v8](https://github.com/auth0/node-jsonwebtoken/wiki/Migration-Notes:-v7-to-v8) + +# Usage + +### jwt.sign(payload, secretOrPrivateKey, [options, callback]) + +(Asynchronous) If a callback is supplied, the callback is called with the `err` or the JWT. + +(Synchronous) Returns the JsonWebToken as string + +`payload` could be an object literal, buffer or string representing valid JSON. +> **Please _note_ that** `exp` or any other claim is only set if the payload is an object literal. Buffer or string payloads are not checked for JSON validity. + +> If `payload` is not a buffer or a string, it will be coerced into a string using `JSON.stringify`. + +`secretOrPrivateKey` is a string, buffer, or object containing either the secret for HMAC algorithms or the PEM +encoded private key for RSA and ECDSA. In case of a private key with passphrase an object `{ key, passphrase }` can be used (based on [crypto documentation](https://nodejs.org/api/crypto.html#crypto_sign_sign_private_key_output_format)), in this case be sure you pass the `algorithm` option. + +`options`: + +* `algorithm` (default: `HS256`) +* `expiresIn`: expressed in seconds or a string describing a time span [zeit/ms](https://github.com/zeit/ms). + > Eg: `60`, `"2 days"`, `"10h"`, `"7d"`. A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), otherwise milliseconds unit is used by default (`"120"` is equal to `"120ms"`). +* `notBefore`: expressed in seconds or a string describing a time span [zeit/ms](https://github.com/zeit/ms). + > Eg: `60`, `"2 days"`, `"10h"`, `"7d"`. A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), otherwise milliseconds unit is used by default (`"120"` is equal to `"120ms"`). +* `audience` +* `issuer` +* `jwtid` +* `subject` +* `noTimestamp` +* `header` +* `keyid` +* `mutatePayload`: if true, the sign function will modify the payload object directly. This is useful if you need a raw reference to the payload after claims have been applied to it but before it has been encoded into a token. + + + +> There are no default values for `expiresIn`, `notBefore`, `audience`, `subject`, `issuer`. These claims can also be provided in the payload directly with `exp`, `nbf`, `aud`, `sub` and `iss` respectively, but you **_can't_** include in both places. + +Remember that `exp`, `nbf` and `iat` are **NumericDate**, see related [Token Expiration (exp claim)](#token-expiration-exp-claim) + + +The header can be customized via the `options.header` object. + +Generated jwts will include an `iat` (issued at) claim by default unless `noTimestamp` is specified. If `iat` is inserted in the payload, it will be used instead of the real timestamp for calculating other things like `exp` given a timespan in `options.expiresIn`. + +Synchronous Sign with default (HMAC SHA256) + +```js +var jwt = require('jsonwebtoken'); +var token = jwt.sign({ foo: 'bar' }, 'shhhhh'); +``` + +Synchronous Sign with RSA SHA256 +```js +// sign with RSA SHA256 +var privateKey = fs.readFileSync('private.key'); +var token = jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256'}); +``` + +Sign asynchronously +```js +jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256' }, function(err, token) { + console.log(token); +}); +``` + +Backdate a jwt 30 seconds +```js +var older_token = jwt.sign({ foo: 'bar', iat: Math.floor(Date.now() / 1000) - 30 }, 'shhhhh'); +``` + +#### Token Expiration (exp claim) + +The standard for JWT defines an `exp` claim for expiration. The expiration is represented as a **NumericDate**: + +> A JSON numeric value representing the number of seconds from 1970-01-01T00:00:00Z UTC until the specified UTC date/time, ignoring leap seconds. This is equivalent to the IEEE Std 1003.1, 2013 Edition [POSIX.1] definition "Seconds Since the Epoch", in which each day is accounted for by exactly 86400 seconds, other than that non-integer values can be represented. See RFC 3339 [RFC3339] for details regarding date/times in general and UTC in particular. + +This means that the `exp` field should contain the number of seconds since the epoch. + +Signing a token with 1 hour of expiration: + +```javascript +jwt.sign({ + exp: Math.floor(Date.now() / 1000) + (60 * 60), + data: 'foobar' +}, 'secret'); +``` + +Another way to generate a token like this with this library is: + +```javascript +jwt.sign({ + data: 'foobar' +}, 'secret', { expiresIn: 60 * 60 }); + +//or even better: + +jwt.sign({ + data: 'foobar' +}, 'secret', { expiresIn: '1h' }); +``` + +### jwt.verify(token, secretOrPublicKey, [options, callback]) + +(Asynchronous) If a callback is supplied, function acts asynchronously. The callback is called with the decoded payload if the signature is valid and optional expiration, audience, or issuer are valid. If not, it will be called with the error. + +(Synchronous) If a callback is not supplied, function acts synchronously. Returns the payload decoded if the signature is valid and optional expiration, audience, or issuer are valid. If not, it will throw the error. + +`token` is the JsonWebToken string + +`secretOrPublicKey` is a string or buffer containing either the secret for HMAC algorithms, or the PEM +encoded public key for RSA and ECDSA. +If `jwt.verify` is called asynchronous, `secretOrPublicKey` can be a function that should fetch the secret or public key. See below for a detailed example + +As mentioned in [this comment](https://github.com/auth0/node-jsonwebtoken/issues/208#issuecomment-231861138), there are other libraries that expect base64 encoded secrets (random bytes encoded using base64), if that is your case you can pass `Buffer.from(secret, 'base64')`, by doing this the secret will be decoded using base64 and the token verification will use the original random bytes. + +`options` + +* `algorithms`: List of strings with the names of the allowed algorithms. For instance, `["HS256", "HS384"]`. +* `audience`: if you want to check audience (`aud`), provide a value here. The audience can be checked against a string, a regular expression or a list of strings and/or regular expressions. + > Eg: `"urn:foo"`, `/urn:f[o]{2}/`, `[/urn:f[o]{2}/, "urn:bar"]` +* `complete`: return an object with the decoded `{ payload, header, signature }` instead of only the usual content of the payload. +* `issuer` (optional): string or array of strings of valid values for the `iss` field. +* `ignoreExpiration`: if `true` do not validate the expiration of the token. +* `ignoreNotBefore`... +* `subject`: if you want to check subject (`sub`), provide a value here +* `clockTolerance`: number of seconds to tolerate when checking the `nbf` and `exp` claims, to deal with small clock differences among different servers +* `maxAge`: the maximum allowed age for tokens to still be valid. It is expressed in seconds or a string describing a time span [zeit/ms](https://github.com/zeit/ms). + > Eg: `1000`, `"2 days"`, `"10h"`, `"7d"`. A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), otherwise milliseconds unit is used by default (`"120"` is equal to `"120ms"`). +* `clockTimestamp`: the time in seconds that should be used as the current time for all necessary comparisons. +* `nonce`: if you want to check `nonce` claim, provide a string value here. It is used on Open ID for the ID Tokens. ([Open ID implementation notes](https://openid.net/specs/openid-connect-core-1_0.html#NonceNotes)) + + +```js +// verify a token symmetric - synchronous +var decoded = jwt.verify(token, 'shhhhh'); +console.log(decoded.foo) // bar + +// verify a token symmetric +jwt.verify(token, 'shhhhh', function(err, decoded) { + console.log(decoded.foo) // bar +}); + +// invalid token - synchronous +try { + var decoded = jwt.verify(token, 'wrong-secret'); +} catch(err) { + // err +} + +// invalid token +jwt.verify(token, 'wrong-secret', function(err, decoded) { + // err + // decoded undefined +}); + +// verify a token asymmetric +var cert = fs.readFileSync('public.pem'); // get public key +jwt.verify(token, cert, function(err, decoded) { + console.log(decoded.foo) // bar +}); + +// verify audience +var cert = fs.readFileSync('public.pem'); // get public key +jwt.verify(token, cert, { audience: 'urn:foo' }, function(err, decoded) { + // if audience mismatch, err == invalid audience +}); + +// verify issuer +var cert = fs.readFileSync('public.pem'); // get public key +jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer' }, function(err, decoded) { + // if issuer mismatch, err == invalid issuer +}); + +// verify jwt id +var cert = fs.readFileSync('public.pem'); // get public key +jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid' }, function(err, decoded) { + // if jwt id mismatch, err == invalid jwt id +}); + +// verify subject +var cert = fs.readFileSync('public.pem'); // get public key +jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid', subject: 'subject' }, function(err, decoded) { + // if subject mismatch, err == invalid subject +}); + +// alg mismatch +var cert = fs.readFileSync('public.pem'); // get public key +jwt.verify(token, cert, { algorithms: ['RS256'] }, function (err, payload) { + // if token alg != RS256, err == invalid signature +}); + +// Verify using getKey callback +// Example uses https://github.com/auth0/node-jwks-rsa as a way to fetch the keys. +var jwksClient = require('jwks-rsa'); +var client = jwksClient({ + jwksUri: 'https://sandrino.auth0.com/.well-known/jwks.json' +}); +function getKey(header, callback){ + client.getSigningKey(header.kid, function(err, key) { + var signingKey = key.publicKey || key.rsaPublicKey; + callback(null, signingKey); + }); +} + +jwt.verify(token, getKey, options, function(err, decoded) { + console.log(decoded.foo) // bar +}); + +``` + +### jwt.decode(token [, options]) + +(Synchronous) Returns the decoded payload without verifying if the signature is valid. + +> __Warning:__ This will __not__ verify whether the signature is valid. You should __not__ use this for untrusted messages. You most likely want to use `jwt.verify` instead. + +`token` is the JsonWebToken string + +`options`: + +* `json`: force JSON.parse on the payload even if the header doesn't contain `"typ":"JWT"`. +* `complete`: return an object with the decoded payload and header. + +Example + +```js +// get the decoded payload ignoring signature, no secretOrPrivateKey needed +var decoded = jwt.decode(token); + +// get the decoded payload and header +var decoded = jwt.decode(token, {complete: true}); +console.log(decoded.header); +console.log(decoded.payload) +``` + +## Errors & Codes +Possible thrown errors during verification. +Error is the first argument of the verification callback. + +### TokenExpiredError + +Thrown error if the token is expired. + +Error object: + +* name: 'TokenExpiredError' +* message: 'jwt expired' +* expiredAt: [ExpDate] + +```js +jwt.verify(token, 'shhhhh', function(err, decoded) { + if (err) { + /* + err = { + name: 'TokenExpiredError', + message: 'jwt expired', + expiredAt: 1408621000 + } + */ + } +}); +``` + +### JsonWebTokenError +Error object: + +* name: 'JsonWebTokenError' +* message: + * 'jwt malformed' + * 'jwt signature is required' + * 'invalid signature' + * 'jwt audience invalid. expected: [OPTIONS AUDIENCE]' + * 'jwt issuer invalid. expected: [OPTIONS ISSUER]' + * 'jwt id invalid. expected: [OPTIONS JWT ID]' + * 'jwt subject invalid. expected: [OPTIONS SUBJECT]' + +```js +jwt.verify(token, 'shhhhh', function(err, decoded) { + if (err) { + /* + err = { + name: 'JsonWebTokenError', + message: 'jwt malformed' + } + */ + } +}); +``` + +### NotBeforeError +Thrown if current time is before the nbf claim. + +Error object: + +* name: 'NotBeforeError' +* message: 'jwt not active' +* date: 2018-10-04T16:10:44.000Z + +```js +jwt.verify(token, 'shhhhh', function(err, decoded) { + if (err) { + /* + err = { + name: 'NotBeforeError', + message: 'jwt not active', + date: 2018-10-04T16:10:44.000Z + } + */ + } +}); +``` + + +## Algorithms supported + +Array of supported algorithms. The following algorithms are currently supported. + +alg Parameter Value | Digital Signature or MAC Algorithm +----------------|---------------------------- +HS256 | HMAC using SHA-256 hash algorithm +HS384 | HMAC using SHA-384 hash algorithm +HS512 | HMAC using SHA-512 hash algorithm +RS256 | RSASSA-PKCS1-v1_5 using SHA-256 hash algorithm +RS384 | RSASSA-PKCS1-v1_5 using SHA-384 hash algorithm +RS512 | RSASSA-PKCS1-v1_5 using SHA-512 hash algorithm +PS256 | RSASSA-PSS using SHA-256 hash algorithm (only node ^6.12.0 OR >=8.0.0) +PS384 | RSASSA-PSS using SHA-384 hash algorithm (only node ^6.12.0 OR >=8.0.0) +PS512 | RSASSA-PSS using SHA-512 hash algorithm (only node ^6.12.0 OR >=8.0.0) +ES256 | ECDSA using P-256 curve and SHA-256 hash algorithm +ES384 | ECDSA using P-384 curve and SHA-384 hash algorithm +ES512 | ECDSA using P-521 curve and SHA-512 hash algorithm +none | No digital signature or MAC value included + +## Refreshing JWTs + +First of all, we recommend you to think carefully if auto-refreshing a JWT will not introduce any vulnerability in your system. + +We are not comfortable including this as part of the library, however, you can take a look at [this example](https://gist.github.com/ziluvatar/a3feb505c4c0ec37059054537b38fc48) to show how this could be accomplished. +Apart from that example there are [an issue](https://github.com/auth0/node-jsonwebtoken/issues/122) and [a pull request](https://github.com/auth0/node-jsonwebtoken/pull/172) to get more knowledge about this topic. + +# TODO + +* X.509 certificate chain is not checked + +## Issue Reporting + +If you have found a bug or if you have a feature request, please report them at this repository issues section. Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues. + +## Author + +[Auth0](https://auth0.com) + +## License + +This project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more info. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/decode.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/decode.js new file mode 100644 index 0000000..8fe1adc --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/decode.js @@ -0,0 +1,30 @@ +var jws = require('jws'); + +module.exports = function (jwt, options) { + options = options || {}; + var decoded = jws.decode(jwt, options); + if (!decoded) { return null; } + var payload = decoded.payload; + + //try parse the payload + if(typeof payload === 'string') { + try { + var obj = JSON.parse(payload); + if(obj !== null && typeof obj === 'object') { + payload = obj; + } + } catch (e) { } + } + + //return header if `complete` option is enabled. header includes claims + //such as `kid` and `alg` used to select the key within a JWKS needed to + //verify the signature + if (options.complete === true) { + return { + header: decoded.header, + payload: payload, + signature: decoded.signature + }; + } + return payload; +}; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/index.js new file mode 100644 index 0000000..161eb2d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/index.js @@ -0,0 +1,8 @@ +module.exports = { + decode: require('./decode'), + verify: require('./verify'), + sign: require('./sign'), + JsonWebTokenError: require('./lib/JsonWebTokenError'), + NotBeforeError: require('./lib/NotBeforeError'), + TokenExpiredError: require('./lib/TokenExpiredError'), +}; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/JsonWebTokenError.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/JsonWebTokenError.js new file mode 100644 index 0000000..e068222 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/JsonWebTokenError.js @@ -0,0 +1,14 @@ +var JsonWebTokenError = function (message, error) { + Error.call(this, message); + if(Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } + this.name = 'JsonWebTokenError'; + this.message = message; + if (error) this.inner = error; +}; + +JsonWebTokenError.prototype = Object.create(Error.prototype); +JsonWebTokenError.prototype.constructor = JsonWebTokenError; + +module.exports = JsonWebTokenError; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/NotBeforeError.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/NotBeforeError.js new file mode 100644 index 0000000..7b30084 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/NotBeforeError.js @@ -0,0 +1,13 @@ +var JsonWebTokenError = require('./JsonWebTokenError'); + +var NotBeforeError = function (message, date) { + JsonWebTokenError.call(this, message); + this.name = 'NotBeforeError'; + this.date = date; +}; + +NotBeforeError.prototype = Object.create(JsonWebTokenError.prototype); + +NotBeforeError.prototype.constructor = NotBeforeError; + +module.exports = NotBeforeError; \ No newline at end of file diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/TokenExpiredError.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/TokenExpiredError.js new file mode 100644 index 0000000..abb704f --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/TokenExpiredError.js @@ -0,0 +1,13 @@ +var JsonWebTokenError = require('./JsonWebTokenError'); + +var TokenExpiredError = function (message, expiredAt) { + JsonWebTokenError.call(this, message); + this.name = 'TokenExpiredError'; + this.expiredAt = expiredAt; +}; + +TokenExpiredError.prototype = Object.create(JsonWebTokenError.prototype); + +TokenExpiredError.prototype.constructor = TokenExpiredError; + +module.exports = TokenExpiredError; \ No newline at end of file diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/psSupported.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/psSupported.js new file mode 100644 index 0000000..8c04144 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/psSupported.js @@ -0,0 +1,3 @@ +var semver = require('semver'); + +module.exports = semver.satisfies(process.version, '^6.12.0 || >=8.0.0'); diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/timespan.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/timespan.js new file mode 100644 index 0000000..e509869 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/lib/timespan.js @@ -0,0 +1,18 @@ +var ms = require('ms'); + +module.exports = function (time, iat) { + var timestamp = iat || Math.floor(Date.now() / 1000); + + if (typeof time === 'string') { + var milliseconds = ms(time); + if (typeof milliseconds === 'undefined') { + return; + } + return Math.floor(timestamp + milliseconds / 1000); + } else if (typeof time === 'number') { + return timestamp + time; + } else { + return; + } + +}; \ No newline at end of file diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/package.json new file mode 100644 index 0000000..8d396e9 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/package.json @@ -0,0 +1,99 @@ +{ + "_from": "jsonwebtoken@8.5.1", + "_id": "jsonwebtoken@8.5.1", + "_inBundle": false, + "_integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "_location": "/jsonwebtoken", + "_phantomChildren": {}, + "_requested": { + "type": "version", + "registry": true, + "raw": "jsonwebtoken@8.5.1", + "name": "jsonwebtoken", + "escapedName": "jsonwebtoken", + "rawSpec": "8.5.1", + "saveSpec": null, + "fetchSpec": "8.5.1" + }, + "_requiredBy": [ + "/" + ], + "_resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "_shasum": "00e71e0b8df54c2121a1f26137df2280673bcc0d", + "_spec": "jsonwebtoken@8.5.1", + "_where": "D:\\xm\\online-code\\hellounicloud\\uni_modules\\uni-id-pages\\uniCloud\\cloudfunctions\\uni-id-co", + "author": { + "name": "auth0" + }, + "bugs": { + "url": "https://github.com/auth0/node-jsonwebtoken/issues" + }, + "bundleDependencies": false, + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "deprecated": false, + "description": "JSON Web Token implementation (symmetric and asymmetric)", + "devDependencies": { + "atob": "^2.1.2", + "chai": "^4.1.2", + "conventional-changelog": "~1.1.0", + "cost-of-modules": "^1.0.1", + "eslint": "^4.19.1", + "mocha": "^5.2.0", + "nsp": "^2.6.2", + "nyc": "^11.9.0", + "sinon": "^6.0.0" + }, + "engines": { + "node": ">=4", + "npm": ">=1.4.28" + }, + "files": [ + "lib", + "decode.js", + "sign.js", + "verify.js" + ], + "homepage": "https://github.com/auth0/node-jsonwebtoken#readme", + "keywords": [ + "jwt" + ], + "license": "MIT", + "main": "index.js", + "name": "jsonwebtoken", + "nyc": { + "check-coverage": true, + "lines": 95, + "statements": 95, + "functions": 100, + "branches": 95, + "exclude": [ + "./test/**" + ], + "reporter": [ + "json", + "lcov", + "text-summary" + ] + }, + "repository": { + "type": "git", + "url": "git+https://github.com/auth0/node-jsonwebtoken.git" + }, + "scripts": { + "coverage": "nyc mocha --use_strict", + "lint": "eslint .", + "test": "npm run lint && npm run coverage && cost-of-modules" + }, + "version": "8.5.1" +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/sign.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/sign.js new file mode 100644 index 0000000..f649ce4 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/sign.js @@ -0,0 +1,206 @@ +var timespan = require('./lib/timespan'); +var PS_SUPPORTED = require('./lib/psSupported'); +var jws = require('jws'); +var includes = require('lodash.includes'); +var isBoolean = require('lodash.isboolean'); +var isInteger = require('lodash.isinteger'); +var isNumber = require('lodash.isnumber'); +var isPlainObject = require('lodash.isplainobject'); +var isString = require('lodash.isstring'); +var once = require('lodash.once'); + +var SUPPORTED_ALGS = ['RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512', 'HS256', 'HS384', 'HS512', 'none'] +if (PS_SUPPORTED) { + SUPPORTED_ALGS.splice(3, 0, 'PS256', 'PS384', 'PS512'); +} + +var sign_options_schema = { + expiresIn: { isValid: function(value) { return isInteger(value) || (isString(value) && value); }, message: '"expiresIn" should be a number of seconds or string representing a timespan' }, + notBefore: { isValid: function(value) { return isInteger(value) || (isString(value) && value); }, message: '"notBefore" should be a number of seconds or string representing a timespan' }, + audience: { isValid: function(value) { return isString(value) || Array.isArray(value); }, message: '"audience" must be a string or array' }, + algorithm: { isValid: includes.bind(null, SUPPORTED_ALGS), message: '"algorithm" must be a valid string enum value' }, + header: { isValid: isPlainObject, message: '"header" must be an object' }, + encoding: { isValid: isString, message: '"encoding" must be a string' }, + issuer: { isValid: isString, message: '"issuer" must be a string' }, + subject: { isValid: isString, message: '"subject" must be a string' }, + jwtid: { isValid: isString, message: '"jwtid" must be a string' }, + noTimestamp: { isValid: isBoolean, message: '"noTimestamp" must be a boolean' }, + keyid: { isValid: isString, message: '"keyid" must be a string' }, + mutatePayload: { isValid: isBoolean, message: '"mutatePayload" must be a boolean' } +}; + +var registered_claims_schema = { + iat: { isValid: isNumber, message: '"iat" should be a number of seconds' }, + exp: { isValid: isNumber, message: '"exp" should be a number of seconds' }, + nbf: { isValid: isNumber, message: '"nbf" should be a number of seconds' } +}; + +function validate(schema, allowUnknown, object, parameterName) { + if (!isPlainObject(object)) { + throw new Error('Expected "' + parameterName + '" to be a plain object.'); + } + Object.keys(object) + .forEach(function(key) { + var validator = schema[key]; + if (!validator) { + if (!allowUnknown) { + throw new Error('"' + key + '" is not allowed in "' + parameterName + '"'); + } + return; + } + if (!validator.isValid(object[key])) { + throw new Error(validator.message); + } + }); +} + +function validateOptions(options) { + return validate(sign_options_schema, false, options, 'options'); +} + +function validatePayload(payload) { + return validate(registered_claims_schema, true, payload, 'payload'); +} + +var options_to_payload = { + 'audience': 'aud', + 'issuer': 'iss', + 'subject': 'sub', + 'jwtid': 'jti' +}; + +var options_for_objects = [ + 'expiresIn', + 'notBefore', + 'noTimestamp', + 'audience', + 'issuer', + 'subject', + 'jwtid', +]; + +module.exports = function (payload, secretOrPrivateKey, options, callback) { + if (typeof options === 'function') { + callback = options; + options = {}; + } else { + options = options || {}; + } + + var isObjectPayload = typeof payload === 'object' && + !Buffer.isBuffer(payload); + + var header = Object.assign({ + alg: options.algorithm || 'HS256', + typ: isObjectPayload ? 'JWT' : undefined, + kid: options.keyid + }, options.header); + + function failure(err) { + if (callback) { + return callback(err); + } + throw err; + } + + if (!secretOrPrivateKey && options.algorithm !== 'none') { + return failure(new Error('secretOrPrivateKey must have a value')); + } + + if (typeof payload === 'undefined') { + return failure(new Error('payload is required')); + } else if (isObjectPayload) { + try { + validatePayload(payload); + } + catch (error) { + return failure(error); + } + if (!options.mutatePayload) { + payload = Object.assign({},payload); + } + } else { + var invalid_options = options_for_objects.filter(function (opt) { + return typeof options[opt] !== 'undefined'; + }); + + if (invalid_options.length > 0) { + return failure(new Error('invalid ' + invalid_options.join(',') + ' option for ' + (typeof payload ) + ' payload')); + } + } + + if (typeof payload.exp !== 'undefined' && typeof options.expiresIn !== 'undefined') { + return failure(new Error('Bad "options.expiresIn" option the payload already has an "exp" property.')); + } + + if (typeof payload.nbf !== 'undefined' && typeof options.notBefore !== 'undefined') { + return failure(new Error('Bad "options.notBefore" option the payload already has an "nbf" property.')); + } + + try { + validateOptions(options); + } + catch (error) { + return failure(error); + } + + var timestamp = payload.iat || Math.floor(Date.now() / 1000); + + if (options.noTimestamp) { + delete payload.iat; + } else if (isObjectPayload) { + payload.iat = timestamp; + } + + if (typeof options.notBefore !== 'undefined') { + try { + payload.nbf = timespan(options.notBefore, timestamp); + } + catch (err) { + return failure(err); + } + if (typeof payload.nbf === 'undefined') { + return failure(new Error('"notBefore" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60')); + } + } + + if (typeof options.expiresIn !== 'undefined' && typeof payload === 'object') { + try { + payload.exp = timespan(options.expiresIn, timestamp); + } + catch (err) { + return failure(err); + } + if (typeof payload.exp === 'undefined') { + return failure(new Error('"expiresIn" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60')); + } + } + + Object.keys(options_to_payload).forEach(function (key) { + var claim = options_to_payload[key]; + if (typeof options[key] !== 'undefined') { + if (typeof payload[claim] !== 'undefined') { + return failure(new Error('Bad "options.' + key + '" option. The payload already has an "' + claim + '" property.')); + } + payload[claim] = options[key]; + } + }); + + var encoding = options.encoding || 'utf8'; + + if (typeof callback === 'function') { + callback = callback && once(callback); + + jws.createSign({ + header: header, + privateKey: secretOrPrivateKey, + payload: payload, + encoding: encoding + }).once('error', callback) + .once('done', function (signature) { + callback(null, signature); + }); + } else { + return jws.sign({header: header, payload: payload, secret: secretOrPrivateKey, encoding: encoding}); + } +}; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/verify.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/verify.js new file mode 100644 index 0000000..1df99f8 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jsonwebtoken/verify.js @@ -0,0 +1,225 @@ +var JsonWebTokenError = require('./lib/JsonWebTokenError'); +var NotBeforeError = require('./lib/NotBeforeError'); +var TokenExpiredError = require('./lib/TokenExpiredError'); +var decode = require('./decode'); +var timespan = require('./lib/timespan'); +var PS_SUPPORTED = require('./lib/psSupported'); +var jws = require('jws'); + +var PUB_KEY_ALGS = ['RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512']; +var RSA_KEY_ALGS = ['RS256', 'RS384', 'RS512']; +var HS_ALGS = ['HS256', 'HS384', 'HS512']; + +if (PS_SUPPORTED) { + PUB_KEY_ALGS.splice(3, 0, 'PS256', 'PS384', 'PS512'); + RSA_KEY_ALGS.splice(3, 0, 'PS256', 'PS384', 'PS512'); +} + +module.exports = function (jwtString, secretOrPublicKey, options, callback) { + if ((typeof options === 'function') && !callback) { + callback = options; + options = {}; + } + + if (!options) { + options = {}; + } + + //clone this object since we are going to mutate it. + options = Object.assign({}, options); + + var done; + + if (callback) { + done = callback; + } else { + done = function(err, data) { + if (err) throw err; + return data; + }; + } + + if (options.clockTimestamp && typeof options.clockTimestamp !== 'number') { + return done(new JsonWebTokenError('clockTimestamp must be a number')); + } + + if (options.nonce !== undefined && (typeof options.nonce !== 'string' || options.nonce.trim() === '')) { + return done(new JsonWebTokenError('nonce must be a non-empty string')); + } + + var clockTimestamp = options.clockTimestamp || Math.floor(Date.now() / 1000); + + if (!jwtString){ + return done(new JsonWebTokenError('jwt must be provided')); + } + + if (typeof jwtString !== 'string') { + return done(new JsonWebTokenError('jwt must be a string')); + } + + var parts = jwtString.split('.'); + + if (parts.length !== 3){ + return done(new JsonWebTokenError('jwt malformed')); + } + + var decodedToken; + + try { + decodedToken = decode(jwtString, { complete: true }); + } catch(err) { + return done(err); + } + + if (!decodedToken) { + return done(new JsonWebTokenError('invalid token')); + } + + var header = decodedToken.header; + var getSecret; + + if(typeof secretOrPublicKey === 'function') { + if(!callback) { + return done(new JsonWebTokenError('verify must be called asynchronous if secret or public key is provided as a callback')); + } + + getSecret = secretOrPublicKey; + } + else { + getSecret = function(header, secretCallback) { + return secretCallback(null, secretOrPublicKey); + }; + } + + return getSecret(header, function(err, secretOrPublicKey) { + if(err) { + return done(new JsonWebTokenError('error in secret or public key callback: ' + err.message)); + } + + var hasSignature = parts[2].trim() !== ''; + + if (!hasSignature && secretOrPublicKey){ + return done(new JsonWebTokenError('jwt signature is required')); + } + + if (hasSignature && !secretOrPublicKey) { + return done(new JsonWebTokenError('secret or public key must be provided')); + } + + if (!hasSignature && !options.algorithms) { + options.algorithms = ['none']; + } + + if (!options.algorithms) { + options.algorithms = ~secretOrPublicKey.toString().indexOf('BEGIN CERTIFICATE') || + ~secretOrPublicKey.toString().indexOf('BEGIN PUBLIC KEY') ? PUB_KEY_ALGS : + ~secretOrPublicKey.toString().indexOf('BEGIN RSA PUBLIC KEY') ? RSA_KEY_ALGS : HS_ALGS; + + } + + if (!~options.algorithms.indexOf(decodedToken.header.alg)) { + return done(new JsonWebTokenError('invalid algorithm')); + } + + var valid; + + try { + valid = jws.verify(jwtString, decodedToken.header.alg, secretOrPublicKey); + } catch (e) { + return done(e); + } + + if (!valid) { + return done(new JsonWebTokenError('invalid signature')); + } + + var payload = decodedToken.payload; + + if (typeof payload.nbf !== 'undefined' && !options.ignoreNotBefore) { + if (typeof payload.nbf !== 'number') { + return done(new JsonWebTokenError('invalid nbf value')); + } + if (payload.nbf > clockTimestamp + (options.clockTolerance || 0)) { + return done(new NotBeforeError('jwt not active', new Date(payload.nbf * 1000))); + } + } + + if (typeof payload.exp !== 'undefined' && !options.ignoreExpiration) { + if (typeof payload.exp !== 'number') { + return done(new JsonWebTokenError('invalid exp value')); + } + if (clockTimestamp >= payload.exp + (options.clockTolerance || 0)) { + return done(new TokenExpiredError('jwt expired', new Date(payload.exp * 1000))); + } + } + + if (options.audience) { + var audiences = Array.isArray(options.audience) ? options.audience : [options.audience]; + var target = Array.isArray(payload.aud) ? payload.aud : [payload.aud]; + + var match = target.some(function (targetAudience) { + return audiences.some(function (audience) { + return audience instanceof RegExp ? audience.test(targetAudience) : audience === targetAudience; + }); + }); + + if (!match) { + return done(new JsonWebTokenError('jwt audience invalid. expected: ' + audiences.join(' or '))); + } + } + + if (options.issuer) { + var invalid_issuer = + (typeof options.issuer === 'string' && payload.iss !== options.issuer) || + (Array.isArray(options.issuer) && options.issuer.indexOf(payload.iss) === -1); + + if (invalid_issuer) { + return done(new JsonWebTokenError('jwt issuer invalid. expected: ' + options.issuer)); + } + } + + if (options.subject) { + if (payload.sub !== options.subject) { + return done(new JsonWebTokenError('jwt subject invalid. expected: ' + options.subject)); + } + } + + if (options.jwtid) { + if (payload.jti !== options.jwtid) { + return done(new JsonWebTokenError('jwt jwtid invalid. expected: ' + options.jwtid)); + } + } + + if (options.nonce) { + if (payload.nonce !== options.nonce) { + return done(new JsonWebTokenError('jwt nonce invalid. expected: ' + options.nonce)); + } + } + + if (options.maxAge) { + if (typeof payload.iat !== 'number') { + return done(new JsonWebTokenError('iat required when maxAge is specified')); + } + + var maxAgeTimestamp = timespan(options.maxAge, payload.iat); + if (typeof maxAgeTimestamp === 'undefined') { + return done(new JsonWebTokenError('"maxAge" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60')); + } + if (clockTimestamp >= maxAgeTimestamp + (options.clockTolerance || 0)) { + return done(new TokenExpiredError('maxAge exceeded', new Date(maxAgeTimestamp * 1000))); + } + } + + if (options.complete === true) { + var signature = decodedToken.signature; + + return done(null, { + header: header, + payload: payload, + signature: signature + }); + } + + return done(null, payload); + }); +}; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jwa/LICENSE b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jwa/LICENSE new file mode 100644 index 0000000..caeb849 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jwa/LICENSE @@ -0,0 +1,17 @@ +Copyright (c) 2013 Brian J. Brennan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jwa/README.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jwa/README.md new file mode 100644 index 0000000..fb433e2 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jwa/README.md @@ -0,0 +1,150 @@ +# node-jwa [![Build Status](https://travis-ci.org/brianloveswords/node-jwa.svg?branch=master)](https://travis-ci.org/brianloveswords/node-jwa) + +A +[JSON Web Algorithms](http://tools.ietf.org/id/draft-ietf-jose-json-web-algorithms-08.html) +implementation focusing (exclusively, at this point) on the algorithms necessary for +[JSON Web Signatures](http://self-issued.info/docs/draft-ietf-jose-json-web-signature.html). + +This library supports all of the required, recommended and optional cryptographic algorithms for JWS: + +alg Parameter Value | Digital Signature or MAC Algorithm +----------------|---------------------------- +HS256 | HMAC using SHA-256 hash algorithm +HS384 | HMAC using SHA-384 hash algorithm +HS512 | HMAC using SHA-512 hash algorithm +RS256 | RSASSA using SHA-256 hash algorithm +RS384 | RSASSA using SHA-384 hash algorithm +RS512 | RSASSA using SHA-512 hash algorithm +PS256 | RSASSA-PSS using SHA-256 hash algorithm +PS384 | RSASSA-PSS using SHA-384 hash algorithm +PS512 | RSASSA-PSS using SHA-512 hash algorithm +ES256 | ECDSA using P-256 curve and SHA-256 hash algorithm +ES384 | ECDSA using P-384 curve and SHA-384 hash algorithm +ES512 | ECDSA using P-521 curve and SHA-512 hash algorithm +none | No digital signature or MAC value included + +Please note that PS* only works on Node 6.12+ (excluding 7.x). + +# Requirements + +In order to run the tests, a recent version of OpenSSL is +required. **The version that comes with OS X (OpenSSL 0.9.8r 8 Feb +2011) is not recent enough**, as it does not fully support ECDSA +keys. You'll need to use a version > 1.0.0; I tested with OpenSSL 1.0.1c 10 May 2012. + +# Testing + +To run the tests, do + +```bash +$ npm test +``` + +This will generate a bunch of keypairs to use in testing. If you want to +generate new keypairs, do `make clean` before running `npm test` again. + +## Methodology + +I spawn `openssl dgst -sign` to test OpenSSL sign → JS verify and +`openssl dgst -verify` to test JS sign → OpenSSL verify for each of the +RSA and ECDSA algorithms. + +# Usage + +## jwa(algorithm) + +Creates a new `jwa` object with `sign` and `verify` methods for the +algorithm. Valid values for algorithm can be found in the table above +(`'HS256'`, `'HS384'`, etc) and are case-insensitive. Passing an invalid +algorithm value will throw a `TypeError`. + + +## jwa#sign(input, secretOrPrivateKey) + +Sign some input with either a secret for HMAC algorithms, or a private +key for RSA and ECDSA algorithms. + +If input is not already a string or buffer, `JSON.stringify` will be +called on it to attempt to coerce it. + +For the HMAC algorithm, `secretOrPrivateKey` should be a string or a +buffer. For ECDSA and RSA, the value should be a string representing a +PEM encoded **private** key. + +Output [base64url](http://en.wikipedia.org/wiki/Base64#URL_applications) +formatted. This is for convenience as JWS expects the signature in this +format. If your application needs the output in a different format, +[please open an issue](https://github.com/brianloveswords/node-jwa/issues). In +the meantime, you can use +[brianloveswords/base64url](https://github.com/brianloveswords/base64url) +to decode the signature. + +As of nodejs *v0.11.8*, SPKAC support was introduce. If your nodeJs +version satisfies, then you can pass an object `{ key: '..', passphrase: '...' }` + + +## jwa#verify(input, signature, secretOrPublicKey) + +Verify a signature. Returns `true` or `false`. + +`signature` should be a base64url encoded string. + +For the HMAC algorithm, `secretOrPublicKey` should be a string or a +buffer. For ECDSA and RSA, the value should be a string represented a +PEM encoded **public** key. + + +# Example + +HMAC +```js +const jwa = require('jwa'); + +const hmac = jwa('HS256'); +const input = 'super important stuff'; +const secret = 'shhhhhh'; + +const signature = hmac.sign(input, secret); +hmac.verify(input, signature, secret) // === true +hmac.verify(input, signature, 'trickery!') // === false +``` + +With keys +```js +const fs = require('fs'); +const jwa = require('jwa'); +const privateKey = fs.readFileSync(__dirname + '/ecdsa-p521-private.pem'); +const publicKey = fs.readFileSync(__dirname + '/ecdsa-p521-public.pem'); + +const ecdsa = jwa('ES512'); +const input = 'very important stuff'; + +const signature = ecdsa.sign(input, privateKey); +ecdsa.verify(input, signature, publicKey) // === true +``` +## License + +MIT + +``` +Copyright (c) 2013 Brian J. Brennan + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +``` diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jwa/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jwa/index.js new file mode 100644 index 0000000..e71e6d1 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jwa/index.js @@ -0,0 +1,252 @@ +var bufferEqual = require('buffer-equal-constant-time'); +var Buffer = require('safe-buffer').Buffer; +var crypto = require('crypto'); +var formatEcdsa = require('ecdsa-sig-formatter'); +var util = require('util'); + +var MSG_INVALID_ALGORITHM = '"%s" is not a valid algorithm.\n Supported algorithms are:\n "HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "PS256", "PS384", "PS512", "ES256", "ES384", "ES512" and "none".' +var MSG_INVALID_SECRET = 'secret must be a string or buffer'; +var MSG_INVALID_VERIFIER_KEY = 'key must be a string or a buffer'; +var MSG_INVALID_SIGNER_KEY = 'key must be a string, a buffer or an object'; + +var supportsKeyObjects = typeof crypto.createPublicKey === 'function'; +if (supportsKeyObjects) { + MSG_INVALID_VERIFIER_KEY += ' or a KeyObject'; + MSG_INVALID_SECRET += 'or a KeyObject'; +} + +function checkIsPublicKey(key) { + if (Buffer.isBuffer(key)) { + return; + } + + if (typeof key === 'string') { + return; + } + + if (!supportsKeyObjects) { + throw typeError(MSG_INVALID_VERIFIER_KEY); + } + + if (typeof key !== 'object') { + throw typeError(MSG_INVALID_VERIFIER_KEY); + } + + if (typeof key.type !== 'string') { + throw typeError(MSG_INVALID_VERIFIER_KEY); + } + + if (typeof key.asymmetricKeyType !== 'string') { + throw typeError(MSG_INVALID_VERIFIER_KEY); + } + + if (typeof key.export !== 'function') { + throw typeError(MSG_INVALID_VERIFIER_KEY); + } +}; + +function checkIsPrivateKey(key) { + if (Buffer.isBuffer(key)) { + return; + } + + if (typeof key === 'string') { + return; + } + + if (typeof key === 'object') { + return; + } + + throw typeError(MSG_INVALID_SIGNER_KEY); +}; + +function checkIsSecretKey(key) { + if (Buffer.isBuffer(key)) { + return; + } + + if (typeof key === 'string') { + return key; + } + + if (!supportsKeyObjects) { + throw typeError(MSG_INVALID_SECRET); + } + + if (typeof key !== 'object') { + throw typeError(MSG_INVALID_SECRET); + } + + if (key.type !== 'secret') { + throw typeError(MSG_INVALID_SECRET); + } + + if (typeof key.export !== 'function') { + throw typeError(MSG_INVALID_SECRET); + } +} + +function fromBase64(base64) { + return base64 + .replace(/=/g, '') + .replace(/\+/g, '-') + .replace(/\//g, '_'); +} + +function toBase64(base64url) { + base64url = base64url.toString(); + + var padding = 4 - base64url.length % 4; + if (padding !== 4) { + for (var i = 0; i < padding; ++i) { + base64url += '='; + } + } + + return base64url + .replace(/\-/g, '+') + .replace(/_/g, '/'); +} + +function typeError(template) { + var args = [].slice.call(arguments, 1); + var errMsg = util.format.bind(util, template).apply(null, args); + return new TypeError(errMsg); +} + +function bufferOrString(obj) { + return Buffer.isBuffer(obj) || typeof obj === 'string'; +} + +function normalizeInput(thing) { + if (!bufferOrString(thing)) + thing = JSON.stringify(thing); + return thing; +} + +function createHmacSigner(bits) { + return function sign(thing, secret) { + checkIsSecretKey(secret); + thing = normalizeInput(thing); + var hmac = crypto.createHmac('sha' + bits, secret); + var sig = (hmac.update(thing), hmac.digest('base64')) + return fromBase64(sig); + } +} + +function createHmacVerifier(bits) { + return function verify(thing, signature, secret) { + var computedSig = createHmacSigner(bits)(thing, secret); + return bufferEqual(Buffer.from(signature), Buffer.from(computedSig)); + } +} + +function createKeySigner(bits) { + return function sign(thing, privateKey) { + checkIsPrivateKey(privateKey); + thing = normalizeInput(thing); + // Even though we are specifying "RSA" here, this works with ECDSA + // keys as well. + var signer = crypto.createSign('RSA-SHA' + bits); + var sig = (signer.update(thing), signer.sign(privateKey, 'base64')); + return fromBase64(sig); + } +} + +function createKeyVerifier(bits) { + return function verify(thing, signature, publicKey) { + checkIsPublicKey(publicKey); + thing = normalizeInput(thing); + signature = toBase64(signature); + var verifier = crypto.createVerify('RSA-SHA' + bits); + verifier.update(thing); + return verifier.verify(publicKey, signature, 'base64'); + } +} + +function createPSSKeySigner(bits) { + return function sign(thing, privateKey) { + checkIsPrivateKey(privateKey); + thing = normalizeInput(thing); + var signer = crypto.createSign('RSA-SHA' + bits); + var sig = (signer.update(thing), signer.sign({ + key: privateKey, + padding: crypto.constants.RSA_PKCS1_PSS_PADDING, + saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST + }, 'base64')); + return fromBase64(sig); + } +} + +function createPSSKeyVerifier(bits) { + return function verify(thing, signature, publicKey) { + checkIsPublicKey(publicKey); + thing = normalizeInput(thing); + signature = toBase64(signature); + var verifier = crypto.createVerify('RSA-SHA' + bits); + verifier.update(thing); + return verifier.verify({ + key: publicKey, + padding: crypto.constants.RSA_PKCS1_PSS_PADDING, + saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST + }, signature, 'base64'); + } +} + +function createECDSASigner(bits) { + var inner = createKeySigner(bits); + return function sign() { + var signature = inner.apply(null, arguments); + signature = formatEcdsa.derToJose(signature, 'ES' + bits); + return signature; + }; +} + +function createECDSAVerifer(bits) { + var inner = createKeyVerifier(bits); + return function verify(thing, signature, publicKey) { + signature = formatEcdsa.joseToDer(signature, 'ES' + bits).toString('base64'); + var result = inner(thing, signature, publicKey); + return result; + }; +} + +function createNoneSigner() { + return function sign() { + return ''; + } +} + +function createNoneVerifier() { + return function verify(thing, signature) { + return signature === ''; + } +} + +module.exports = function jwa(algorithm) { + var signerFactories = { + hs: createHmacSigner, + rs: createKeySigner, + ps: createPSSKeySigner, + es: createECDSASigner, + none: createNoneSigner, + } + var verifierFactories = { + hs: createHmacVerifier, + rs: createKeyVerifier, + ps: createPSSKeyVerifier, + es: createECDSAVerifer, + none: createNoneVerifier, + } + var match = algorithm.match(/^(RS|PS|ES|HS)(256|384|512)$|^(none)$/i); + if (!match) + throw typeError(MSG_INVALID_ALGORITHM, algorithm); + var algo = (match[1] || match[3]).toLowerCase(); + var bits = match[2]; + + return { + sign: signerFactories[algo](bits), + verify: verifierFactories[algo](bits), + } +}; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jwa/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jwa/package.json new file mode 100644 index 0000000..135dbb0 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jwa/package.json @@ -0,0 +1,69 @@ +{ + "_from": "jwa@^1.4.1", + "_id": "jwa@1.4.1", + "_inBundle": false, + "_integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "_location": "/jwa", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "jwa@^1.4.1", + "name": "jwa", + "escapedName": "jwa", + "rawSpec": "^1.4.1", + "saveSpec": null, + "fetchSpec": "^1.4.1" + }, + "_requiredBy": [ + "/jws" + ], + "_resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "_shasum": "743c32985cb9e98655530d53641b66c8645b039a", + "_spec": "jwa@^1.4.1", + "_where": "D:\\xm\\online-code\\hellounicloud\\uni_modules\\uni-id-pages\\uniCloud\\cloudfunctions\\uni-id-co\\node_modules\\jws", + "author": { + "name": "Brian J. Brennan", + "email": "brianloveswords@gmail.com" + }, + "bugs": { + "url": "https://github.com/brianloveswords/node-jwa/issues" + }, + "bundleDependencies": false, + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + }, + "deprecated": false, + "description": "JWA implementation (supports all JWS algorithms)", + "devDependencies": { + "base64url": "^2.0.0", + "jwk-to-pem": "^2.0.1", + "semver": "4.3.6", + "tap": "6.2.0" + }, + "directories": { + "test": "test" + }, + "homepage": "https://github.com/brianloveswords/node-jwa#readme", + "keywords": [ + "jwa", + "jws", + "jwt", + "rsa", + "ecdsa", + "hmac" + ], + "license": "MIT", + "main": "index.js", + "name": "jwa", + "repository": { + "type": "git", + "url": "git://github.com/brianloveswords/node-jwa.git" + }, + "scripts": { + "test": "make test" + }, + "version": "1.4.1" +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/CHANGELOG.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/CHANGELOG.md new file mode 100644 index 0000000..af8fc28 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/CHANGELOG.md @@ -0,0 +1,34 @@ +# Change Log +All notable changes to this project will be documented in this file. + +## [3.0.0] +### Changed +- **BREAKING**: `jwt.verify` now requires an `algorithm` parameter, and + `jws.createVerify` requires an `algorithm` option. The `"alg"` field + signature headers is ignored. This mitigates a critical security flaw + in the library which would allow an attacker to generate signatures with + arbitrary contents that would be accepted by `jwt.verify`. See + https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/ + for details. + +## [2.0.0] - 2015-01-30 +### Changed +- **BREAKING**: Default payload encoding changed from `binary` to + `utf8`. `utf8` is a is a more sensible default than `binary` because + many payloads, as far as I can tell, will contain user-facing + strings that could be in any language. ([6b6de48]) + +- Code reorganization, thanks [@fearphage]! ([7880050]) + +### Added +- Option in all relevant methods for `encoding`. For those few users + that might be depending on a `binary` encoding of the messages, this + is for them. ([6b6de48]) + +[unreleased]: https://github.com/brianloveswords/node-jws/compare/v2.0.0...HEAD +[2.0.0]: https://github.com/brianloveswords/node-jws/compare/v1.0.1...v2.0.0 + +[7880050]: https://github.com/brianloveswords/node-jws/commit/7880050 +[6b6de48]: https://github.com/brianloveswords/node-jws/commit/6b6de48 + +[@fearphage]: https://github.com/fearphage diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/LICENSE b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/LICENSE new file mode 100644 index 0000000..caeb849 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/LICENSE @@ -0,0 +1,17 @@ +Copyright (c) 2013 Brian J. Brennan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/index.js new file mode 100644 index 0000000..8c8da93 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/index.js @@ -0,0 +1,22 @@ +/*global exports*/ +var SignStream = require('./lib/sign-stream'); +var VerifyStream = require('./lib/verify-stream'); + +var ALGORITHMS = [ + 'HS256', 'HS384', 'HS512', + 'RS256', 'RS384', 'RS512', + 'PS256', 'PS384', 'PS512', + 'ES256', 'ES384', 'ES512' +]; + +exports.ALGORITHMS = ALGORITHMS; +exports.sign = SignStream.sign; +exports.verify = VerifyStream.verify; +exports.decode = VerifyStream.decode; +exports.isValid = VerifyStream.isValid; +exports.createSign = function createSign(opts) { + return new SignStream(opts); +}; +exports.createVerify = function createVerify(opts) { + return new VerifyStream(opts); +}; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/lib/data-stream.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/lib/data-stream.js new file mode 100644 index 0000000..3535d31 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/lib/data-stream.js @@ -0,0 +1,55 @@ +/*global module, process*/ +var Buffer = require('safe-buffer').Buffer; +var Stream = require('stream'); +var util = require('util'); + +function DataStream(data) { + this.buffer = null; + this.writable = true; + this.readable = true; + + // No input + if (!data) { + this.buffer = Buffer.alloc(0); + return this; + } + + // Stream + if (typeof data.pipe === 'function') { + this.buffer = Buffer.alloc(0); + data.pipe(this); + return this; + } + + // Buffer or String + // or Object (assumedly a passworded key) + if (data.length || typeof data === 'object') { + this.buffer = data; + this.writable = false; + process.nextTick(function () { + this.emit('end', data); + this.readable = false; + this.emit('close'); + }.bind(this)); + return this; + } + + throw new TypeError('Unexpected data type ('+ typeof data + ')'); +} +util.inherits(DataStream, Stream); + +DataStream.prototype.write = function write(data) { + this.buffer = Buffer.concat([this.buffer, Buffer.from(data)]); + this.emit('data', data); +}; + +DataStream.prototype.end = function end(data) { + if (data) + this.write(data); + this.emit('end', data); + this.emit('close'); + this.writable = false; + this.readable = false; +}; + +module.exports = DataStream; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/lib/sign-stream.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/lib/sign-stream.js new file mode 100644 index 0000000..6a7ee42 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/lib/sign-stream.js @@ -0,0 +1,78 @@ +/*global module*/ +var Buffer = require('safe-buffer').Buffer; +var DataStream = require('./data-stream'); +var jwa = require('jwa'); +var Stream = require('stream'); +var toString = require('./tostring'); +var util = require('util'); + +function base64url(string, encoding) { + return Buffer + .from(string, encoding) + .toString('base64') + .replace(/=/g, '') + .replace(/\+/g, '-') + .replace(/\//g, '_'); +} + +function jwsSecuredInput(header, payload, encoding) { + encoding = encoding || 'utf8'; + var encodedHeader = base64url(toString(header), 'binary'); + var encodedPayload = base64url(toString(payload), encoding); + return util.format('%s.%s', encodedHeader, encodedPayload); +} + +function jwsSign(opts) { + var header = opts.header; + var payload = opts.payload; + var secretOrKey = opts.secret || opts.privateKey; + var encoding = opts.encoding; + var algo = jwa(header.alg); + var securedInput = jwsSecuredInput(header, payload, encoding); + var signature = algo.sign(securedInput, secretOrKey); + return util.format('%s.%s', securedInput, signature); +} + +function SignStream(opts) { + var secret = opts.secret||opts.privateKey||opts.key; + var secretStream = new DataStream(secret); + this.readable = true; + this.header = opts.header; + this.encoding = opts.encoding; + this.secret = this.privateKey = this.key = secretStream; + this.payload = new DataStream(opts.payload); + this.secret.once('close', function () { + if (!this.payload.writable && this.readable) + this.sign(); + }.bind(this)); + + this.payload.once('close', function () { + if (!this.secret.writable && this.readable) + this.sign(); + }.bind(this)); +} +util.inherits(SignStream, Stream); + +SignStream.prototype.sign = function sign() { + try { + var signature = jwsSign({ + header: this.header, + payload: this.payload.buffer, + secret: this.secret.buffer, + encoding: this.encoding + }); + this.emit('done', signature); + this.emit('data', signature); + this.emit('end'); + this.readable = false; + return signature; + } catch (e) { + this.readable = false; + this.emit('error', e); + this.emit('close'); + } +}; + +SignStream.sign = jwsSign; + +module.exports = SignStream; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/lib/tostring.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/lib/tostring.js new file mode 100644 index 0000000..f5a49a3 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/lib/tostring.js @@ -0,0 +1,10 @@ +/*global module*/ +var Buffer = require('buffer').Buffer; + +module.exports = function toString(obj) { + if (typeof obj === 'string') + return obj; + if (typeof obj === 'number' || Buffer.isBuffer(obj)) + return obj.toString(); + return JSON.stringify(obj); +}; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/lib/verify-stream.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/lib/verify-stream.js new file mode 100644 index 0000000..39f7c73 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/lib/verify-stream.js @@ -0,0 +1,120 @@ +/*global module*/ +var Buffer = require('safe-buffer').Buffer; +var DataStream = require('./data-stream'); +var jwa = require('jwa'); +var Stream = require('stream'); +var toString = require('./tostring'); +var util = require('util'); +var JWS_REGEX = /^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$/; + +function isObject(thing) { + return Object.prototype.toString.call(thing) === '[object Object]'; +} + +function safeJsonParse(thing) { + if (isObject(thing)) + return thing; + try { return JSON.parse(thing); } + catch (e) { return undefined; } +} + +function headerFromJWS(jwsSig) { + var encodedHeader = jwsSig.split('.', 1)[0]; + return safeJsonParse(Buffer.from(encodedHeader, 'base64').toString('binary')); +} + +function securedInputFromJWS(jwsSig) { + return jwsSig.split('.', 2).join('.'); +} + +function signatureFromJWS(jwsSig) { + return jwsSig.split('.')[2]; +} + +function payloadFromJWS(jwsSig, encoding) { + encoding = encoding || 'utf8'; + var payload = jwsSig.split('.')[1]; + return Buffer.from(payload, 'base64').toString(encoding); +} + +function isValidJws(string) { + return JWS_REGEX.test(string) && !!headerFromJWS(string); +} + +function jwsVerify(jwsSig, algorithm, secretOrKey) { + if (!algorithm) { + var err = new Error("Missing algorithm parameter for jws.verify"); + err.code = "MISSING_ALGORITHM"; + throw err; + } + jwsSig = toString(jwsSig); + var signature = signatureFromJWS(jwsSig); + var securedInput = securedInputFromJWS(jwsSig); + var algo = jwa(algorithm); + return algo.verify(securedInput, signature, secretOrKey); +} + +function jwsDecode(jwsSig, opts) { + opts = opts || {}; + jwsSig = toString(jwsSig); + + if (!isValidJws(jwsSig)) + return null; + + var header = headerFromJWS(jwsSig); + + if (!header) + return null; + + var payload = payloadFromJWS(jwsSig); + if (header.typ === 'JWT' || opts.json) + payload = JSON.parse(payload, opts.encoding); + + return { + header: header, + payload: payload, + signature: signatureFromJWS(jwsSig) + }; +} + +function VerifyStream(opts) { + opts = opts || {}; + var secretOrKey = opts.secret||opts.publicKey||opts.key; + var secretStream = new DataStream(secretOrKey); + this.readable = true; + this.algorithm = opts.algorithm; + this.encoding = opts.encoding; + this.secret = this.publicKey = this.key = secretStream; + this.signature = new DataStream(opts.signature); + this.secret.once('close', function () { + if (!this.signature.writable && this.readable) + this.verify(); + }.bind(this)); + + this.signature.once('close', function () { + if (!this.secret.writable && this.readable) + this.verify(); + }.bind(this)); +} +util.inherits(VerifyStream, Stream); +VerifyStream.prototype.verify = function verify() { + try { + var valid = jwsVerify(this.signature.buffer, this.algorithm, this.key.buffer); + var obj = jwsDecode(this.signature.buffer, this.encoding); + this.emit('done', valid, obj); + this.emit('data', valid); + this.emit('end'); + this.readable = false; + return valid; + } catch (e) { + this.readable = false; + this.emit('error', e); + this.emit('close'); + } +}; + +VerifyStream.decode = jwsDecode; +VerifyStream.isValid = isValidJws; +VerifyStream.verify = jwsVerify; + +module.exports = VerifyStream; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/package.json new file mode 100644 index 0000000..def1772 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/package.json @@ -0,0 +1,64 @@ +{ + "_from": "jws@^3.2.2", + "_id": "jws@3.2.2", + "_inBundle": false, + "_integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "_location": "/jws", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "jws@^3.2.2", + "name": "jws", + "escapedName": "jws", + "rawSpec": "^3.2.2", + "saveSpec": null, + "fetchSpec": "^3.2.2" + }, + "_requiredBy": [ + "/jsonwebtoken" + ], + "_resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "_shasum": "001099f3639468c9414000e99995fa52fb478304", + "_spec": "jws@^3.2.2", + "_where": "D:\\xm\\online-code\\hellounicloud\\uni_modules\\uni-id-pages\\uniCloud\\cloudfunctions\\uni-id-co\\node_modules\\jsonwebtoken", + "author": { + "name": "Brian J Brennan" + }, + "bugs": { + "url": "https://github.com/brianloveswords/node-jws/issues" + }, + "bundleDependencies": false, + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + }, + "deprecated": false, + "description": "Implementation of JSON Web Signatures", + "devDependencies": { + "semver": "^5.1.0", + "tape": "~2.14.0" + }, + "directories": { + "test": "test" + }, + "gitHead": "c0f6b27bcea5a2ad2e304d91c2e842e4076a6b03", + "homepage": "https://github.com/brianloveswords/node-jws#readme", + "keywords": [ + "jws", + "json", + "web", + "signatures" + ], + "license": "MIT", + "main": "index.js", + "name": "jws", + "repository": { + "type": "git", + "url": "git://github.com/brianloveswords/node-jws.git" + }, + "scripts": { + "test": "make test" + }, + "version": "3.2.2" +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/readme.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/readme.md new file mode 100644 index 0000000..1910c9a --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/jws/readme.md @@ -0,0 +1,255 @@ +# node-jws [![Build Status](https://secure.travis-ci.org/brianloveswords/node-jws.png)](http://travis-ci.org/brianloveswords/node-jws) + +An implementation of [JSON Web Signatures](http://self-issued.info/docs/draft-ietf-jose-json-web-signature.html). + +This was developed against `draft-ietf-jose-json-web-signature-08` and +implements the entire spec **except** X.509 Certificate Chain +signing/verifying (patches welcome). + +There are both synchronous (`jws.sign`, `jws.verify`) and streaming +(`jws.createSign`, `jws.createVerify`) APIs. + +# Install + +```bash +$ npm install jws +``` + +# Usage + +## jws.ALGORITHMS + +Array of supported algorithms. The following algorithms are currently supported. + +alg Parameter Value | Digital Signature or MAC Algorithm +----------------|---------------------------- +HS256 | HMAC using SHA-256 hash algorithm +HS384 | HMAC using SHA-384 hash algorithm +HS512 | HMAC using SHA-512 hash algorithm +RS256 | RSASSA using SHA-256 hash algorithm +RS384 | RSASSA using SHA-384 hash algorithm +RS512 | RSASSA using SHA-512 hash algorithm +PS256 | RSASSA-PSS using SHA-256 hash algorithm +PS384 | RSASSA-PSS using SHA-384 hash algorithm +PS512 | RSASSA-PSS using SHA-512 hash algorithm +ES256 | ECDSA using P-256 curve and SHA-256 hash algorithm +ES384 | ECDSA using P-384 curve and SHA-384 hash algorithm +ES512 | ECDSA using P-521 curve and SHA-512 hash algorithm +none | No digital signature or MAC value included + +## jws.sign(options) + +(Synchronous) Return a JSON Web Signature for a header and a payload. + +Options: + +* `header` +* `payload` +* `secret` or `privateKey` +* `encoding` (Optional, defaults to 'utf8') + +`header` must be an object with an `alg` property. `header.alg` must be +one a value found in `jws.ALGORITHMS`. See above for a table of +supported algorithms. + +If `payload` is not a buffer or a string, it will be coerced into a string +using `JSON.stringify`. + +Example + +```js +const signature = jws.sign({ + header: { alg: 'HS256' }, + payload: 'h. jon benjamin', + secret: 'has a van', +}); +``` + +## jws.verify(signature, algorithm, secretOrKey) + +(Synchronous) Returns `true` or `false` for whether a signature matches a +secret or key. + +`signature` is a JWS Signature. `header.alg` must be a value found in `jws.ALGORITHMS`. +See above for a table of supported algorithms. `secretOrKey` is a string or +buffer containing either the secret for HMAC algorithms, or the PEM +encoded public key for RSA and ECDSA. + +Note that the `"alg"` value from the signature header is ignored. + + +## jws.decode(signature) + +(Synchronous) Returns the decoded header, decoded payload, and signature +parts of the JWS Signature. + +Returns an object with three properties, e.g. +```js +{ header: { alg: 'HS256' }, + payload: 'h. jon benjamin', + signature: 'YOWPewyGHKu4Y_0M_vtlEnNlqmFOclqp4Hy6hVHfFT4' +} +``` + +## jws.createSign(options) + +Returns a new SignStream object. + +Options: + +* `header` (required) +* `payload` +* `key` || `privateKey` || `secret` +* `encoding` (Optional, defaults to 'utf8') + +Other than `header`, all options expect a string or a buffer when the +value is known ahead of time, or a stream for convenience. +`key`/`privateKey`/`secret` may also be an object when using an encrypted +private key, see the [crypto documentation][encrypted-key-docs]. + +Example: + +```js + +// This... +jws.createSign({ + header: { alg: 'RS256' }, + privateKey: privateKeyStream, + payload: payloadStream, +}).on('done', function(signature) { + // ... +}); + +// is equivalent to this: +const signer = jws.createSign({ + header: { alg: 'RS256' }, +}); +privateKeyStream.pipe(signer.privateKey); +payloadStream.pipe(signer.payload); +signer.on('done', function(signature) { + // ... +}); +``` + +## jws.createVerify(options) + +Returns a new VerifyStream object. + +Options: + +* `signature` +* `algorithm` +* `key` || `publicKey` || `secret` +* `encoding` (Optional, defaults to 'utf8') + +All options expect a string or a buffer when the value is known ahead of +time, or a stream for convenience. + +Example: + +```js + +// This... +jws.createVerify({ + publicKey: pubKeyStream, + signature: sigStream, +}).on('done', function(verified, obj) { + // ... +}); + +// is equivilant to this: +const verifier = jws.createVerify(); +pubKeyStream.pipe(verifier.publicKey); +sigStream.pipe(verifier.signature); +verifier.on('done', function(verified, obj) { + // ... +}); +``` + +## Class: SignStream + +A `Readable Stream` that emits a single data event (the calculated +signature) when done. + +### Event: 'done' +`function (signature) { }` + +### signer.payload + +A `Writable Stream` that expects the JWS payload. Do *not* use if you +passed a `payload` option to the constructor. + +Example: + +```js +payloadStream.pipe(signer.payload); +``` + +### signer.secret
signer.key
signer.privateKey + +A `Writable Stream`. Expects the JWS secret for HMAC, or the privateKey +for ECDSA and RSA. Do *not* use if you passed a `secret` or `key` option +to the constructor. + +Example: + +```js +privateKeyStream.pipe(signer.privateKey); +``` + +## Class: VerifyStream + +This is a `Readable Stream` that emits a single data event, the result +of whether or not that signature was valid. + +### Event: 'done' +`function (valid, obj) { }` + +`valid` is a boolean for whether or not the signature is valid. + +### verifier.signature + +A `Writable Stream` that expects a JWS Signature. Do *not* use if you +passed a `signature` option to the constructor. + +### verifier.secret
verifier.key
verifier.publicKey + +A `Writable Stream` that expects a public key or secret. Do *not* use if you +passed a `key` or `secret` option to the constructor. + +# TODO + +* It feels like there should be some convenience options/APIs for + defining the algorithm rather than having to define a header object + with `{ alg: 'ES512' }` or whatever every time. + +* X.509 support, ugh + +# License + +MIT + +``` +Copyright (c) 2013-2015 Brian J. Brennan + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +``` + +[encrypted-key-docs]: https://nodejs.org/api/crypto.html#crypto_sign_sign_private_key_output_format diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.includes/LICENSE b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.includes/LICENSE new file mode 100644 index 0000000..e0c69d5 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.includes/LICENSE @@ -0,0 +1,47 @@ +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.includes/README.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.includes/README.md new file mode 100644 index 0000000..26e9377 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.includes/README.md @@ -0,0 +1,18 @@ +# lodash.includes v4.3.0 + +The [lodash](https://lodash.com/) method `_.includes` exported as a [Node.js](https://nodejs.org/) module. + +## Installation + +Using npm: +```bash +$ {sudo -H} npm i -g npm +$ npm i --save lodash.includes +``` + +In Node.js: +```js +var includes = require('lodash.includes'); +``` + +See the [documentation](https://lodash.com/docs#includes) or [package source](https://github.com/lodash/lodash/blob/4.3.0-npm-packages/lodash.includes) for more details. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.includes/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.includes/index.js new file mode 100644 index 0000000..e88d533 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.includes/index.js @@ -0,0 +1,745 @@ +/** + * lodash (Custom Build) + * Build: `lodash modularize exports="npm" -o ./` + * Copyright jQuery Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */ + +/** Used as references for various `Number` constants. */ +var INFINITY = 1 / 0, + MAX_SAFE_INTEGER = 9007199254740991, + MAX_INTEGER = 1.7976931348623157e+308, + NAN = 0 / 0; + +/** `Object#toString` result references. */ +var argsTag = '[object Arguments]', + funcTag = '[object Function]', + genTag = '[object GeneratorFunction]', + stringTag = '[object String]', + symbolTag = '[object Symbol]'; + +/** Used to match leading and trailing whitespace. */ +var reTrim = /^\s+|\s+$/g; + +/** Used to detect bad signed hexadecimal string values. */ +var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; + +/** Used to detect binary string values. */ +var reIsBinary = /^0b[01]+$/i; + +/** Used to detect octal string values. */ +var reIsOctal = /^0o[0-7]+$/i; + +/** Used to detect unsigned integer values. */ +var reIsUint = /^(?:0|[1-9]\d*)$/; + +/** Built-in method references without a dependency on `root`. */ +var freeParseInt = parseInt; + +/** + * A specialized version of `_.map` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ +function arrayMap(array, iteratee) { + var index = -1, + length = array ? array.length : 0, + result = Array(length); + + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; +} + +/** + * The base implementation of `_.findIndex` and `_.findLastIndex` without + * support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {number} fromIndex The index to search from. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {number} Returns the index of the matched value, else `-1`. + */ +function baseFindIndex(array, predicate, fromIndex, fromRight) { + var length = array.length, + index = fromIndex + (fromRight ? 1 : -1); + + while ((fromRight ? index-- : ++index < length)) { + if (predicate(array[index], index, array)) { + return index; + } + } + return -1; +} + +/** + * The base implementation of `_.indexOf` without `fromIndex` bounds checks. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ +function baseIndexOf(array, value, fromIndex) { + if (value !== value) { + return baseFindIndex(array, baseIsNaN, fromIndex); + } + var index = fromIndex - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; +} + +/** + * The base implementation of `_.isNaN` without support for number objects. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + */ +function baseIsNaN(value) { + return value !== value; +} + +/** + * The base implementation of `_.times` without support for iteratee shorthands + * or max array length checks. + * + * @private + * @param {number} n The number of times to invoke `iteratee`. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the array of results. + */ +function baseTimes(n, iteratee) { + var index = -1, + result = Array(n); + + while (++index < n) { + result[index] = iteratee(index); + } + return result; +} + +/** + * The base implementation of `_.values` and `_.valuesIn` which creates an + * array of `object` property values corresponding to the property names + * of `props`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} props The property names to get values for. + * @returns {Object} Returns the array of property values. + */ +function baseValues(object, props) { + return arrayMap(props, function(key) { + return object[key]; + }); +} + +/** + * Creates a unary function that invokes `func` with its argument transformed. + * + * @private + * @param {Function} func The function to wrap. + * @param {Function} transform The argument transform. + * @returns {Function} Returns the new function. + */ +function overArg(func, transform) { + return function(arg) { + return func(transform(arg)); + }; +} + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var objectToString = objectProto.toString; + +/** Built-in value references. */ +var propertyIsEnumerable = objectProto.propertyIsEnumerable; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeKeys = overArg(Object.keys, Object), + nativeMax = Math.max; + +/** + * Creates an array of the enumerable property names of the array-like `value`. + * + * @private + * @param {*} value The value to query. + * @param {boolean} inherited Specify returning inherited property names. + * @returns {Array} Returns the array of property names. + */ +function arrayLikeKeys(value, inherited) { + // Safari 8.1 makes `arguments.callee` enumerable in strict mode. + // Safari 9 makes `arguments.length` enumerable in strict mode. + var result = (isArray(value) || isArguments(value)) + ? baseTimes(value.length, String) + : []; + + var length = result.length, + skipIndexes = !!length; + + for (var key in value) { + if ((inherited || hasOwnProperty.call(value, key)) && + !(skipIndexes && (key == 'length' || isIndex(key, length)))) { + result.push(key); + } + } + return result; +} + +/** + * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ +function baseKeys(object) { + if (!isPrototype(object)) { + return nativeKeys(object); + } + var result = []; + for (var key in Object(object)) { + if (hasOwnProperty.call(object, key) && key != 'constructor') { + result.push(key); + } + } + return result; +} + +/** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ +function isIndex(value, length) { + length = length == null ? MAX_SAFE_INTEGER : length; + return !!length && + (typeof value == 'number' || reIsUint.test(value)) && + (value > -1 && value % 1 == 0 && value < length); +} + +/** + * Checks if `value` is likely a prototype object. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. + */ +function isPrototype(value) { + var Ctor = value && value.constructor, + proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; + + return value === proto; +} + +/** + * Checks if `value` is in `collection`. If `collection` is a string, it's + * checked for a substring of `value`, otherwise + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * is used for equality comparisons. If `fromIndex` is negative, it's used as + * the offset from the end of `collection`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object|string} collection The collection to inspect. + * @param {*} value The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. + * @returns {boolean} Returns `true` if `value` is found, else `false`. + * @example + * + * _.includes([1, 2, 3], 1); + * // => true + * + * _.includes([1, 2, 3], 1, 2); + * // => false + * + * _.includes({ 'a': 1, 'b': 2 }, 1); + * // => true + * + * _.includes('abcd', 'bc'); + * // => true + */ +function includes(collection, value, fromIndex, guard) { + collection = isArrayLike(collection) ? collection : values(collection); + fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0; + + var length = collection.length; + if (fromIndex < 0) { + fromIndex = nativeMax(length + fromIndex, 0); + } + return isString(collection) + ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1) + : (!!length && baseIndexOf(collection, value, fromIndex) > -1); +} + +/** + * Checks if `value` is likely an `arguments` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ +function isArguments(value) { + // Safari 8.1 makes `arguments.callee` enumerable in strict mode. + return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') && + (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag); +} + +/** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ +var isArray = Array.isArray; + +/** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(document.body.children); + * // => true + * + * _.isArrayLike('abc'); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ +function isArrayLike(value) { + return value != null && isLength(value.length) && !isFunction(value); +} + +/** + * This method is like `_.isArrayLike` except that it also checks if `value` + * is an object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array-like object, + * else `false`. + * @example + * + * _.isArrayLikeObject([1, 2, 3]); + * // => true + * + * _.isArrayLikeObject(document.body.children); + * // => true + * + * _.isArrayLikeObject('abc'); + * // => false + * + * _.isArrayLikeObject(_.noop); + * // => false + */ +function isArrayLikeObject(value) { + return isObjectLike(value) && isArrayLike(value); +} + +/** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ +function isFunction(value) { + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 8-9 which returns 'object' for typed array and other constructors. + var tag = isObject(value) ? objectToString.call(value) : ''; + return tag == funcTag || tag == genTag; +} + +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This method is loosely based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @example + * + * _.isLength(3); + * // => true + * + * _.isLength(Number.MIN_VALUE); + * // => false + * + * _.isLength(Infinity); + * // => false + * + * _.isLength('3'); + * // => false + */ +function isLength(value) { + return typeof value == 'number' && + value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} + +/** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ +function isObject(value) { + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); +} + +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { + return !!value && typeof value == 'object'; +} + +/** + * Checks if `value` is classified as a `String` primitive or object. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a string, else `false`. + * @example + * + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false + */ +function isString(value) { + return typeof value == 'string' || + (!isArray(value) && isObjectLike(value) && objectToString.call(value) == stringTag); +} + +/** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ +function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && objectToString.call(value) == symbolTag); +} + +/** + * Converts `value` to a finite number. + * + * @static + * @memberOf _ + * @since 4.12.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted number. + * @example + * + * _.toFinite(3.2); + * // => 3.2 + * + * _.toFinite(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toFinite(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toFinite('3.2'); + * // => 3.2 + */ +function toFinite(value) { + if (!value) { + return value === 0 ? value : 0; + } + value = toNumber(value); + if (value === INFINITY || value === -INFINITY) { + var sign = (value < 0 ? -1 : 1); + return sign * MAX_INTEGER; + } + return value === value ? value : 0; +} + +/** + * Converts `value` to an integer. + * + * **Note:** This method is loosely based on + * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toInteger(3.2); + * // => 3 + * + * _.toInteger(Number.MIN_VALUE); + * // => 0 + * + * _.toInteger(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toInteger('3.2'); + * // => 3 + */ +function toInteger(value) { + var result = toFinite(value), + remainder = result % 1; + + return result === result ? (remainder ? result - remainder : result) : 0; +} + +/** + * Converts `value` to a number. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to process. + * @returns {number} Returns the number. + * @example + * + * _.toNumber(3.2); + * // => 3.2 + * + * _.toNumber(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toNumber(Infinity); + * // => Infinity + * + * _.toNumber('3.2'); + * // => 3.2 + */ +function toNumber(value) { + if (typeof value == 'number') { + return value; + } + if (isSymbol(value)) { + return NAN; + } + if (isObject(value)) { + var other = typeof value.valueOf == 'function' ? value.valueOf() : value; + value = isObject(other) ? (other + '') : other; + } + if (typeof value != 'string') { + return value === 0 ? value : +value; + } + value = value.replace(reTrim, ''); + var isBinary = reIsBinary.test(value); + return (isBinary || reIsOctal.test(value)) + ? freeParseInt(value.slice(2), isBinary ? 2 : 8) + : (reIsBadHex.test(value) ? NAN : +value); +} + +/** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * for more details. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ +function keys(object) { + return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); +} + +/** + * Creates an array of the own enumerable string keyed property values of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property values. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.values(new Foo); + * // => [1, 2] (iteration order is not guaranteed) + * + * _.values('hi'); + * // => ['h', 'i'] + */ +function values(object) { + return object ? baseValues(object, keys(object)) : []; +} + +module.exports = includes; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.includes/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.includes/package.json new file mode 100644 index 0000000..c96e6b6 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.includes/package.json @@ -0,0 +1,69 @@ +{ + "_from": "lodash.includes@^4.3.0", + "_id": "lodash.includes@4.3.0", + "_inBundle": false, + "_integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "_location": "/lodash.includes", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "lodash.includes@^4.3.0", + "name": "lodash.includes", + "escapedName": "lodash.includes", + "rawSpec": "^4.3.0", + "saveSpec": null, + "fetchSpec": "^4.3.0" + }, + "_requiredBy": [ + "/jsonwebtoken" + ], + "_resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "_shasum": "60bb98a87cb923c68ca1e51325483314849f553f", + "_spec": "lodash.includes@^4.3.0", + "_where": "D:\\xm\\online-code\\hellounicloud\\uni_modules\\uni-id-pages\\uniCloud\\cloudfunctions\\uni-id-co\\node_modules\\jsonwebtoken", + "author": { + "name": "John-David Dalton", + "email": "john.david.dalton@gmail.com", + "url": "http://allyoucanleet.com/" + }, + "bugs": { + "url": "https://github.com/lodash/lodash/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "John-David Dalton", + "email": "john.david.dalton@gmail.com", + "url": "http://allyoucanleet.com/" + }, + { + "name": "Blaine Bublitz", + "email": "blaine.bublitz@gmail.com", + "url": "https://github.com/phated" + }, + { + "name": "Mathias Bynens", + "email": "mathias@qiwi.be", + "url": "https://mathiasbynens.be/" + } + ], + "deprecated": false, + "description": "The lodash method `_.includes` exported as a module.", + "homepage": "https://lodash.com/", + "icon": "https://lodash.com/icon.svg", + "keywords": [ + "lodash-modularized", + "includes" + ], + "license": "MIT", + "name": "lodash.includes", + "repository": { + "type": "git", + "url": "git+https://github.com/lodash/lodash.git" + }, + "scripts": { + "test": "echo \"See https://travis-ci.org/lodash/lodash-cli for testing details.\"" + }, + "version": "4.3.0" +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isboolean/LICENSE b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isboolean/LICENSE new file mode 100644 index 0000000..b054ca5 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isboolean/LICENSE @@ -0,0 +1,22 @@ +Copyright 2012-2016 The Dojo Foundation +Based on Underscore.js, copyright 2009-2016 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isboolean/README.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isboolean/README.md new file mode 100644 index 0000000..b3c476b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isboolean/README.md @@ -0,0 +1,18 @@ +# lodash.isboolean v3.0.3 + +The [lodash](https://lodash.com/) method `_.isBoolean` exported as a [Node.js](https://nodejs.org/) module. + +## Installation + +Using npm: +```bash +$ {sudo -H} npm i -g npm +$ npm i --save lodash.isboolean +``` + +In Node.js: +```js +var isBoolean = require('lodash.isboolean'); +``` + +See the [documentation](https://lodash.com/docs#isBoolean) or [package source](https://github.com/lodash/lodash/blob/3.0.3-npm-packages/lodash.isboolean) for more details. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isboolean/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isboolean/index.js new file mode 100644 index 0000000..23bbabd --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isboolean/index.js @@ -0,0 +1,70 @@ +/** + * lodash 3.0.3 (Custom Build) + * Build: `lodash modularize exports="npm" -o ./` + * Copyright 2012-2016 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** `Object#toString` result references. */ +var boolTag = '[object Boolean]'; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) + * of values. + */ +var objectToString = objectProto.toString; + +/** + * Checks if `value` is classified as a boolean primitive or object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isBoolean(false); + * // => true + * + * _.isBoolean(null); + * // => false + */ +function isBoolean(value) { + return value === true || value === false || + (isObjectLike(value) && objectToString.call(value) == boolTag); +} + +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { + return !!value && typeof value == 'object'; +} + +module.exports = isBoolean; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isboolean/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isboolean/package.json new file mode 100644 index 0000000..950c2ec --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isboolean/package.json @@ -0,0 +1,69 @@ +{ + "_from": "lodash.isboolean@^3.0.3", + "_id": "lodash.isboolean@3.0.3", + "_inBundle": false, + "_integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "_location": "/lodash.isboolean", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "lodash.isboolean@^3.0.3", + "name": "lodash.isboolean", + "escapedName": "lodash.isboolean", + "rawSpec": "^3.0.3", + "saveSpec": null, + "fetchSpec": "^3.0.3" + }, + "_requiredBy": [ + "/jsonwebtoken" + ], + "_resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "_shasum": "6c2e171db2a257cd96802fd43b01b20d5f5870f6", + "_spec": "lodash.isboolean@^3.0.3", + "_where": "D:\\xm\\online-code\\hellounicloud\\uni_modules\\uni-id-pages\\uniCloud\\cloudfunctions\\uni-id-co\\node_modules\\jsonwebtoken", + "author": { + "name": "John-David Dalton", + "email": "john.david.dalton@gmail.com", + "url": "http://allyoucanleet.com/" + }, + "bugs": { + "url": "https://github.com/lodash/lodash/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "John-David Dalton", + "email": "john.david.dalton@gmail.com", + "url": "http://allyoucanleet.com/" + }, + { + "name": "Blaine Bublitz", + "email": "blaine@iceddev.com", + "url": "https://github.com/phated" + }, + { + "name": "Mathias Bynens", + "email": "mathias@qiwi.be", + "url": "https://mathiasbynens.be/" + } + ], + "deprecated": false, + "description": "The lodash method `_.isBoolean` exported as a module.", + "homepage": "https://lodash.com/", + "icon": "https://lodash.com/icon.svg", + "keywords": [ + "lodash-modularized", + "isboolean" + ], + "license": "MIT", + "name": "lodash.isboolean", + "repository": { + "type": "git", + "url": "git+https://github.com/lodash/lodash.git" + }, + "scripts": { + "test": "echo \"See https://travis-ci.org/lodash/lodash-cli for testing details.\"" + }, + "version": "3.0.3" +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isinteger/LICENSE b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isinteger/LICENSE new file mode 100644 index 0000000..e0c69d5 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isinteger/LICENSE @@ -0,0 +1,47 @@ +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isinteger/README.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isinteger/README.md new file mode 100644 index 0000000..3a78567 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isinteger/README.md @@ -0,0 +1,18 @@ +# lodash.isinteger v4.0.4 + +The [lodash](https://lodash.com/) method `_.isInteger` exported as a [Node.js](https://nodejs.org/) module. + +## Installation + +Using npm: +```bash +$ {sudo -H} npm i -g npm +$ npm i --save lodash.isinteger +``` + +In Node.js: +```js +var isInteger = require('lodash.isinteger'); +``` + +See the [documentation](https://lodash.com/docs#isInteger) or [package source](https://github.com/lodash/lodash/blob/4.0.4-npm-packages/lodash.isinteger) for more details. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isinteger/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isinteger/index.js new file mode 100644 index 0000000..3bf06f0 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isinteger/index.js @@ -0,0 +1,265 @@ +/** + * lodash (Custom Build) + * Build: `lodash modularize exports="npm" -o ./` + * Copyright jQuery Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */ + +/** Used as references for various `Number` constants. */ +var INFINITY = 1 / 0, + MAX_INTEGER = 1.7976931348623157e+308, + NAN = 0 / 0; + +/** `Object#toString` result references. */ +var symbolTag = '[object Symbol]'; + +/** Used to match leading and trailing whitespace. */ +var reTrim = /^\s+|\s+$/g; + +/** Used to detect bad signed hexadecimal string values. */ +var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; + +/** Used to detect binary string values. */ +var reIsBinary = /^0b[01]+$/i; + +/** Used to detect octal string values. */ +var reIsOctal = /^0o[0-7]+$/i; + +/** Built-in method references without a dependency on `root`. */ +var freeParseInt = parseInt; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var objectToString = objectProto.toString; + +/** + * Checks if `value` is an integer. + * + * **Note:** This method is based on + * [`Number.isInteger`](https://mdn.io/Number/isInteger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an integer, else `false`. + * @example + * + * _.isInteger(3); + * // => true + * + * _.isInteger(Number.MIN_VALUE); + * // => false + * + * _.isInteger(Infinity); + * // => false + * + * _.isInteger('3'); + * // => false + */ +function isInteger(value) { + return typeof value == 'number' && value == toInteger(value); +} + +/** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ +function isObject(value) { + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); +} + +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { + return !!value && typeof value == 'object'; +} + +/** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ +function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && objectToString.call(value) == symbolTag); +} + +/** + * Converts `value` to a finite number. + * + * @static + * @memberOf _ + * @since 4.12.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted number. + * @example + * + * _.toFinite(3.2); + * // => 3.2 + * + * _.toFinite(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toFinite(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toFinite('3.2'); + * // => 3.2 + */ +function toFinite(value) { + if (!value) { + return value === 0 ? value : 0; + } + value = toNumber(value); + if (value === INFINITY || value === -INFINITY) { + var sign = (value < 0 ? -1 : 1); + return sign * MAX_INTEGER; + } + return value === value ? value : 0; +} + +/** + * Converts `value` to an integer. + * + * **Note:** This method is loosely based on + * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toInteger(3.2); + * // => 3 + * + * _.toInteger(Number.MIN_VALUE); + * // => 0 + * + * _.toInteger(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toInteger('3.2'); + * // => 3 + */ +function toInteger(value) { + var result = toFinite(value), + remainder = result % 1; + + return result === result ? (remainder ? result - remainder : result) : 0; +} + +/** + * Converts `value` to a number. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to process. + * @returns {number} Returns the number. + * @example + * + * _.toNumber(3.2); + * // => 3.2 + * + * _.toNumber(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toNumber(Infinity); + * // => Infinity + * + * _.toNumber('3.2'); + * // => 3.2 + */ +function toNumber(value) { + if (typeof value == 'number') { + return value; + } + if (isSymbol(value)) { + return NAN; + } + if (isObject(value)) { + var other = typeof value.valueOf == 'function' ? value.valueOf() : value; + value = isObject(other) ? (other + '') : other; + } + if (typeof value != 'string') { + return value === 0 ? value : +value; + } + value = value.replace(reTrim, ''); + var isBinary = reIsBinary.test(value); + return (isBinary || reIsOctal.test(value)) + ? freeParseInt(value.slice(2), isBinary ? 2 : 8) + : (reIsBadHex.test(value) ? NAN : +value); +} + +module.exports = isInteger; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isinteger/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isinteger/package.json new file mode 100644 index 0000000..82afd4a --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isinteger/package.json @@ -0,0 +1,69 @@ +{ + "_from": "lodash.isinteger@^4.0.4", + "_id": "lodash.isinteger@4.0.4", + "_inBundle": false, + "_integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "_location": "/lodash.isinteger", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "lodash.isinteger@^4.0.4", + "name": "lodash.isinteger", + "escapedName": "lodash.isinteger", + "rawSpec": "^4.0.4", + "saveSpec": null, + "fetchSpec": "^4.0.4" + }, + "_requiredBy": [ + "/jsonwebtoken" + ], + "_resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "_shasum": "619c0af3d03f8b04c31f5882840b77b11cd68343", + "_spec": "lodash.isinteger@^4.0.4", + "_where": "D:\\xm\\online-code\\hellounicloud\\uni_modules\\uni-id-pages\\uniCloud\\cloudfunctions\\uni-id-co\\node_modules\\jsonwebtoken", + "author": { + "name": "John-David Dalton", + "email": "john.david.dalton@gmail.com", + "url": "http://allyoucanleet.com/" + }, + "bugs": { + "url": "https://github.com/lodash/lodash/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "John-David Dalton", + "email": "john.david.dalton@gmail.com", + "url": "http://allyoucanleet.com/" + }, + { + "name": "Blaine Bublitz", + "email": "blaine.bublitz@gmail.com", + "url": "https://github.com/phated" + }, + { + "name": "Mathias Bynens", + "email": "mathias@qiwi.be", + "url": "https://mathiasbynens.be/" + } + ], + "deprecated": false, + "description": "The lodash method `_.isInteger` exported as a module.", + "homepage": "https://lodash.com/", + "icon": "https://lodash.com/icon.svg", + "keywords": [ + "lodash-modularized", + "isinteger" + ], + "license": "MIT", + "name": "lodash.isinteger", + "repository": { + "type": "git", + "url": "git+https://github.com/lodash/lodash.git" + }, + "scripts": { + "test": "echo \"See https://travis-ci.org/lodash/lodash-cli for testing details.\"" + }, + "version": "4.0.4" +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isnumber/LICENSE b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isnumber/LICENSE new file mode 100644 index 0000000..b054ca5 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isnumber/LICENSE @@ -0,0 +1,22 @@ +Copyright 2012-2016 The Dojo Foundation +Based on Underscore.js, copyright 2009-2016 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isnumber/README.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isnumber/README.md new file mode 100644 index 0000000..a1d434d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isnumber/README.md @@ -0,0 +1,18 @@ +# lodash.isnumber v3.0.3 + +The [lodash](https://lodash.com/) method `_.isNumber` exported as a [Node.js](https://nodejs.org/) module. + +## Installation + +Using npm: +```bash +$ {sudo -H} npm i -g npm +$ npm i --save lodash.isnumber +``` + +In Node.js: +```js +var isNumber = require('lodash.isnumber'); +``` + +See the [documentation](https://lodash.com/docs#isNumber) or [package source](https://github.com/lodash/lodash/blob/3.0.3-npm-packages/lodash.isnumber) for more details. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isnumber/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isnumber/index.js new file mode 100644 index 0000000..35a8573 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isnumber/index.js @@ -0,0 +1,79 @@ +/** + * lodash 3.0.3 (Custom Build) + * Build: `lodash modularize exports="npm" -o ./` + * Copyright 2012-2016 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** `Object#toString` result references. */ +var numberTag = '[object Number]'; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) + * of values. + */ +var objectToString = objectProto.toString; + +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { + return !!value && typeof value == 'object'; +} + +/** + * Checks if `value` is classified as a `Number` primitive or object. + * + * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are classified + * as numbers, use the `_.isFinite` method. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isNumber(3); + * // => true + * + * _.isNumber(Number.MIN_VALUE); + * // => true + * + * _.isNumber(Infinity); + * // => true + * + * _.isNumber('3'); + * // => false + */ +function isNumber(value) { + return typeof value == 'number' || + (isObjectLike(value) && objectToString.call(value) == numberTag); +} + +module.exports = isNumber; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isnumber/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isnumber/package.json new file mode 100644 index 0000000..6fbd85f --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isnumber/package.json @@ -0,0 +1,69 @@ +{ + "_from": "lodash.isnumber@^3.0.3", + "_id": "lodash.isnumber@3.0.3", + "_inBundle": false, + "_integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "_location": "/lodash.isnumber", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "lodash.isnumber@^3.0.3", + "name": "lodash.isnumber", + "escapedName": "lodash.isnumber", + "rawSpec": "^3.0.3", + "saveSpec": null, + "fetchSpec": "^3.0.3" + }, + "_requiredBy": [ + "/jsonwebtoken" + ], + "_resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "_shasum": "3ce76810c5928d03352301ac287317f11c0b1ffc", + "_spec": "lodash.isnumber@^3.0.3", + "_where": "D:\\xm\\online-code\\hellounicloud\\uni_modules\\uni-id-pages\\uniCloud\\cloudfunctions\\uni-id-co\\node_modules\\jsonwebtoken", + "author": { + "name": "John-David Dalton", + "email": "john.david.dalton@gmail.com", + "url": "http://allyoucanleet.com/" + }, + "bugs": { + "url": "https://github.com/lodash/lodash/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "John-David Dalton", + "email": "john.david.dalton@gmail.com", + "url": "http://allyoucanleet.com/" + }, + { + "name": "Blaine Bublitz", + "email": "blaine@iceddev.com", + "url": "https://github.com/phated" + }, + { + "name": "Mathias Bynens", + "email": "mathias@qiwi.be", + "url": "https://mathiasbynens.be/" + } + ], + "deprecated": false, + "description": "The lodash method `_.isNumber` exported as a module.", + "homepage": "https://lodash.com/", + "icon": "https://lodash.com/icon.svg", + "keywords": [ + "lodash-modularized", + "isnumber" + ], + "license": "MIT", + "name": "lodash.isnumber", + "repository": { + "type": "git", + "url": "git+https://github.com/lodash/lodash.git" + }, + "scripts": { + "test": "echo \"See https://travis-ci.org/lodash/lodash-cli for testing details.\"" + }, + "version": "3.0.3" +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isplainobject/LICENSE b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isplainobject/LICENSE new file mode 100644 index 0000000..e0c69d5 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isplainobject/LICENSE @@ -0,0 +1,47 @@ +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isplainobject/README.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isplainobject/README.md new file mode 100644 index 0000000..aeefd74 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isplainobject/README.md @@ -0,0 +1,18 @@ +# lodash.isplainobject v4.0.6 + +The [lodash](https://lodash.com/) method `_.isPlainObject` exported as a [Node.js](https://nodejs.org/) module. + +## Installation + +Using npm: +```bash +$ {sudo -H} npm i -g npm +$ npm i --save lodash.isplainobject +``` + +In Node.js: +```js +var isPlainObject = require('lodash.isplainobject'); +``` + +See the [documentation](https://lodash.com/docs#isPlainObject) or [package source](https://github.com/lodash/lodash/blob/4.0.6-npm-packages/lodash.isplainobject) for more details. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isplainobject/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isplainobject/index.js new file mode 100644 index 0000000..0f820ee --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isplainobject/index.js @@ -0,0 +1,139 @@ +/** + * lodash (Custom Build) + * Build: `lodash modularize exports="npm" -o ./` + * Copyright jQuery Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */ + +/** `Object#toString` result references. */ +var objectTag = '[object Object]'; + +/** + * Checks if `value` is a host object in IE < 9. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a host object, else `false`. + */ +function isHostObject(value) { + // Many host objects are `Object` objects that can coerce to strings + // despite having improperly defined `toString` methods. + var result = false; + if (value != null && typeof value.toString != 'function') { + try { + result = !!(value + ''); + } catch (e) {} + } + return result; +} + +/** + * Creates a unary function that invokes `func` with its argument transformed. + * + * @private + * @param {Function} func The function to wrap. + * @param {Function} transform The argument transform. + * @returns {Function} Returns the new function. + */ +function overArg(func, transform) { + return function(arg) { + return func(transform(arg)); + }; +} + +/** Used for built-in method references. */ +var funcProto = Function.prototype, + objectProto = Object.prototype; + +/** Used to resolve the decompiled source of functions. */ +var funcToString = funcProto.toString; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** Used to infer the `Object` constructor. */ +var objectCtorString = funcToString.call(Object); + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var objectToString = objectProto.toString; + +/** Built-in value references. */ +var getPrototype = overArg(Object.getPrototypeOf, Object); + +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { + return !!value && typeof value == 'object'; +} + +/** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * @static + * @memberOf _ + * @since 0.8.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ +function isPlainObject(value) { + if (!isObjectLike(value) || + objectToString.call(value) != objectTag || isHostObject(value)) { + return false; + } + var proto = getPrototype(value); + if (proto === null) { + return true; + } + var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; + return (typeof Ctor == 'function' && + Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString); +} + +module.exports = isPlainObject; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isplainobject/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isplainobject/package.json new file mode 100644 index 0000000..71f8c91 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isplainobject/package.json @@ -0,0 +1,69 @@ +{ + "_from": "lodash.isplainobject@^4.0.6", + "_id": "lodash.isplainobject@4.0.6", + "_inBundle": false, + "_integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "_location": "/lodash.isplainobject", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "lodash.isplainobject@^4.0.6", + "name": "lodash.isplainobject", + "escapedName": "lodash.isplainobject", + "rawSpec": "^4.0.6", + "saveSpec": null, + "fetchSpec": "^4.0.6" + }, + "_requiredBy": [ + "/jsonwebtoken" + ], + "_resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "_shasum": "7c526a52d89b45c45cc690b88163be0497f550cb", + "_spec": "lodash.isplainobject@^4.0.6", + "_where": "D:\\xm\\online-code\\hellounicloud\\uni_modules\\uni-id-pages\\uniCloud\\cloudfunctions\\uni-id-co\\node_modules\\jsonwebtoken", + "author": { + "name": "John-David Dalton", + "email": "john.david.dalton@gmail.com", + "url": "http://allyoucanleet.com/" + }, + "bugs": { + "url": "https://github.com/lodash/lodash/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "John-David Dalton", + "email": "john.david.dalton@gmail.com", + "url": "http://allyoucanleet.com/" + }, + { + "name": "Blaine Bublitz", + "email": "blaine.bublitz@gmail.com", + "url": "https://github.com/phated" + }, + { + "name": "Mathias Bynens", + "email": "mathias@qiwi.be", + "url": "https://mathiasbynens.be/" + } + ], + "deprecated": false, + "description": "The lodash method `_.isPlainObject` exported as a module.", + "homepage": "https://lodash.com/", + "icon": "https://lodash.com/icon.svg", + "keywords": [ + "lodash-modularized", + "isplainobject" + ], + "license": "MIT", + "name": "lodash.isplainobject", + "repository": { + "type": "git", + "url": "git+https://github.com/lodash/lodash.git" + }, + "scripts": { + "test": "echo \"See https://travis-ci.org/lodash/lodash-cli for testing details.\"" + }, + "version": "4.0.6" +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isstring/LICENSE b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isstring/LICENSE new file mode 100644 index 0000000..b054ca5 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isstring/LICENSE @@ -0,0 +1,22 @@ +Copyright 2012-2016 The Dojo Foundation +Based on Underscore.js, copyright 2009-2016 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isstring/README.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isstring/README.md new file mode 100644 index 0000000..f184029 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isstring/README.md @@ -0,0 +1,18 @@ +# lodash.isstring v4.0.1 + +The [lodash](https://lodash.com/) method `_.isString` exported as a [Node.js](https://nodejs.org/) module. + +## Installation + +Using npm: +```bash +$ {sudo -H} npm i -g npm +$ npm i --save lodash.isstring +``` + +In Node.js: +```js +var isString = require('lodash.isstring'); +``` + +See the [documentation](https://lodash.com/docs#isString) or [package source](https://github.com/lodash/lodash/blob/4.0.1-npm-packages/lodash.isstring) for more details. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isstring/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isstring/index.js new file mode 100644 index 0000000..408225c --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isstring/index.js @@ -0,0 +1,95 @@ +/** + * lodash 4.0.1 (Custom Build) + * Build: `lodash modularize exports="npm" -o ./` + * Copyright 2012-2016 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** `Object#toString` result references. */ +var stringTag = '[object String]'; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) + * of values. + */ +var objectToString = objectProto.toString; + +/** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @type Function + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ +var isArray = Array.isArray; + +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { + return !!value && typeof value == 'object'; +} + +/** + * Checks if `value` is classified as a `String` primitive or object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false + */ +function isString(value) { + return typeof value == 'string' || + (!isArray(value) && isObjectLike(value) && objectToString.call(value) == stringTag); +} + +module.exports = isString; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isstring/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isstring/package.json new file mode 100644 index 0000000..be5a631 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.isstring/package.json @@ -0,0 +1,69 @@ +{ + "_from": "lodash.isstring@^4.0.1", + "_id": "lodash.isstring@4.0.1", + "_inBundle": false, + "_integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "_location": "/lodash.isstring", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "lodash.isstring@^4.0.1", + "name": "lodash.isstring", + "escapedName": "lodash.isstring", + "rawSpec": "^4.0.1", + "saveSpec": null, + "fetchSpec": "^4.0.1" + }, + "_requiredBy": [ + "/jsonwebtoken" + ], + "_resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "_shasum": "d527dfb5456eca7cc9bb95d5daeaf88ba54a5451", + "_spec": "lodash.isstring@^4.0.1", + "_where": "D:\\xm\\online-code\\hellounicloud\\uni_modules\\uni-id-pages\\uniCloud\\cloudfunctions\\uni-id-co\\node_modules\\jsonwebtoken", + "author": { + "name": "John-David Dalton", + "email": "john.david.dalton@gmail.com", + "url": "http://allyoucanleet.com/" + }, + "bugs": { + "url": "https://github.com/lodash/lodash/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "John-David Dalton", + "email": "john.david.dalton@gmail.com", + "url": "http://allyoucanleet.com/" + }, + { + "name": "Blaine Bublitz", + "email": "blaine@iceddev.com", + "url": "https://github.com/phated" + }, + { + "name": "Mathias Bynens", + "email": "mathias@qiwi.be", + "url": "https://mathiasbynens.be/" + } + ], + "deprecated": false, + "description": "The lodash method `_.isString` exported as a module.", + "homepage": "https://lodash.com/", + "icon": "https://lodash.com/icon.svg", + "keywords": [ + "lodash-modularized", + "isstring" + ], + "license": "MIT", + "name": "lodash.isstring", + "repository": { + "type": "git", + "url": "git+https://github.com/lodash/lodash.git" + }, + "scripts": { + "test": "echo \"See https://travis-ci.org/lodash/lodash-cli for testing details.\"" + }, + "version": "4.0.1" +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.merge/LICENSE b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.merge/LICENSE new file mode 100644 index 0000000..77c42f1 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.merge/LICENSE @@ -0,0 +1,47 @@ +Copyright OpenJS Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.merge/README.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.merge/README.md new file mode 100644 index 0000000..91b7538 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.merge/README.md @@ -0,0 +1,18 @@ +# lodash.merge v4.6.2 + +The [Lodash](https://lodash.com/) method `_.merge` exported as a [Node.js](https://nodejs.org/) module. + +## Installation + +Using npm: +```bash +$ {sudo -H} npm i -g npm +$ npm i --save lodash.merge +``` + +In Node.js: +```js +var merge = require('lodash.merge'); +``` + +See the [documentation](https://lodash.com/docs#merge) or [package source](https://github.com/lodash/lodash/blob/4.6.2-npm-packages/lodash.merge) for more details. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.merge/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.merge/index.js new file mode 100644 index 0000000..8e75d95 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.merge/index.js @@ -0,0 +1,1977 @@ +/** + * Lodash (Custom Build) + * Build: `lodash modularize exports="npm" -o ./` + * Copyright OpenJS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */ + +/** Used as the size to enable large array optimizations. */ +var LARGE_ARRAY_SIZE = 200; + +/** Used to stand-in for `undefined` hash values. */ +var HASH_UNDEFINED = '__lodash_hash_undefined__'; + +/** Used to detect hot functions by number of calls within a span of milliseconds. */ +var HOT_COUNT = 800, + HOT_SPAN = 16; + +/** Used as references for various `Number` constants. */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** `Object#toString` result references. */ +var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + asyncTag = '[object AsyncFunction]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + errorTag = '[object Error]', + funcTag = '[object Function]', + genTag = '[object GeneratorFunction]', + mapTag = '[object Map]', + numberTag = '[object Number]', + nullTag = '[object Null]', + objectTag = '[object Object]', + proxyTag = '[object Proxy]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + undefinedTag = '[object Undefined]', + weakMapTag = '[object WeakMap]'; + +var arrayBufferTag = '[object ArrayBuffer]', + dataViewTag = '[object DataView]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + +/** + * Used to match `RegExp` + * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). + */ +var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; + +/** Used to detect host constructors (Safari). */ +var reIsHostCtor = /^\[object .+?Constructor\]$/; + +/** Used to detect unsigned integer values. */ +var reIsUint = /^(?:0|[1-9]\d*)$/; + +/** Used to identify `toStringTag` values of typed arrays. */ +var typedArrayTags = {}; +typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = +typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = +typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = +typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = +typedArrayTags[uint32Tag] = true; +typedArrayTags[argsTag] = typedArrayTags[arrayTag] = +typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = +typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = +typedArrayTags[errorTag] = typedArrayTags[funcTag] = +typedArrayTags[mapTag] = typedArrayTags[numberTag] = +typedArrayTags[objectTag] = typedArrayTags[regexpTag] = +typedArrayTags[setTag] = typedArrayTags[stringTag] = +typedArrayTags[weakMapTag] = false; + +/** Detect free variable `global` from Node.js. */ +var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; + +/** Detect free variable `self`. */ +var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + +/** Used as a reference to the global object. */ +var root = freeGlobal || freeSelf || Function('return this')(); + +/** Detect free variable `exports`. */ +var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + +/** Detect free variable `module`. */ +var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + +/** Detect the popular CommonJS extension `module.exports`. */ +var moduleExports = freeModule && freeModule.exports === freeExports; + +/** Detect free variable `process` from Node.js. */ +var freeProcess = moduleExports && freeGlobal.process; + +/** Used to access faster Node.js helpers. */ +var nodeUtil = (function() { + try { + // Use `util.types` for Node.js 10+. + var types = freeModule && freeModule.require && freeModule.require('util').types; + + if (types) { + return types; + } + + // Legacy `process.binding('util')` for Node.js < 10. + return freeProcess && freeProcess.binding && freeProcess.binding('util'); + } catch (e) {} +}()); + +/* Node.js helper references. */ +var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; + +/** + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. + * + * @private + * @param {Function} func The function to invoke. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} args The arguments to invoke `func` with. + * @returns {*} Returns the result of `func`. + */ +function apply(func, thisArg, args) { + switch (args.length) { + case 0: return func.call(thisArg); + case 1: return func.call(thisArg, args[0]); + case 2: return func.call(thisArg, args[0], args[1]); + case 3: return func.call(thisArg, args[0], args[1], args[2]); + } + return func.apply(thisArg, args); +} + +/** + * The base implementation of `_.times` without support for iteratee shorthands + * or max array length checks. + * + * @private + * @param {number} n The number of times to invoke `iteratee`. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the array of results. + */ +function baseTimes(n, iteratee) { + var index = -1, + result = Array(n); + + while (++index < n) { + result[index] = iteratee(index); + } + return result; +} + +/** + * The base implementation of `_.unary` without support for storing metadata. + * + * @private + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. + */ +function baseUnary(func) { + return function(value) { + return func(value); + }; +} + +/** + * Gets the value at `key` of `object`. + * + * @private + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ +function getValue(object, key) { + return object == null ? undefined : object[key]; +} + +/** + * Creates a unary function that invokes `func` with its argument transformed. + * + * @private + * @param {Function} func The function to wrap. + * @param {Function} transform The argument transform. + * @returns {Function} Returns the new function. + */ +function overArg(func, transform) { + return function(arg) { + return func(transform(arg)); + }; +} + +/** Used for built-in method references. */ +var arrayProto = Array.prototype, + funcProto = Function.prototype, + objectProto = Object.prototype; + +/** Used to detect overreaching core-js shims. */ +var coreJsData = root['__core-js_shared__']; + +/** Used to resolve the decompiled source of functions. */ +var funcToString = funcProto.toString; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** Used to detect methods masquerading as native. */ +var maskSrcKey = (function() { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; +}()); + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString = objectProto.toString; + +/** Used to infer the `Object` constructor. */ +var objectCtorString = funcToString.call(Object); + +/** Used to detect if a method is native. */ +var reIsNative = RegExp('^' + + funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' +); + +/** Built-in value references. */ +var Buffer = moduleExports ? root.Buffer : undefined, + Symbol = root.Symbol, + Uint8Array = root.Uint8Array, + allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined, + getPrototype = overArg(Object.getPrototypeOf, Object), + objectCreate = Object.create, + propertyIsEnumerable = objectProto.propertyIsEnumerable, + splice = arrayProto.splice, + symToStringTag = Symbol ? Symbol.toStringTag : undefined; + +var defineProperty = (function() { + try { + var func = getNative(Object, 'defineProperty'); + func({}, '', {}); + return func; + } catch (e) {} +}()); + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined, + nativeMax = Math.max, + nativeNow = Date.now; + +/* Built-in method references that are verified to be native. */ +var Map = getNative(root, 'Map'), + nativeCreate = getNative(Object, 'create'); + +/** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} proto The object to inherit from. + * @returns {Object} Returns the new object. + */ +var baseCreate = (function() { + function object() {} + return function(proto) { + if (!isObject(proto)) { + return {}; + } + if (objectCreate) { + return objectCreate(proto); + } + object.prototype = proto; + var result = new object; + object.prototype = undefined; + return result; + }; +}()); + +/** + * Creates a hash object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function Hash(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} + +/** + * Removes all key-value entries from the hash. + * + * @private + * @name clear + * @memberOf Hash + */ +function hashClear() { + this.__data__ = nativeCreate ? nativeCreate(null) : {}; + this.size = 0; +} + +/** + * Removes `key` and its value from the hash. + * + * @private + * @name delete + * @memberOf Hash + * @param {Object} hash The hash to modify. + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function hashDelete(key) { + var result = this.has(key) && delete this.__data__[key]; + this.size -= result ? 1 : 0; + return result; +} + +/** + * Gets the hash value for `key`. + * + * @private + * @name get + * @memberOf Hash + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function hashGet(key) { + var data = this.__data__; + if (nativeCreate) { + var result = data[key]; + return result === HASH_UNDEFINED ? undefined : result; + } + return hasOwnProperty.call(data, key) ? data[key] : undefined; +} + +/** + * Checks if a hash value for `key` exists. + * + * @private + * @name has + * @memberOf Hash + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function hashHas(key) { + var data = this.__data__; + return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); +} + +/** + * Sets the hash `key` to `value`. + * + * @private + * @name set + * @memberOf Hash + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the hash instance. + */ +function hashSet(key, value) { + var data = this.__data__; + this.size += this.has(key) ? 0 : 1; + data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; + return this; +} + +// Add methods to `Hash`. +Hash.prototype.clear = hashClear; +Hash.prototype['delete'] = hashDelete; +Hash.prototype.get = hashGet; +Hash.prototype.has = hashHas; +Hash.prototype.set = hashSet; + +/** + * Creates an list cache object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function ListCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} + +/** + * Removes all key-value entries from the list cache. + * + * @private + * @name clear + * @memberOf ListCache + */ +function listCacheClear() { + this.__data__ = []; + this.size = 0; +} + +/** + * Removes `key` and its value from the list cache. + * + * @private + * @name delete + * @memberOf ListCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function listCacheDelete(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + return false; + } + var lastIndex = data.length - 1; + if (index == lastIndex) { + data.pop(); + } else { + splice.call(data, index, 1); + } + --this.size; + return true; +} + +/** + * Gets the list cache value for `key`. + * + * @private + * @name get + * @memberOf ListCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function listCacheGet(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + return index < 0 ? undefined : data[index][1]; +} + +/** + * Checks if a list cache value for `key` exists. + * + * @private + * @name has + * @memberOf ListCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function listCacheHas(key) { + return assocIndexOf(this.__data__, key) > -1; +} + +/** + * Sets the list cache `key` to `value`. + * + * @private + * @name set + * @memberOf ListCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the list cache instance. + */ +function listCacheSet(key, value) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + ++this.size; + data.push([key, value]); + } else { + data[index][1] = value; + } + return this; +} + +// Add methods to `ListCache`. +ListCache.prototype.clear = listCacheClear; +ListCache.prototype['delete'] = listCacheDelete; +ListCache.prototype.get = listCacheGet; +ListCache.prototype.has = listCacheHas; +ListCache.prototype.set = listCacheSet; + +/** + * Creates a map cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function MapCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} + +/** + * Removes all key-value entries from the map. + * + * @private + * @name clear + * @memberOf MapCache + */ +function mapCacheClear() { + this.size = 0; + this.__data__ = { + 'hash': new Hash, + 'map': new (Map || ListCache), + 'string': new Hash + }; +} + +/** + * Removes `key` and its value from the map. + * + * @private + * @name delete + * @memberOf MapCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function mapCacheDelete(key) { + var result = getMapData(this, key)['delete'](key); + this.size -= result ? 1 : 0; + return result; +} + +/** + * Gets the map value for `key`. + * + * @private + * @name get + * @memberOf MapCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function mapCacheGet(key) { + return getMapData(this, key).get(key); +} + +/** + * Checks if a map value for `key` exists. + * + * @private + * @name has + * @memberOf MapCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function mapCacheHas(key) { + return getMapData(this, key).has(key); +} + +/** + * Sets the map `key` to `value`. + * + * @private + * @name set + * @memberOf MapCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the map cache instance. + */ +function mapCacheSet(key, value) { + var data = getMapData(this, key), + size = data.size; + + data.set(key, value); + this.size += data.size == size ? 0 : 1; + return this; +} + +// Add methods to `MapCache`. +MapCache.prototype.clear = mapCacheClear; +MapCache.prototype['delete'] = mapCacheDelete; +MapCache.prototype.get = mapCacheGet; +MapCache.prototype.has = mapCacheHas; +MapCache.prototype.set = mapCacheSet; + +/** + * Creates a stack cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function Stack(entries) { + var data = this.__data__ = new ListCache(entries); + this.size = data.size; +} + +/** + * Removes all key-value entries from the stack. + * + * @private + * @name clear + * @memberOf Stack + */ +function stackClear() { + this.__data__ = new ListCache; + this.size = 0; +} + +/** + * Removes `key` and its value from the stack. + * + * @private + * @name delete + * @memberOf Stack + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function stackDelete(key) { + var data = this.__data__, + result = data['delete'](key); + + this.size = data.size; + return result; +} + +/** + * Gets the stack value for `key`. + * + * @private + * @name get + * @memberOf Stack + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function stackGet(key) { + return this.__data__.get(key); +} + +/** + * Checks if a stack value for `key` exists. + * + * @private + * @name has + * @memberOf Stack + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function stackHas(key) { + return this.__data__.has(key); +} + +/** + * Sets the stack `key` to `value`. + * + * @private + * @name set + * @memberOf Stack + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the stack cache instance. + */ +function stackSet(key, value) { + var data = this.__data__; + if (data instanceof ListCache) { + var pairs = data.__data__; + if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { + pairs.push([key, value]); + this.size = ++data.size; + return this; + } + data = this.__data__ = new MapCache(pairs); + } + data.set(key, value); + this.size = data.size; + return this; +} + +// Add methods to `Stack`. +Stack.prototype.clear = stackClear; +Stack.prototype['delete'] = stackDelete; +Stack.prototype.get = stackGet; +Stack.prototype.has = stackHas; +Stack.prototype.set = stackSet; + +/** + * Creates an array of the enumerable property names of the array-like `value`. + * + * @private + * @param {*} value The value to query. + * @param {boolean} inherited Specify returning inherited property names. + * @returns {Array} Returns the array of property names. + */ +function arrayLikeKeys(value, inherited) { + var isArr = isArray(value), + isArg = !isArr && isArguments(value), + isBuff = !isArr && !isArg && isBuffer(value), + isType = !isArr && !isArg && !isBuff && isTypedArray(value), + skipIndexes = isArr || isArg || isBuff || isType, + result = skipIndexes ? baseTimes(value.length, String) : [], + length = result.length; + + for (var key in value) { + if ((inherited || hasOwnProperty.call(value, key)) && + !(skipIndexes && ( + // Safari 9 has enumerable `arguments.length` in strict mode. + key == 'length' || + // Node.js 0.10 has enumerable non-index properties on buffers. + (isBuff && (key == 'offset' || key == 'parent')) || + // PhantomJS 2 has enumerable non-index properties on typed arrays. + (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || + // Skip index properties. + isIndex(key, length) + ))) { + result.push(key); + } + } + return result; +} + +/** + * This function is like `assignValue` except that it doesn't assign + * `undefined` values. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ +function assignMergeValue(object, key, value) { + if ((value !== undefined && !eq(object[key], value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } +} + +/** + * Assigns `value` to `key` of `object` if the existing value is not equivalent + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ +function assignValue(object, key, value) { + var objValue = object[key]; + if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } +} + +/** + * Gets the index at which the `key` is found in `array` of key-value pairs. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} key The key to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + */ +function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (eq(array[length][0], key)) { + return length; + } + } + return -1; +} + +/** + * The base implementation of `assignValue` and `assignMergeValue` without + * value checks. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ +function baseAssignValue(object, key, value) { + if (key == '__proto__' && defineProperty) { + defineProperty(object, key, { + 'configurable': true, + 'enumerable': true, + 'value': value, + 'writable': true + }); + } else { + object[key] = value; + } +} + +/** + * The base implementation of `baseForOwn` which iterates over `object` + * properties returned by `keysFunc` and invokes `iteratee` for each property. + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ +var baseFor = createBaseFor(); + +/** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ +function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (symToStringTag && symToStringTag in Object(value)) + ? getRawTag(value) + : objectToString(value); +} + +/** + * The base implementation of `_.isArguments`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + */ +function baseIsArguments(value) { + return isObjectLike(value) && baseGetTag(value) == argsTag; +} + +/** + * The base implementation of `_.isNative` without bad shim checks. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + */ +function baseIsNative(value) { + if (!isObject(value) || isMasked(value)) { + return false; + } + var pattern = isFunction(value) ? reIsNative : reIsHostCtor; + return pattern.test(toSource(value)); +} + +/** + * The base implementation of `_.isTypedArray` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + */ +function baseIsTypedArray(value) { + return isObjectLike(value) && + isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; +} + +/** + * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ +function baseKeysIn(object) { + if (!isObject(object)) { + return nativeKeysIn(object); + } + var isProto = isPrototype(object), + result = []; + + for (var key in object) { + if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { + result.push(key); + } + } + return result; +} + +/** + * The base implementation of `_.merge` without support for multiple sources. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {number} srcIndex The index of `source`. + * @param {Function} [customizer] The function to customize merged values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ +function baseMerge(object, source, srcIndex, customizer, stack) { + if (object === source) { + return; + } + baseFor(source, function(srcValue, key) { + stack || (stack = new Stack); + if (isObject(srcValue)) { + baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); + } + else { + var newValue = customizer + ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack) + : undefined; + + if (newValue === undefined) { + newValue = srcValue; + } + assignMergeValue(object, key, newValue); + } + }, keysIn); +} + +/** + * A specialized version of `baseMerge` for arrays and objects which performs + * deep merges and tracks traversed objects enabling objects with circular + * references to be merged. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {string} key The key of the value to merge. + * @param {number} srcIndex The index of `source`. + * @param {Function} mergeFunc The function to merge values. + * @param {Function} [customizer] The function to customize assigned values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ +function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { + var objValue = safeGet(object, key), + srcValue = safeGet(source, key), + stacked = stack.get(srcValue); + + if (stacked) { + assignMergeValue(object, key, stacked); + return; + } + var newValue = customizer + ? customizer(objValue, srcValue, (key + ''), object, source, stack) + : undefined; + + var isCommon = newValue === undefined; + + if (isCommon) { + var isArr = isArray(srcValue), + isBuff = !isArr && isBuffer(srcValue), + isTyped = !isArr && !isBuff && isTypedArray(srcValue); + + newValue = srcValue; + if (isArr || isBuff || isTyped) { + if (isArray(objValue)) { + newValue = objValue; + } + else if (isArrayLikeObject(objValue)) { + newValue = copyArray(objValue); + } + else if (isBuff) { + isCommon = false; + newValue = cloneBuffer(srcValue, true); + } + else if (isTyped) { + isCommon = false; + newValue = cloneTypedArray(srcValue, true); + } + else { + newValue = []; + } + } + else if (isPlainObject(srcValue) || isArguments(srcValue)) { + newValue = objValue; + if (isArguments(objValue)) { + newValue = toPlainObject(objValue); + } + else if (!isObject(objValue) || isFunction(objValue)) { + newValue = initCloneObject(srcValue); + } + } + else { + isCommon = false; + } + } + if (isCommon) { + // Recursively merge objects and arrays (susceptible to call stack limits). + stack.set(srcValue, newValue); + mergeFunc(newValue, srcValue, srcIndex, customizer, stack); + stack['delete'](srcValue); + } + assignMergeValue(object, key, newValue); +} + +/** + * The base implementation of `_.rest` which doesn't validate or coerce arguments. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + */ +function baseRest(func, start) { + return setToString(overRest(func, start, identity), func + ''); +} + +/** + * The base implementation of `setToString` without support for hot loop shorting. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ +var baseSetToString = !defineProperty ? identity : function(func, string) { + return defineProperty(func, 'toString', { + 'configurable': true, + 'enumerable': false, + 'value': constant(string), + 'writable': true + }); +}; + +/** + * Creates a clone of `buffer`. + * + * @private + * @param {Buffer} buffer The buffer to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Buffer} Returns the cloned buffer. + */ +function cloneBuffer(buffer, isDeep) { + if (isDeep) { + return buffer.slice(); + } + var length = buffer.length, + result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length); + + buffer.copy(result); + return result; +} + +/** + * Creates a clone of `arrayBuffer`. + * + * @private + * @param {ArrayBuffer} arrayBuffer The array buffer to clone. + * @returns {ArrayBuffer} Returns the cloned array buffer. + */ +function cloneArrayBuffer(arrayBuffer) { + var result = new arrayBuffer.constructor(arrayBuffer.byteLength); + new Uint8Array(result).set(new Uint8Array(arrayBuffer)); + return result; +} + +/** + * Creates a clone of `typedArray`. + * + * @private + * @param {Object} typedArray The typed array to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned typed array. + */ +function cloneTypedArray(typedArray, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; + return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); +} + +/** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ +function copyArray(source, array) { + var index = -1, + length = source.length; + + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; +} + +/** + * Copies properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Array} props The property identifiers to copy. + * @param {Object} [object={}] The object to copy properties to. + * @param {Function} [customizer] The function to customize copied values. + * @returns {Object} Returns `object`. + */ +function copyObject(source, props, object, customizer) { + var isNew = !object; + object || (object = {}); + + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + + var newValue = customizer + ? customizer(object[key], source[key], key, object, source) + : undefined; + + if (newValue === undefined) { + newValue = source[key]; + } + if (isNew) { + baseAssignValue(object, key, newValue); + } else { + assignValue(object, key, newValue); + } + } + return object; +} + +/** + * Creates a function like `_.assign`. + * + * @private + * @param {Function} assigner The function to assign values. + * @returns {Function} Returns the new assigner function. + */ +function createAssigner(assigner) { + return baseRest(function(object, sources) { + var index = -1, + length = sources.length, + customizer = length > 1 ? sources[length - 1] : undefined, + guard = length > 2 ? sources[2] : undefined; + + customizer = (assigner.length > 3 && typeof customizer == 'function') + ? (length--, customizer) + : undefined; + + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + customizer = length < 3 ? undefined : customizer; + length = 1; + } + object = Object(object); + while (++index < length) { + var source = sources[index]; + if (source) { + assigner(object, source, index, customizer); + } + } + return object; + }); +} + +/** + * Creates a base function for methods like `_.forIn` and `_.forOwn`. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ +function createBaseFor(fromRight) { + return function(object, iteratee, keysFunc) { + var index = -1, + iterable = Object(object), + props = keysFunc(object), + length = props.length; + + while (length--) { + var key = props[fromRight ? length : ++index]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; + }; +} + +/** + * Gets the data for `map`. + * + * @private + * @param {Object} map The map to query. + * @param {string} key The reference key. + * @returns {*} Returns the map data. + */ +function getMapData(map, key) { + var data = map.__data__; + return isKeyable(key) + ? data[typeof key == 'string' ? 'string' : 'hash'] + : data.map; +} + +/** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ +function getNative(object, key) { + var value = getValue(object, key); + return baseIsNative(value) ? value : undefined; +} + +/** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ +function getRawTag(value) { + var isOwn = hasOwnProperty.call(value, symToStringTag), + tag = value[symToStringTag]; + + try { + value[symToStringTag] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag] = tag; + } else { + delete value[symToStringTag]; + } + } + return result; +} + +/** + * Initializes an object clone. + * + * @private + * @param {Object} object The object to clone. + * @returns {Object} Returns the initialized clone. + */ +function initCloneObject(object) { + return (typeof object.constructor == 'function' && !isPrototype(object)) + ? baseCreate(getPrototype(object)) + : {}; +} + +/** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ +function isIndex(value, length) { + var type = typeof value; + length = length == null ? MAX_SAFE_INTEGER : length; + + return !!length && + (type == 'number' || + (type != 'symbol' && reIsUint.test(value))) && + (value > -1 && value % 1 == 0 && value < length); +} + +/** + * Checks if the given arguments are from an iteratee call. + * + * @private + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, + * else `false`. + */ +function isIterateeCall(value, index, object) { + if (!isObject(object)) { + return false; + } + var type = typeof index; + if (type == 'number' + ? (isArrayLike(object) && isIndex(index, object.length)) + : (type == 'string' && index in object) + ) { + return eq(object[index], value); + } + return false; +} + +/** + * Checks if `value` is suitable for use as unique object key. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is suitable, else `false`. + */ +function isKeyable(value) { + var type = typeof value; + return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') + ? (value !== '__proto__') + : (value === null); +} + +/** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ +function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); +} + +/** + * Checks if `value` is likely a prototype object. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. + */ +function isPrototype(value) { + var Ctor = value && value.constructor, + proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; + + return value === proto; +} + +/** + * This function is like + * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * except that it includes inherited enumerable properties. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ +function nativeKeysIn(object) { + var result = []; + if (object != null) { + for (var key in Object(object)) { + result.push(key); + } + } + return result; +} + +/** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ +function objectToString(value) { + return nativeObjectToString.call(value); +} + +/** + * A specialized version of `baseRest` which transforms the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @param {Function} transform The rest array transform. + * @returns {Function} Returns the new function. + */ +function overRest(func, start, transform) { + start = nativeMax(start === undefined ? (func.length - 1) : start, 0); + return function() { + var args = arguments, + index = -1, + length = nativeMax(args.length - start, 0), + array = Array(length); + + while (++index < length) { + array[index] = args[start + index]; + } + index = -1; + var otherArgs = Array(start + 1); + while (++index < start) { + otherArgs[index] = args[index]; + } + otherArgs[start] = transform(array); + return apply(func, this, otherArgs); + }; +} + +/** + * Gets the value at `key`, unless `key` is "__proto__" or "constructor". + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ +function safeGet(object, key) { + if (key === 'constructor' && typeof object[key] === 'function') { + return; + } + + if (key == '__proto__') { + return; + } + + return object[key]; +} + +/** + * Sets the `toString` method of `func` to return `string`. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ +var setToString = shortOut(baseSetToString); + +/** + * Creates a function that'll short out and invoke `identity` instead + * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` + * milliseconds. + * + * @private + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new shortable function. + */ +function shortOut(func) { + var count = 0, + lastCalled = 0; + + return function() { + var stamp = nativeNow(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return arguments[0]; + } + } else { + count = 0; + } + return func.apply(undefined, arguments); + }; +} + +/** + * Converts `func` to its source code. + * + * @private + * @param {Function} func The function to convert. + * @returns {string} Returns the source code. + */ +function toSource(func) { + if (func != null) { + try { + return funcToString.call(func); + } catch (e) {} + try { + return (func + ''); + } catch (e) {} + } + return ''; +} + +/** + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true + */ +function eq(value, other) { + return value === other || (value !== value && other !== other); +} + +/** + * Checks if `value` is likely an `arguments` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ +var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { + return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && + !propertyIsEnumerable.call(value, 'callee'); +}; + +/** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ +var isArray = Array.isArray; + +/** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(document.body.children); + * // => true + * + * _.isArrayLike('abc'); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ +function isArrayLike(value) { + return value != null && isLength(value.length) && !isFunction(value); +} + +/** + * This method is like `_.isArrayLike` except that it also checks if `value` + * is an object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array-like object, + * else `false`. + * @example + * + * _.isArrayLikeObject([1, 2, 3]); + * // => true + * + * _.isArrayLikeObject(document.body.children); + * // => true + * + * _.isArrayLikeObject('abc'); + * // => false + * + * _.isArrayLikeObject(_.noop); + * // => false + */ +function isArrayLikeObject(value) { + return isObjectLike(value) && isArrayLike(value); +} + +/** + * Checks if `value` is a buffer. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. + * @example + * + * _.isBuffer(new Buffer(2)); + * // => true + * + * _.isBuffer(new Uint8Array(2)); + * // => false + */ +var isBuffer = nativeIsBuffer || stubFalse; + +/** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ +function isFunction(value) { + if (!isObject(value)) { + return false; + } + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 9 which returns 'object' for typed arrays and other constructors. + var tag = baseGetTag(value); + return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; +} + +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This method is loosely based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @example + * + * _.isLength(3); + * // => true + * + * _.isLength(Number.MIN_VALUE); + * // => false + * + * _.isLength(Infinity); + * // => false + * + * _.isLength('3'); + * // => false + */ +function isLength(value) { + return typeof value == 'number' && + value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} + +/** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ +function isObject(value) { + var type = typeof value; + return value != null && (type == 'object' || type == 'function'); +} + +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { + return value != null && typeof value == 'object'; +} + +/** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * @static + * @memberOf _ + * @since 0.8.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ +function isPlainObject(value) { + if (!isObjectLike(value) || baseGetTag(value) != objectTag) { + return false; + } + var proto = getPrototype(value); + if (proto === null) { + return true; + } + var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; + return typeof Ctor == 'function' && Ctor instanceof Ctor && + funcToString.call(Ctor) == objectCtorString; +} + +/** + * Checks if `value` is classified as a typed array. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + * @example + * + * _.isTypedArray(new Uint8Array); + * // => true + * + * _.isTypedArray([]); + * // => false + */ +var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; + +/** + * Converts `value` to a plain object flattening inherited enumerable string + * keyed properties of `value` to own properties of the plain object. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {Object} Returns the converted plain object. + * @example + * + * function Foo() { + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.assign({ 'a': 1 }, new Foo); + * // => { 'a': 1, 'b': 2 } + * + * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); + * // => { 'a': 1, 'b': 2, 'c': 3 } + */ +function toPlainObject(value) { + return copyObject(value, keysIn(value)); +} + +/** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ +function keysIn(object) { + return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); +} + +/** + * This method is like `_.assign` except that it recursively merges own and + * inherited enumerable string keyed properties of source objects into the + * destination object. Source properties that resolve to `undefined` are + * skipped if a destination value exists. Array and plain object properties + * are merged recursively. Other objects and value types are overridden by + * assignment. Source objects are applied from left to right. Subsequent + * sources overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * var object = { + * 'a': [{ 'b': 2 }, { 'd': 4 }] + * }; + * + * var other = { + * 'a': [{ 'c': 3 }, { 'e': 5 }] + * }; + * + * _.merge(object, other); + * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } + */ +var merge = createAssigner(function(object, source, srcIndex) { + baseMerge(object, source, srcIndex); +}); + +/** + * Creates a function that returns `value`. + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Util + * @param {*} value The value to return from the new function. + * @returns {Function} Returns the new constant function. + * @example + * + * var objects = _.times(2, _.constant({ 'a': 1 })); + * + * console.log(objects); + * // => [{ 'a': 1 }, { 'a': 1 }] + * + * console.log(objects[0] === objects[1]); + * // => true + */ +function constant(value) { + return function() { + return value; + }; +} + +/** + * This method returns the first argument it receives. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Util + * @param {*} value Any value. + * @returns {*} Returns `value`. + * @example + * + * var object = { 'a': 1 }; + * + * console.log(_.identity(object) === object); + * // => true + */ +function identity(value) { + return value; +} + +/** + * This method returns `false`. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {boolean} Returns `false`. + * @example + * + * _.times(2, _.stubFalse); + * // => [false, false] + */ +function stubFalse() { + return false; +} + +module.exports = merge; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.merge/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.merge/package.json new file mode 100644 index 0000000..e4be1d8 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.merge/package.json @@ -0,0 +1,61 @@ +{ + "_from": "lodash.merge@^4.6.2", + "_id": "lodash.merge@4.6.2", + "_inBundle": false, + "_integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "_location": "/lodash.merge", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "lodash.merge@^4.6.2", + "name": "lodash.merge", + "escapedName": "lodash.merge", + "rawSpec": "^4.6.2", + "saveSpec": null, + "fetchSpec": "^4.6.2" + }, + "_requiredBy": [ + "/" + ], + "_resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "_shasum": "558aa53b43b661e1925a0afdfa36a9a1085fe57a", + "_spec": "lodash.merge@^4.6.2", + "_where": "D:\\xm\\online-code\\hellounicloud\\uni_modules\\uni-id-pages\\uniCloud\\cloudfunctions\\uni-id-co", + "author": { + "name": "John-David Dalton", + "email": "john.david.dalton@gmail.com" + }, + "bugs": { + "url": "https://github.com/lodash/lodash/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "John-David Dalton", + "email": "john.david.dalton@gmail.com" + }, + { + "name": "Mathias Bynens", + "email": "mathias@qiwi.be" + } + ], + "deprecated": false, + "description": "The Lodash method `_.merge` exported as a module.", + "homepage": "https://lodash.com/", + "icon": "https://lodash.com/icon.svg", + "keywords": [ + "lodash-modularized", + "merge" + ], + "license": "MIT", + "name": "lodash.merge", + "repository": { + "type": "git", + "url": "git+https://github.com/lodash/lodash.git" + }, + "scripts": { + "test": "echo \"See https://travis-ci.org/lodash/lodash-cli for testing details.\"" + }, + "version": "4.6.2" +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.once/LICENSE b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.once/LICENSE new file mode 100644 index 0000000..e0c69d5 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.once/LICENSE @@ -0,0 +1,47 @@ +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.once/README.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.once/README.md new file mode 100644 index 0000000..c4a2f16 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.once/README.md @@ -0,0 +1,18 @@ +# lodash.once v4.1.1 + +The [lodash](https://lodash.com/) method `_.once` exported as a [Node.js](https://nodejs.org/) module. + +## Installation + +Using npm: +```bash +$ {sudo -H} npm i -g npm +$ npm i --save lodash.once +``` + +In Node.js: +```js +var once = require('lodash.once'); +``` + +See the [documentation](https://lodash.com/docs#once) or [package source](https://github.com/lodash/lodash/blob/4.1.1-npm-packages/lodash.once) for more details. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.once/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.once/index.js new file mode 100644 index 0000000..414ceb3 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.once/index.js @@ -0,0 +1,294 @@ +/** + * lodash (Custom Build) + * Build: `lodash modularize exports="npm" -o ./` + * Copyright jQuery Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */ + +/** Used as the `TypeError` message for "Functions" methods. */ +var FUNC_ERROR_TEXT = 'Expected a function'; + +/** Used as references for various `Number` constants. */ +var INFINITY = 1 / 0, + MAX_INTEGER = 1.7976931348623157e+308, + NAN = 0 / 0; + +/** `Object#toString` result references. */ +var symbolTag = '[object Symbol]'; + +/** Used to match leading and trailing whitespace. */ +var reTrim = /^\s+|\s+$/g; + +/** Used to detect bad signed hexadecimal string values. */ +var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; + +/** Used to detect binary string values. */ +var reIsBinary = /^0b[01]+$/i; + +/** Used to detect octal string values. */ +var reIsOctal = /^0o[0-7]+$/i; + +/** Built-in method references without a dependency on `root`. */ +var freeParseInt = parseInt; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var objectToString = objectProto.toString; + +/** + * Creates a function that invokes `func`, with the `this` binding and arguments + * of the created function, while it's called less than `n` times. Subsequent + * calls to the created function return the result of the last `func` invocation. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {number} n The number of calls at which `func` is no longer invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * jQuery(element).on('click', _.before(5, addContactToList)); + * // => Allows adding up to 4 contacts to the list. + */ +function before(n, func) { + var result; + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + n = toInteger(n); + return function() { + if (--n > 0) { + result = func.apply(this, arguments); + } + if (n <= 1) { + func = undefined; + } + return result; + }; +} + +/** + * Creates a function that is restricted to invoking `func` once. Repeat calls + * to the function return the value of the first invocation. The `func` is + * invoked with the `this` binding and arguments of the created function. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var initialize = _.once(createApplication); + * initialize(); + * initialize(); + * // => `createApplication` is invoked once + */ +function once(func) { + return before(2, func); +} + +/** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ +function isObject(value) { + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); +} + +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { + return !!value && typeof value == 'object'; +} + +/** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ +function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && objectToString.call(value) == symbolTag); +} + +/** + * Converts `value` to a finite number. + * + * @static + * @memberOf _ + * @since 4.12.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted number. + * @example + * + * _.toFinite(3.2); + * // => 3.2 + * + * _.toFinite(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toFinite(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toFinite('3.2'); + * // => 3.2 + */ +function toFinite(value) { + if (!value) { + return value === 0 ? value : 0; + } + value = toNumber(value); + if (value === INFINITY || value === -INFINITY) { + var sign = (value < 0 ? -1 : 1); + return sign * MAX_INTEGER; + } + return value === value ? value : 0; +} + +/** + * Converts `value` to an integer. + * + * **Note:** This method is loosely based on + * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toInteger(3.2); + * // => 3 + * + * _.toInteger(Number.MIN_VALUE); + * // => 0 + * + * _.toInteger(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toInteger('3.2'); + * // => 3 + */ +function toInteger(value) { + var result = toFinite(value), + remainder = result % 1; + + return result === result ? (remainder ? result - remainder : result) : 0; +} + +/** + * Converts `value` to a number. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to process. + * @returns {number} Returns the number. + * @example + * + * _.toNumber(3.2); + * // => 3.2 + * + * _.toNumber(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toNumber(Infinity); + * // => Infinity + * + * _.toNumber('3.2'); + * // => 3.2 + */ +function toNumber(value) { + if (typeof value == 'number') { + return value; + } + if (isSymbol(value)) { + return NAN; + } + if (isObject(value)) { + var other = typeof value.valueOf == 'function' ? value.valueOf() : value; + value = isObject(other) ? (other + '') : other; + } + if (typeof value != 'string') { + return value === 0 ? value : +value; + } + value = value.replace(reTrim, ''); + var isBinary = reIsBinary.test(value); + return (isBinary || reIsOctal.test(value)) + ? freeParseInt(value.slice(2), isBinary ? 2 : 8) + : (reIsBadHex.test(value) ? NAN : +value); +} + +module.exports = once; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.once/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.once/package.json new file mode 100644 index 0000000..7d95724 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/lodash.once/package.json @@ -0,0 +1,69 @@ +{ + "_from": "lodash.once@^4.0.0", + "_id": "lodash.once@4.1.1", + "_inBundle": false, + "_integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "_location": "/lodash.once", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "lodash.once@^4.0.0", + "name": "lodash.once", + "escapedName": "lodash.once", + "rawSpec": "^4.0.0", + "saveSpec": null, + "fetchSpec": "^4.0.0" + }, + "_requiredBy": [ + "/jsonwebtoken" + ], + "_resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "_shasum": "0dd3971213c7c56df880977d504c88fb471a97ac", + "_spec": "lodash.once@^4.0.0", + "_where": "D:\\xm\\online-code\\hellounicloud\\uni_modules\\uni-id-pages\\uniCloud\\cloudfunctions\\uni-id-co\\node_modules\\jsonwebtoken", + "author": { + "name": "John-David Dalton", + "email": "john.david.dalton@gmail.com", + "url": "http://allyoucanleet.com/" + }, + "bugs": { + "url": "https://github.com/lodash/lodash/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "John-David Dalton", + "email": "john.david.dalton@gmail.com", + "url": "http://allyoucanleet.com/" + }, + { + "name": "Blaine Bublitz", + "email": "blaine.bublitz@gmail.com", + "url": "https://github.com/phated" + }, + { + "name": "Mathias Bynens", + "email": "mathias@qiwi.be", + "url": "https://mathiasbynens.be/" + } + ], + "deprecated": false, + "description": "The lodash method `_.once` exported as a module.", + "homepage": "https://lodash.com/", + "icon": "https://lodash.com/icon.svg", + "keywords": [ + "lodash-modularized", + "once" + ], + "license": "MIT", + "name": "lodash.once", + "repository": { + "type": "git", + "url": "git+https://github.com/lodash/lodash.git" + }, + "scripts": { + "test": "echo \"See https://travis-ci.org/lodash/lodash-cli for testing details.\"" + }, + "version": "4.1.1" +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ms/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ms/index.js new file mode 100644 index 0000000..ea734fb --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ms/index.js @@ -0,0 +1,162 @@ +/** + * Helpers. + */ + +var s = 1000; +var m = s * 60; +var h = m * 60; +var d = h * 24; +var w = d * 7; +var y = d * 365.25; + +/** + * Parse or format the given `val`. + * + * Options: + * + * - `long` verbose formatting [false] + * + * @param {String|Number} val + * @param {Object} [options] + * @throws {Error} throw an error if val is not a non-empty string or a number + * @return {String|Number} + * @api public + */ + +module.exports = function (val, options) { + options = options || {}; + var type = typeof val; + if (type === 'string' && val.length > 0) { + return parse(val); + } else if (type === 'number' && isFinite(val)) { + return options.long ? fmtLong(val) : fmtShort(val); + } + throw new Error( + 'val is not a non-empty string or a valid number. val=' + + JSON.stringify(val) + ); +}; + +/** + * Parse the given `str` and return milliseconds. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function parse(str) { + str = String(str); + if (str.length > 100) { + return; + } + var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec( + str + ); + if (!match) { + return; + } + var n = parseFloat(match[1]); + var type = (match[2] || 'ms').toLowerCase(); + switch (type) { + case 'years': + case 'year': + case 'yrs': + case 'yr': + case 'y': + return n * y; + case 'weeks': + case 'week': + case 'w': + return n * w; + case 'days': + case 'day': + case 'd': + return n * d; + case 'hours': + case 'hour': + case 'hrs': + case 'hr': + case 'h': + return n * h; + case 'minutes': + case 'minute': + case 'mins': + case 'min': + case 'm': + return n * m; + case 'seconds': + case 'second': + case 'secs': + case 'sec': + case 's': + return n * s; + case 'milliseconds': + case 'millisecond': + case 'msecs': + case 'msec': + case 'ms': + return n; + default: + return undefined; + } +} + +/** + * Short format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtShort(ms) { + var msAbs = Math.abs(ms); + if (msAbs >= d) { + return Math.round(ms / d) + 'd'; + } + if (msAbs >= h) { + return Math.round(ms / h) + 'h'; + } + if (msAbs >= m) { + return Math.round(ms / m) + 'm'; + } + if (msAbs >= s) { + return Math.round(ms / s) + 's'; + } + return ms + 'ms'; +} + +/** + * Long format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtLong(ms) { + var msAbs = Math.abs(ms); + if (msAbs >= d) { + return plural(ms, msAbs, d, 'day'); + } + if (msAbs >= h) { + return plural(ms, msAbs, h, 'hour'); + } + if (msAbs >= m) { + return plural(ms, msAbs, m, 'minute'); + } + if (msAbs >= s) { + return plural(ms, msAbs, s, 'second'); + } + return ms + ' ms'; +} + +/** + * Pluralization helper. + */ + +function plural(ms, msAbs, n, name) { + var isPlural = msAbs >= n * 1.5; + return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : ''); +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ms/license.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ms/license.md new file mode 100644 index 0000000..fa5d39b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ms/license.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2020 Vercel, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ms/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ms/package.json new file mode 100644 index 0000000..d281c72 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ms/package.json @@ -0,0 +1,70 @@ +{ + "_from": "ms@^2.1.1", + "_id": "ms@2.1.3", + "_inBundle": false, + "_integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "_location": "/ms", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "ms@^2.1.1", + "name": "ms", + "escapedName": "ms", + "rawSpec": "^2.1.1", + "saveSpec": null, + "fetchSpec": "^2.1.1" + }, + "_requiredBy": [ + "/jsonwebtoken" + ], + "_resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "_shasum": "574c8138ce1d2b5861f0b44579dbadd60c6615b2", + "_spec": "ms@^2.1.1", + "_where": "D:\\xm\\online-code\\hellounicloud\\uni_modules\\uni-id-pages\\uniCloud\\cloudfunctions\\uni-id-co\\node_modules\\jsonwebtoken", + "bugs": { + "url": "https://github.com/vercel/ms/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "Tiny millisecond conversion utility", + "devDependencies": { + "eslint": "4.18.2", + "expect.js": "0.3.1", + "husky": "0.14.3", + "lint-staged": "5.0.0", + "mocha": "4.0.1", + "prettier": "2.0.5" + }, + "eslintConfig": { + "extends": "eslint:recommended", + "env": { + "node": true, + "es6": true + } + }, + "files": [ + "index.js" + ], + "homepage": "https://github.com/vercel/ms#readme", + "license": "MIT", + "lint-staged": { + "*.js": [ + "npm run lint", + "prettier --single-quote --write", + "git add" + ] + }, + "main": "./index", + "name": "ms", + "repository": { + "type": "git", + "url": "git+https://github.com/vercel/ms.git" + }, + "scripts": { + "lint": "eslint lib/* bin/*", + "precommit": "lint-staged", + "test": "mocha tests.js" + }, + "version": "2.1.3" +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ms/readme.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ms/readme.md new file mode 100644 index 0000000..0fc1abb --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/ms/readme.md @@ -0,0 +1,59 @@ +# ms + +![CI](https://github.com/vercel/ms/workflows/CI/badge.svg) + +Use this package to easily convert various time formats to milliseconds. + +## Examples + +```js +ms('2 days') // 172800000 +ms('1d') // 86400000 +ms('10h') // 36000000 +ms('2.5 hrs') // 9000000 +ms('2h') // 7200000 +ms('1m') // 60000 +ms('5s') // 5000 +ms('1y') // 31557600000 +ms('100') // 100 +ms('-3 days') // -259200000 +ms('-1h') // -3600000 +ms('-200') // -200 +``` + +### Convert from Milliseconds + +```js +ms(60000) // "1m" +ms(2 * 60000) // "2m" +ms(-3 * 60000) // "-3m" +ms(ms('10 hours')) // "10h" +``` + +### Time Format Written-Out + +```js +ms(60000, { long: true }) // "1 minute" +ms(2 * 60000, { long: true }) // "2 minutes" +ms(-3 * 60000, { long: true }) // "-3 minutes" +ms(ms('10 hours'), { long: true }) // "10 hours" +``` + +## Features + +- Works both in [Node.js](https://nodejs.org) and in the browser +- If a number is supplied to `ms`, a string with a unit is returned +- If a string that contains the number is supplied, it returns it as a number (e.g.: it returns `100` for `'100'`) +- If you pass a string with a number and a valid unit, the number of equivalent milliseconds is returned + +## Related Packages + +- [ms.macro](https://github.com/knpwrs/ms.macro) - Run `ms` as a macro at build-time. + +## Caught a Bug? + +1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device +2. Link the package to the global module directory: `npm link` +3. Within the module you want to test your local development instance of ms, just link it to the dependencies: `npm link ms`. Instead of the default one from npm, Node.js will now use your clone of ms! + +As always, you can run the tests using: `npm test` diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/LICENSE b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/LICENSE new file mode 100644 index 0000000..0c068ce --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Feross Aboukhadijeh + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/README.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/README.md new file mode 100644 index 0000000..e9a81af --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/README.md @@ -0,0 +1,584 @@ +# safe-buffer [![travis][travis-image]][travis-url] [![npm][npm-image]][npm-url] [![downloads][downloads-image]][downloads-url] [![javascript style guide][standard-image]][standard-url] + +[travis-image]: https://img.shields.io/travis/feross/safe-buffer/master.svg +[travis-url]: https://travis-ci.org/feross/safe-buffer +[npm-image]: https://img.shields.io/npm/v/safe-buffer.svg +[npm-url]: https://npmjs.org/package/safe-buffer +[downloads-image]: https://img.shields.io/npm/dm/safe-buffer.svg +[downloads-url]: https://npmjs.org/package/safe-buffer +[standard-image]: https://img.shields.io/badge/code_style-standard-brightgreen.svg +[standard-url]: https://standardjs.com + +#### Safer Node.js Buffer API + +**Use the new Node.js Buffer APIs (`Buffer.from`, `Buffer.alloc`, +`Buffer.allocUnsafe`, `Buffer.allocUnsafeSlow`) in all versions of Node.js.** + +**Uses the built-in implementation when available.** + +## install + +``` +npm install safe-buffer +``` + +## usage + +The goal of this package is to provide a safe replacement for the node.js `Buffer`. + +It's a drop-in replacement for `Buffer`. You can use it by adding one `require` line to +the top of your node.js modules: + +```js +var Buffer = require('safe-buffer').Buffer + +// Existing buffer code will continue to work without issues: + +new Buffer('hey', 'utf8') +new Buffer([1, 2, 3], 'utf8') +new Buffer(obj) +new Buffer(16) // create an uninitialized buffer (potentially unsafe) + +// But you can use these new explicit APIs to make clear what you want: + +Buffer.from('hey', 'utf8') // convert from many types to a Buffer +Buffer.alloc(16) // create a zero-filled buffer (safe) +Buffer.allocUnsafe(16) // create an uninitialized buffer (potentially unsafe) +``` + +## api + +### Class Method: Buffer.from(array) + + +* `array` {Array} + +Allocates a new `Buffer` using an `array` of octets. + +```js +const buf = Buffer.from([0x62,0x75,0x66,0x66,0x65,0x72]); + // creates a new Buffer containing ASCII bytes + // ['b','u','f','f','e','r'] +``` + +A `TypeError` will be thrown if `array` is not an `Array`. + +### Class Method: Buffer.from(arrayBuffer[, byteOffset[, length]]) + + +* `arrayBuffer` {ArrayBuffer} The `.buffer` property of a `TypedArray` or + a `new ArrayBuffer()` +* `byteOffset` {Number} Default: `0` +* `length` {Number} Default: `arrayBuffer.length - byteOffset` + +When passed a reference to the `.buffer` property of a `TypedArray` instance, +the newly created `Buffer` will share the same allocated memory as the +TypedArray. + +```js +const arr = new Uint16Array(2); +arr[0] = 5000; +arr[1] = 4000; + +const buf = Buffer.from(arr.buffer); // shares the memory with arr; + +console.log(buf); + // Prints: + +// changing the TypedArray changes the Buffer also +arr[1] = 6000; + +console.log(buf); + // Prints: +``` + +The optional `byteOffset` and `length` arguments specify a memory range within +the `arrayBuffer` that will be shared by the `Buffer`. + +```js +const ab = new ArrayBuffer(10); +const buf = Buffer.from(ab, 0, 2); +console.log(buf.length); + // Prints: 2 +``` + +A `TypeError` will be thrown if `arrayBuffer` is not an `ArrayBuffer`. + +### Class Method: Buffer.from(buffer) + + +* `buffer` {Buffer} + +Copies the passed `buffer` data onto a new `Buffer` instance. + +```js +const buf1 = Buffer.from('buffer'); +const buf2 = Buffer.from(buf1); + +buf1[0] = 0x61; +console.log(buf1.toString()); + // 'auffer' +console.log(buf2.toString()); + // 'buffer' (copy is not changed) +``` + +A `TypeError` will be thrown if `buffer` is not a `Buffer`. + +### Class Method: Buffer.from(str[, encoding]) + + +* `str` {String} String to encode. +* `encoding` {String} Encoding to use, Default: `'utf8'` + +Creates a new `Buffer` containing the given JavaScript string `str`. If +provided, the `encoding` parameter identifies the character encoding. +If not provided, `encoding` defaults to `'utf8'`. + +```js +const buf1 = Buffer.from('this is a tést'); +console.log(buf1.toString()); + // prints: this is a tést +console.log(buf1.toString('ascii')); + // prints: this is a tC)st + +const buf2 = Buffer.from('7468697320697320612074c3a97374', 'hex'); +console.log(buf2.toString()); + // prints: this is a tést +``` + +A `TypeError` will be thrown if `str` is not a string. + +### Class Method: Buffer.alloc(size[, fill[, encoding]]) + + +* `size` {Number} +* `fill` {Value} Default: `undefined` +* `encoding` {String} Default: `utf8` + +Allocates a new `Buffer` of `size` bytes. If `fill` is `undefined`, the +`Buffer` will be *zero-filled*. + +```js +const buf = Buffer.alloc(5); +console.log(buf); + // +``` + +The `size` must be less than or equal to the value of +`require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is +`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. A zero-length Buffer will +be created if a `size` less than or equal to 0 is specified. + +If `fill` is specified, the allocated `Buffer` will be initialized by calling +`buf.fill(fill)`. See [`buf.fill()`][] for more information. + +```js +const buf = Buffer.alloc(5, 'a'); +console.log(buf); + // +``` + +If both `fill` and `encoding` are specified, the allocated `Buffer` will be +initialized by calling `buf.fill(fill, encoding)`. For example: + +```js +const buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64'); +console.log(buf); + // +``` + +Calling `Buffer.alloc(size)` can be significantly slower than the alternative +`Buffer.allocUnsafe(size)` but ensures that the newly created `Buffer` instance +contents will *never contain sensitive data*. + +A `TypeError` will be thrown if `size` is not a number. + +### Class Method: Buffer.allocUnsafe(size) + + +* `size` {Number} + +Allocates a new *non-zero-filled* `Buffer` of `size` bytes. The `size` must +be less than or equal to the value of `require('buffer').kMaxLength` (on 64-bit +architectures, `kMaxLength` is `(2^31)-1`). Otherwise, a [`RangeError`][] is +thrown. A zero-length Buffer will be created if a `size` less than or equal to +0 is specified. + +The underlying memory for `Buffer` instances created in this way is *not +initialized*. The contents of the newly created `Buffer` are unknown and +*may contain sensitive data*. Use [`buf.fill(0)`][] to initialize such +`Buffer` instances to zeroes. + +```js +const buf = Buffer.allocUnsafe(5); +console.log(buf); + // + // (octets will be different, every time) +buf.fill(0); +console.log(buf); + // +``` + +A `TypeError` will be thrown if `size` is not a number. + +Note that the `Buffer` module pre-allocates an internal `Buffer` instance of +size `Buffer.poolSize` that is used as a pool for the fast allocation of new +`Buffer` instances created using `Buffer.allocUnsafe(size)` (and the deprecated +`new Buffer(size)` constructor) only when `size` is less than or equal to +`Buffer.poolSize >> 1` (floor of `Buffer.poolSize` divided by two). The default +value of `Buffer.poolSize` is `8192` but can be modified. + +Use of this pre-allocated internal memory pool is a key difference between +calling `Buffer.alloc(size, fill)` vs. `Buffer.allocUnsafe(size).fill(fill)`. +Specifically, `Buffer.alloc(size, fill)` will *never* use the internal Buffer +pool, while `Buffer.allocUnsafe(size).fill(fill)` *will* use the internal +Buffer pool if `size` is less than or equal to half `Buffer.poolSize`. The +difference is subtle but can be important when an application requires the +additional performance that `Buffer.allocUnsafe(size)` provides. + +### Class Method: Buffer.allocUnsafeSlow(size) + + +* `size` {Number} + +Allocates a new *non-zero-filled* and non-pooled `Buffer` of `size` bytes. The +`size` must be less than or equal to the value of +`require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is +`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. A zero-length Buffer will +be created if a `size` less than or equal to 0 is specified. + +The underlying memory for `Buffer` instances created in this way is *not +initialized*. The contents of the newly created `Buffer` are unknown and +*may contain sensitive data*. Use [`buf.fill(0)`][] to initialize such +`Buffer` instances to zeroes. + +When using `Buffer.allocUnsafe()` to allocate new `Buffer` instances, +allocations under 4KB are, by default, sliced from a single pre-allocated +`Buffer`. This allows applications to avoid the garbage collection overhead of +creating many individually allocated Buffers. This approach improves both +performance and memory usage by eliminating the need to track and cleanup as +many `Persistent` objects. + +However, in the case where a developer may need to retain a small chunk of +memory from a pool for an indeterminate amount of time, it may be appropriate +to create an un-pooled Buffer instance using `Buffer.allocUnsafeSlow()` then +copy out the relevant bits. + +```js +// need to keep around a few small chunks of memory +const store = []; + +socket.on('readable', () => { + const data = socket.read(); + // allocate for retained data + const sb = Buffer.allocUnsafeSlow(10); + // copy the data into the new allocation + data.copy(sb, 0, 0, 10); + store.push(sb); +}); +``` + +Use of `Buffer.allocUnsafeSlow()` should be used only as a last resort *after* +a developer has observed undue memory retention in their applications. + +A `TypeError` will be thrown if `size` is not a number. + +### All the Rest + +The rest of the `Buffer` API is exactly the same as in node.js. +[See the docs](https://nodejs.org/api/buffer.html). + + +## Related links + +- [Node.js issue: Buffer(number) is unsafe](https://github.com/nodejs/node/issues/4660) +- [Node.js Enhancement Proposal: Buffer.from/Buffer.alloc/Buffer.zalloc/Buffer() soft-deprecate](https://github.com/nodejs/node-eps/pull/4) + +## Why is `Buffer` unsafe? + +Today, the node.js `Buffer` constructor is overloaded to handle many different argument +types like `String`, `Array`, `Object`, `TypedArrayView` (`Uint8Array`, etc.), +`ArrayBuffer`, and also `Number`. + +The API is optimized for convenience: you can throw any type at it, and it will try to do +what you want. + +Because the Buffer constructor is so powerful, you often see code like this: + +```js +// Convert UTF-8 strings to hex +function toHex (str) { + return new Buffer(str).toString('hex') +} +``` + +***But what happens if `toHex` is called with a `Number` argument?*** + +### Remote Memory Disclosure + +If an attacker can make your program call the `Buffer` constructor with a `Number` +argument, then they can make it allocate uninitialized memory from the node.js process. +This could potentially disclose TLS private keys, user data, or database passwords. + +When the `Buffer` constructor is passed a `Number` argument, it returns an +**UNINITIALIZED** block of memory of the specified `size`. When you create a `Buffer` like +this, you **MUST** overwrite the contents before returning it to the user. + +From the [node.js docs](https://nodejs.org/api/buffer.html#buffer_new_buffer_size): + +> `new Buffer(size)` +> +> - `size` Number +> +> The underlying memory for `Buffer` instances created in this way is not initialized. +> **The contents of a newly created `Buffer` are unknown and could contain sensitive +> data.** Use `buf.fill(0)` to initialize a Buffer to zeroes. + +(Emphasis our own.) + +Whenever the programmer intended to create an uninitialized `Buffer` you often see code +like this: + +```js +var buf = new Buffer(16) + +// Immediately overwrite the uninitialized buffer with data from another buffer +for (var i = 0; i < buf.length; i++) { + buf[i] = otherBuf[i] +} +``` + + +### Would this ever be a problem in real code? + +Yes. It's surprisingly common to forget to check the type of your variables in a +dynamically-typed language like JavaScript. + +Usually the consequences of assuming the wrong type is that your program crashes with an +uncaught exception. But the failure mode for forgetting to check the type of arguments to +the `Buffer` constructor is more catastrophic. + +Here's an example of a vulnerable service that takes a JSON payload and converts it to +hex: + +```js +// Take a JSON payload {str: "some string"} and convert it to hex +var server = http.createServer(function (req, res) { + var data = '' + req.setEncoding('utf8') + req.on('data', function (chunk) { + data += chunk + }) + req.on('end', function () { + var body = JSON.parse(data) + res.end(new Buffer(body.str).toString('hex')) + }) +}) + +server.listen(8080) +``` + +In this example, an http client just has to send: + +```json +{ + "str": 1000 +} +``` + +and it will get back 1,000 bytes of uninitialized memory from the server. + +This is a very serious bug. It's similar in severity to the +[the Heartbleed bug](http://heartbleed.com/) that allowed disclosure of OpenSSL process +memory by remote attackers. + + +### Which real-world packages were vulnerable? + +#### [`bittorrent-dht`](https://www.npmjs.com/package/bittorrent-dht) + +[Mathias Buus](https://github.com/mafintosh) and I +([Feross Aboukhadijeh](http://feross.org/)) found this issue in one of our own packages, +[`bittorrent-dht`](https://www.npmjs.com/package/bittorrent-dht). The bug would allow +anyone on the internet to send a series of messages to a user of `bittorrent-dht` and get +them to reveal 20 bytes at a time of uninitialized memory from the node.js process. + +Here's +[the commit](https://github.com/feross/bittorrent-dht/commit/6c7da04025d5633699800a99ec3fbadf70ad35b8) +that fixed it. We released a new fixed version, created a +[Node Security Project disclosure](https://nodesecurity.io/advisories/68), and deprecated all +vulnerable versions on npm so users will get a warning to upgrade to a newer version. + +#### [`ws`](https://www.npmjs.com/package/ws) + +That got us wondering if there were other vulnerable packages. Sure enough, within a short +period of time, we found the same issue in [`ws`](https://www.npmjs.com/package/ws), the +most popular WebSocket implementation in node.js. + +If certain APIs were called with `Number` parameters instead of `String` or `Buffer` as +expected, then uninitialized server memory would be disclosed to the remote peer. + +These were the vulnerable methods: + +```js +socket.send(number) +socket.ping(number) +socket.pong(number) +``` + +Here's a vulnerable socket server with some echo functionality: + +```js +server.on('connection', function (socket) { + socket.on('message', function (message) { + message = JSON.parse(message) + if (message.type === 'echo') { + socket.send(message.data) // send back the user's message + } + }) +}) +``` + +`socket.send(number)` called on the server, will disclose server memory. + +Here's [the release](https://github.com/websockets/ws/releases/tag/1.0.1) where the issue +was fixed, with a more detailed explanation. Props to +[Arnout Kazemier](https://github.com/3rd-Eden) for the quick fix. Here's the +[Node Security Project disclosure](https://nodesecurity.io/advisories/67). + + +### What's the solution? + +It's important that node.js offers a fast way to get memory otherwise performance-critical +applications would needlessly get a lot slower. + +But we need a better way to *signal our intent* as programmers. **When we want +uninitialized memory, we should request it explicitly.** + +Sensitive functionality should not be packed into a developer-friendly API that loosely +accepts many different types. This type of API encourages the lazy practice of passing +variables in without checking the type very carefully. + +#### A new API: `Buffer.allocUnsafe(number)` + +The functionality of creating buffers with uninitialized memory should be part of another +API. We propose `Buffer.allocUnsafe(number)`. This way, it's not part of an API that +frequently gets user input of all sorts of different types passed into it. + +```js +var buf = Buffer.allocUnsafe(16) // careful, uninitialized memory! + +// Immediately overwrite the uninitialized buffer with data from another buffer +for (var i = 0; i < buf.length; i++) { + buf[i] = otherBuf[i] +} +``` + + +### How do we fix node.js core? + +We sent [a PR to node.js core](https://github.com/nodejs/node/pull/4514) (merged as +`semver-major`) which defends against one case: + +```js +var str = 16 +new Buffer(str, 'utf8') +``` + +In this situation, it's implied that the programmer intended the first argument to be a +string, since they passed an encoding as a second argument. Today, node.js will allocate +uninitialized memory in the case of `new Buffer(number, encoding)`, which is probably not +what the programmer intended. + +But this is only a partial solution, since if the programmer does `new Buffer(variable)` +(without an `encoding` parameter) there's no way to know what they intended. If `variable` +is sometimes a number, then uninitialized memory will sometimes be returned. + +### What's the real long-term fix? + +We could deprecate and remove `new Buffer(number)` and use `Buffer.allocUnsafe(number)` when +we need uninitialized memory. But that would break 1000s of packages. + +~~We believe the best solution is to:~~ + +~~1. Change `new Buffer(number)` to return safe, zeroed-out memory~~ + +~~2. Create a new API for creating uninitialized Buffers. We propose: `Buffer.allocUnsafe(number)`~~ + +#### Update + +We now support adding three new APIs: + +- `Buffer.from(value)` - convert from any type to a buffer +- `Buffer.alloc(size)` - create a zero-filled buffer +- `Buffer.allocUnsafe(size)` - create an uninitialized buffer with given size + +This solves the core problem that affected `ws` and `bittorrent-dht` which is +`Buffer(variable)` getting tricked into taking a number argument. + +This way, existing code continues working and the impact on the npm ecosystem will be +minimal. Over time, npm maintainers can migrate performance-critical code to use +`Buffer.allocUnsafe(number)` instead of `new Buffer(number)`. + + +### Conclusion + +We think there's a serious design issue with the `Buffer` API as it exists today. It +promotes insecure software by putting high-risk functionality into a convenient API +with friendly "developer ergonomics". + +This wasn't merely a theoretical exercise because we found the issue in some of the +most popular npm packages. + +Fortunately, there's an easy fix that can be applied today. Use `safe-buffer` in place of +`buffer`. + +```js +var Buffer = require('safe-buffer').Buffer +``` + +Eventually, we hope that node.js core can switch to this new, safer behavior. We believe +the impact on the ecosystem would be minimal since it's not a breaking change. +Well-maintained, popular packages would be updated to use `Buffer.alloc` quickly, while +older, insecure packages would magically become safe from this attack vector. + + +## links + +- [Node.js PR: buffer: throw if both length and enc are passed](https://github.com/nodejs/node/pull/4514) +- [Node Security Project disclosure for `ws`](https://nodesecurity.io/advisories/67) +- [Node Security Project disclosure for`bittorrent-dht`](https://nodesecurity.io/advisories/68) + + +## credit + +The original issues in `bittorrent-dht` +([disclosure](https://nodesecurity.io/advisories/68)) and +`ws` ([disclosure](https://nodesecurity.io/advisories/67)) were discovered by +[Mathias Buus](https://github.com/mafintosh) and +[Feross Aboukhadijeh](http://feross.org/). + +Thanks to [Adam Baldwin](https://github.com/evilpacket) for helping disclose these issues +and for his work running the [Node Security Project](https://nodesecurity.io/). + +Thanks to [John Hiesey](https://github.com/jhiesey) for proofreading this README and +auditing the code. + + +## license + +MIT. Copyright (C) [Feross Aboukhadijeh](http://feross.org) diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/index.d.ts b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/index.d.ts new file mode 100644 index 0000000..e9fed80 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/index.d.ts @@ -0,0 +1,187 @@ +declare module "safe-buffer" { + export class Buffer { + length: number + write(string: string, offset?: number, length?: number, encoding?: string): number; + toString(encoding?: string, start?: number, end?: number): string; + toJSON(): { type: 'Buffer', data: any[] }; + equals(otherBuffer: Buffer): boolean; + compare(otherBuffer: Buffer, targetStart?: number, targetEnd?: number, sourceStart?: number, sourceEnd?: number): number; + copy(targetBuffer: Buffer, targetStart?: number, sourceStart?: number, sourceEnd?: number): number; + slice(start?: number, end?: number): Buffer; + writeUIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; + writeUIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; + writeIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; + writeIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; + readUIntLE(offset: number, byteLength: number, noAssert?: boolean): number; + readUIntBE(offset: number, byteLength: number, noAssert?: boolean): number; + readIntLE(offset: number, byteLength: number, noAssert?: boolean): number; + readIntBE(offset: number, byteLength: number, noAssert?: boolean): number; + readUInt8(offset: number, noAssert?: boolean): number; + readUInt16LE(offset: number, noAssert?: boolean): number; + readUInt16BE(offset: number, noAssert?: boolean): number; + readUInt32LE(offset: number, noAssert?: boolean): number; + readUInt32BE(offset: number, noAssert?: boolean): number; + readInt8(offset: number, noAssert?: boolean): number; + readInt16LE(offset: number, noAssert?: boolean): number; + readInt16BE(offset: number, noAssert?: boolean): number; + readInt32LE(offset: number, noAssert?: boolean): number; + readInt32BE(offset: number, noAssert?: boolean): number; + readFloatLE(offset: number, noAssert?: boolean): number; + readFloatBE(offset: number, noAssert?: boolean): number; + readDoubleLE(offset: number, noAssert?: boolean): number; + readDoubleBE(offset: number, noAssert?: boolean): number; + swap16(): Buffer; + swap32(): Buffer; + swap64(): Buffer; + writeUInt8(value: number, offset: number, noAssert?: boolean): number; + writeUInt16LE(value: number, offset: number, noAssert?: boolean): number; + writeUInt16BE(value: number, offset: number, noAssert?: boolean): number; + writeUInt32LE(value: number, offset: number, noAssert?: boolean): number; + writeUInt32BE(value: number, offset: number, noAssert?: boolean): number; + writeInt8(value: number, offset: number, noAssert?: boolean): number; + writeInt16LE(value: number, offset: number, noAssert?: boolean): number; + writeInt16BE(value: number, offset: number, noAssert?: boolean): number; + writeInt32LE(value: number, offset: number, noAssert?: boolean): number; + writeInt32BE(value: number, offset: number, noAssert?: boolean): number; + writeFloatLE(value: number, offset: number, noAssert?: boolean): number; + writeFloatBE(value: number, offset: number, noAssert?: boolean): number; + writeDoubleLE(value: number, offset: number, noAssert?: boolean): number; + writeDoubleBE(value: number, offset: number, noAssert?: boolean): number; + fill(value: any, offset?: number, end?: number): this; + indexOf(value: string | number | Buffer, byteOffset?: number, encoding?: string): number; + lastIndexOf(value: string | number | Buffer, byteOffset?: number, encoding?: string): number; + includes(value: string | number | Buffer, byteOffset?: number, encoding?: string): boolean; + + /** + * Allocates a new buffer containing the given {str}. + * + * @param str String to store in buffer. + * @param encoding encoding to use, optional. Default is 'utf8' + */ + constructor (str: string, encoding?: string); + /** + * Allocates a new buffer of {size} octets. + * + * @param size count of octets to allocate. + */ + constructor (size: number); + /** + * Allocates a new buffer containing the given {array} of octets. + * + * @param array The octets to store. + */ + constructor (array: Uint8Array); + /** + * Produces a Buffer backed by the same allocated memory as + * the given {ArrayBuffer}. + * + * + * @param arrayBuffer The ArrayBuffer with which to share memory. + */ + constructor (arrayBuffer: ArrayBuffer); + /** + * Allocates a new buffer containing the given {array} of octets. + * + * @param array The octets to store. + */ + constructor (array: any[]); + /** + * Copies the passed {buffer} data onto a new {Buffer} instance. + * + * @param buffer The buffer to copy. + */ + constructor (buffer: Buffer); + prototype: Buffer; + /** + * Allocates a new Buffer using an {array} of octets. + * + * @param array + */ + static from(array: any[]): Buffer; + /** + * When passed a reference to the .buffer property of a TypedArray instance, + * the newly created Buffer will share the same allocated memory as the TypedArray. + * The optional {byteOffset} and {length} arguments specify a memory range + * within the {arrayBuffer} that will be shared by the Buffer. + * + * @param arrayBuffer The .buffer property of a TypedArray or a new ArrayBuffer() + * @param byteOffset + * @param length + */ + static from(arrayBuffer: ArrayBuffer, byteOffset?: number, length?: number): Buffer; + /** + * Copies the passed {buffer} data onto a new Buffer instance. + * + * @param buffer + */ + static from(buffer: Buffer): Buffer; + /** + * Creates a new Buffer containing the given JavaScript string {str}. + * If provided, the {encoding} parameter identifies the character encoding. + * If not provided, {encoding} defaults to 'utf8'. + * + * @param str + */ + static from(str: string, encoding?: string): Buffer; + /** + * Returns true if {obj} is a Buffer + * + * @param obj object to test. + */ + static isBuffer(obj: any): obj is Buffer; + /** + * Returns true if {encoding} is a valid encoding argument. + * Valid string encodings in Node 0.12: 'ascii'|'utf8'|'utf16le'|'ucs2'(alias of 'utf16le')|'base64'|'binary'(deprecated)|'hex' + * + * @param encoding string to test. + */ + static isEncoding(encoding: string): boolean; + /** + * Gives the actual byte length of a string. encoding defaults to 'utf8'. + * This is not the same as String.prototype.length since that returns the number of characters in a string. + * + * @param string string to test. + * @param encoding encoding used to evaluate (defaults to 'utf8') + */ + static byteLength(string: string, encoding?: string): number; + /** + * Returns a buffer which is the result of concatenating all the buffers in the list together. + * + * If the list has no items, or if the totalLength is 0, then it returns a zero-length buffer. + * If the list has exactly one item, then the first item of the list is returned. + * If the list has more than one item, then a new Buffer is created. + * + * @param list An array of Buffer objects to concatenate + * @param totalLength Total length of the buffers when concatenated. + * If totalLength is not provided, it is read from the buffers in the list. However, this adds an additional loop to the function, so it is faster to provide the length explicitly. + */ + static concat(list: Buffer[], totalLength?: number): Buffer; + /** + * The same as buf1.compare(buf2). + */ + static compare(buf1: Buffer, buf2: Buffer): number; + /** + * Allocates a new buffer of {size} octets. + * + * @param size count of octets to allocate. + * @param fill if specified, buffer will be initialized by calling buf.fill(fill). + * If parameter is omitted, buffer will be filled with zeros. + * @param encoding encoding used for call to buf.fill while initalizing + */ + static alloc(size: number, fill?: string | Buffer | number, encoding?: string): Buffer; + /** + * Allocates a new buffer of {size} octets, leaving memory not initialized, so the contents + * of the newly created Buffer are unknown and may contain sensitive data. + * + * @param size count of octets to allocate + */ + static allocUnsafe(size: number): Buffer; + /** + * Allocates a new non-pooled buffer of {size} octets, leaving memory not initialized, so the contents + * of the newly created Buffer are unknown and may contain sensitive data. + * + * @param size count of octets to allocate + */ + static allocUnsafeSlow(size: number): Buffer; + } +} \ No newline at end of file diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/index.js new file mode 100644 index 0000000..f8d3ec9 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/index.js @@ -0,0 +1,65 @@ +/*! safe-buffer. MIT License. Feross Aboukhadijeh */ +/* eslint-disable node/no-deprecated-api */ +var buffer = require('buffer') +var Buffer = buffer.Buffer + +// alternative to using Object.keys for old browsers +function copyProps (src, dst) { + for (var key in src) { + dst[key] = src[key] + } +} +if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { + module.exports = buffer +} else { + // Copy properties from require('buffer') + copyProps(buffer, exports) + exports.Buffer = SafeBuffer +} + +function SafeBuffer (arg, encodingOrOffset, length) { + return Buffer(arg, encodingOrOffset, length) +} + +SafeBuffer.prototype = Object.create(Buffer.prototype) + +// Copy static methods from Buffer +copyProps(Buffer, SafeBuffer) + +SafeBuffer.from = function (arg, encodingOrOffset, length) { + if (typeof arg === 'number') { + throw new TypeError('Argument must not be a number') + } + return Buffer(arg, encodingOrOffset, length) +} + +SafeBuffer.alloc = function (size, fill, encoding) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + var buf = Buffer(size) + if (fill !== undefined) { + if (typeof encoding === 'string') { + buf.fill(fill, encoding) + } else { + buf.fill(fill) + } + } else { + buf.fill(0) + } + return buf +} + +SafeBuffer.allocUnsafe = function (size) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + return Buffer(size) +} + +SafeBuffer.allocUnsafeSlow = function (size) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + return buffer.SlowBuffer(size) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/package.json new file mode 100644 index 0000000..f50768e --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/safe-buffer/package.json @@ -0,0 +1,78 @@ +{ + "_from": "safe-buffer@^5.0.1", + "_id": "safe-buffer@5.2.1", + "_inBundle": false, + "_integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "_location": "/safe-buffer", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "safe-buffer@^5.0.1", + "name": "safe-buffer", + "escapedName": "safe-buffer", + "rawSpec": "^5.0.1", + "saveSpec": null, + "fetchSpec": "^5.0.1" + }, + "_requiredBy": [ + "/ecdsa-sig-formatter", + "/jwa", + "/jws" + ], + "_resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "_shasum": "1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6", + "_spec": "safe-buffer@^5.0.1", + "_where": "D:\\xm\\online-code\\hellounicloud\\uni_modules\\uni-id-pages\\uniCloud\\cloudfunctions\\uni-id-co\\node_modules\\jws", + "author": { + "name": "Feross Aboukhadijeh", + "email": "feross@feross.org", + "url": "https://feross.org" + }, + "bugs": { + "url": "https://github.com/feross/safe-buffer/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "Safer Node.js Buffer API", + "devDependencies": { + "standard": "*", + "tape": "^5.0.0" + }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "homepage": "https://github.com/feross/safe-buffer", + "keywords": [ + "buffer", + "buffer allocate", + "node security", + "safe", + "safe-buffer", + "security", + "uninitialized" + ], + "license": "MIT", + "main": "index.js", + "name": "safe-buffer", + "repository": { + "type": "git", + "url": "git://github.com/feross/safe-buffer.git" + }, + "scripts": { + "test": "standard && tape test/*.js" + }, + "types": "index.d.ts", + "version": "5.2.1" +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/CHANGELOG.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/CHANGELOG.md new file mode 100644 index 0000000..66304fd --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/CHANGELOG.md @@ -0,0 +1,39 @@ +# changes log + +## 5.7 + +* Add `minVersion` method + +## 5.6 + +* Move boolean `loose` param to an options object, with + backwards-compatibility protection. +* Add ability to opt out of special prerelease version handling with + the `includePrerelease` option flag. + +## 5.5 + +* Add version coercion capabilities + +## 5.4 + +* Add intersection checking + +## 5.3 + +* Add `minSatisfying` method + +## 5.2 + +* Add `prerelease(v)` that returns prerelease components + +## 5.1 + +* Add Backus-Naur for ranges +* Remove excessively cute inspection methods + +## 5.0 + +* Remove AMD/Browserified build artifacts +* Fix ltr and gtr when using the `*` range +* Fix for range `*` with a prerelease identifier diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/LICENSE b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/LICENSE new file mode 100644 index 0000000..19129e3 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/LICENSE @@ -0,0 +1,15 @@ +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/README.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/README.md new file mode 100644 index 0000000..f8dfa5a --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/README.md @@ -0,0 +1,412 @@ +semver(1) -- The semantic versioner for npm +=========================================== + +## Install + +```bash +npm install --save semver +```` + +## Usage + +As a node module: + +```js +const semver = require('semver') + +semver.valid('1.2.3') // '1.2.3' +semver.valid('a.b.c') // null +semver.clean(' =v1.2.3 ') // '1.2.3' +semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') // true +semver.gt('1.2.3', '9.8.7') // false +semver.lt('1.2.3', '9.8.7') // true +semver.minVersion('>=1.0.0') // '1.0.0' +semver.valid(semver.coerce('v2')) // '2.0.0' +semver.valid(semver.coerce('42.6.7.9.3-alpha')) // '42.6.7' +``` + +As a command-line utility: + +``` +$ semver -h + +A JavaScript implementation of the https://semver.org/ specification +Copyright Isaac Z. Schlueter + +Usage: semver [options] [ [...]] +Prints valid versions sorted by SemVer precedence + +Options: +-r --range + Print versions that match the specified range. + +-i --increment [] + Increment a version by the specified level. Level can + be one of: major, minor, patch, premajor, preminor, + prepatch, or prerelease. Default level is 'patch'. + Only one version may be specified. + +--preid + Identifier to be used to prefix premajor, preminor, + prepatch or prerelease version increments. + +-l --loose + Interpret versions and ranges loosely + +-p --include-prerelease + Always include prerelease versions in range matching + +-c --coerce + Coerce a string into SemVer if possible + (does not imply --loose) + +Program exits successfully if any valid version satisfies +all supplied ranges, and prints all satisfying versions. + +If no satisfying versions are found, then exits failure. + +Versions are printed in ascending order, so supplying +multiple versions to the utility will just sort them. +``` + +## Versions + +A "version" is described by the `v2.0.0` specification found at +. + +A leading `"="` or `"v"` character is stripped off and ignored. + +## Ranges + +A `version range` is a set of `comparators` which specify versions +that satisfy the range. + +A `comparator` is composed of an `operator` and a `version`. The set +of primitive `operators` is: + +* `<` Less than +* `<=` Less than or equal to +* `>` Greater than +* `>=` Greater than or equal to +* `=` Equal. If no operator is specified, then equality is assumed, + so this operator is optional, but MAY be included. + +For example, the comparator `>=1.2.7` would match the versions +`1.2.7`, `1.2.8`, `2.5.3`, and `1.3.9`, but not the versions `1.2.6` +or `1.1.0`. + +Comparators can be joined by whitespace to form a `comparator set`, +which is satisfied by the **intersection** of all of the comparators +it includes. + +A range is composed of one or more comparator sets, joined by `||`. A +version matches a range if and only if every comparator in at least +one of the `||`-separated comparator sets is satisfied by the version. + +For example, the range `>=1.2.7 <1.3.0` would match the versions +`1.2.7`, `1.2.8`, and `1.2.99`, but not the versions `1.2.6`, `1.3.0`, +or `1.1.0`. + +The range `1.2.7 || >=1.2.9 <2.0.0` would match the versions `1.2.7`, +`1.2.9`, and `1.4.6`, but not the versions `1.2.8` or `2.0.0`. + +### Prerelease Tags + +If a version has a prerelease tag (for example, `1.2.3-alpha.3`) then +it will only be allowed to satisfy comparator sets if at least one +comparator with the same `[major, minor, patch]` tuple also has a +prerelease tag. + +For example, the range `>1.2.3-alpha.3` would be allowed to match the +version `1.2.3-alpha.7`, but it would *not* be satisfied by +`3.4.5-alpha.9`, even though `3.4.5-alpha.9` is technically "greater +than" `1.2.3-alpha.3` according to the SemVer sort rules. The version +range only accepts prerelease tags on the `1.2.3` version. The +version `3.4.5` *would* satisfy the range, because it does not have a +prerelease flag, and `3.4.5` is greater than `1.2.3-alpha.7`. + +The purpose for this behavior is twofold. First, prerelease versions +frequently are updated very quickly, and contain many breaking changes +that are (by the author's design) not yet fit for public consumption. +Therefore, by default, they are excluded from range matching +semantics. + +Second, a user who has opted into using a prerelease version has +clearly indicated the intent to use *that specific* set of +alpha/beta/rc versions. By including a prerelease tag in the range, +the user is indicating that they are aware of the risk. However, it +is still not appropriate to assume that they have opted into taking a +similar risk on the *next* set of prerelease versions. + +Note that this behavior can be suppressed (treating all prerelease +versions as if they were normal versions, for the purpose of range +matching) by setting the `includePrerelease` flag on the options +object to any +[functions](https://github.com/npm/node-semver#functions) that do +range matching. + +#### Prerelease Identifiers + +The method `.inc` takes an additional `identifier` string argument that +will append the value of the string as a prerelease identifier: + +```javascript +semver.inc('1.2.3', 'prerelease', 'beta') +// '1.2.4-beta.0' +``` + +command-line example: + +```bash +$ semver 1.2.3 -i prerelease --preid beta +1.2.4-beta.0 +``` + +Which then can be used to increment further: + +```bash +$ semver 1.2.4-beta.0 -i prerelease +1.2.4-beta.1 +``` + +### Advanced Range Syntax + +Advanced range syntax desugars to primitive comparators in +deterministic ways. + +Advanced ranges may be combined in the same way as primitive +comparators using white space or `||`. + +#### Hyphen Ranges `X.Y.Z - A.B.C` + +Specifies an inclusive set. + +* `1.2.3 - 2.3.4` := `>=1.2.3 <=2.3.4` + +If a partial version is provided as the first version in the inclusive +range, then the missing pieces are replaced with zeroes. + +* `1.2 - 2.3.4` := `>=1.2.0 <=2.3.4` + +If a partial version is provided as the second version in the +inclusive range, then all versions that start with the supplied parts +of the tuple are accepted, but nothing that would be greater than the +provided tuple parts. + +* `1.2.3 - 2.3` := `>=1.2.3 <2.4.0` +* `1.2.3 - 2` := `>=1.2.3 <3.0.0` + +#### X-Ranges `1.2.x` `1.X` `1.2.*` `*` + +Any of `X`, `x`, or `*` may be used to "stand in" for one of the +numeric values in the `[major, minor, patch]` tuple. + +* `*` := `>=0.0.0` (Any version satisfies) +* `1.x` := `>=1.0.0 <2.0.0` (Matching major version) +* `1.2.x` := `>=1.2.0 <1.3.0` (Matching major and minor versions) + +A partial version range is treated as an X-Range, so the special +character is in fact optional. + +* `""` (empty string) := `*` := `>=0.0.0` +* `1` := `1.x.x` := `>=1.0.0 <2.0.0` +* `1.2` := `1.2.x` := `>=1.2.0 <1.3.0` + +#### Tilde Ranges `~1.2.3` `~1.2` `~1` + +Allows patch-level changes if a minor version is specified on the +comparator. Allows minor-level changes if not. + +* `~1.2.3` := `>=1.2.3 <1.(2+1).0` := `>=1.2.3 <1.3.0` +* `~1.2` := `>=1.2.0 <1.(2+1).0` := `>=1.2.0 <1.3.0` (Same as `1.2.x`) +* `~1` := `>=1.0.0 <(1+1).0.0` := `>=1.0.0 <2.0.0` (Same as `1.x`) +* `~0.2.3` := `>=0.2.3 <0.(2+1).0` := `>=0.2.3 <0.3.0` +* `~0.2` := `>=0.2.0 <0.(2+1).0` := `>=0.2.0 <0.3.0` (Same as `0.2.x`) +* `~0` := `>=0.0.0 <(0+1).0.0` := `>=0.0.0 <1.0.0` (Same as `0.x`) +* `~1.2.3-beta.2` := `>=1.2.3-beta.2 <1.3.0` Note that prereleases in + the `1.2.3` version will be allowed, if they are greater than or + equal to `beta.2`. So, `1.2.3-beta.4` would be allowed, but + `1.2.4-beta.2` would not, because it is a prerelease of a + different `[major, minor, patch]` tuple. + +#### Caret Ranges `^1.2.3` `^0.2.5` `^0.0.4` + +Allows changes that do not modify the left-most non-zero digit in the +`[major, minor, patch]` tuple. In other words, this allows patch and +minor updates for versions `1.0.0` and above, patch updates for +versions `0.X >=0.1.0`, and *no* updates for versions `0.0.X`. + +Many authors treat a `0.x` version as if the `x` were the major +"breaking-change" indicator. + +Caret ranges are ideal when an author may make breaking changes +between `0.2.4` and `0.3.0` releases, which is a common practice. +However, it presumes that there will *not* be breaking changes between +`0.2.4` and `0.2.5`. It allows for changes that are presumed to be +additive (but non-breaking), according to commonly observed practices. + +* `^1.2.3` := `>=1.2.3 <2.0.0` +* `^0.2.3` := `>=0.2.3 <0.3.0` +* `^0.0.3` := `>=0.0.3 <0.0.4` +* `^1.2.3-beta.2` := `>=1.2.3-beta.2 <2.0.0` Note that prereleases in + the `1.2.3` version will be allowed, if they are greater than or + equal to `beta.2`. So, `1.2.3-beta.4` would be allowed, but + `1.2.4-beta.2` would not, because it is a prerelease of a + different `[major, minor, patch]` tuple. +* `^0.0.3-beta` := `>=0.0.3-beta <0.0.4` Note that prereleases in the + `0.0.3` version *only* will be allowed, if they are greater than or + equal to `beta`. So, `0.0.3-pr.2` would be allowed. + +When parsing caret ranges, a missing `patch` value desugars to the +number `0`, but will allow flexibility within that value, even if the +major and minor versions are both `0`. + +* `^1.2.x` := `>=1.2.0 <2.0.0` +* `^0.0.x` := `>=0.0.0 <0.1.0` +* `^0.0` := `>=0.0.0 <0.1.0` + +A missing `minor` and `patch` values will desugar to zero, but also +allow flexibility within those values, even if the major version is +zero. + +* `^1.x` := `>=1.0.0 <2.0.0` +* `^0.x` := `>=0.0.0 <1.0.0` + +### Range Grammar + +Putting all this together, here is a Backus-Naur grammar for ranges, +for the benefit of parser authors: + +```bnf +range-set ::= range ( logical-or range ) * +logical-or ::= ( ' ' ) * '||' ( ' ' ) * +range ::= hyphen | simple ( ' ' simple ) * | '' +hyphen ::= partial ' - ' partial +simple ::= primitive | partial | tilde | caret +primitive ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial +partial ::= xr ( '.' xr ( '.' xr qualifier ? )? )? +xr ::= 'x' | 'X' | '*' | nr +nr ::= '0' | ['1'-'9'] ( ['0'-'9'] ) * +tilde ::= '~' partial +caret ::= '^' partial +qualifier ::= ( '-' pre )? ( '+' build )? +pre ::= parts +build ::= parts +parts ::= part ( '.' part ) * +part ::= nr | [-0-9A-Za-z]+ +``` + +## Functions + +All methods and classes take a final `options` object argument. All +options in this object are `false` by default. The options supported +are: + +- `loose` Be more forgiving about not-quite-valid semver strings. + (Any resulting output will always be 100% strict compliant, of + course.) For backwards compatibility reasons, if the `options` + argument is a boolean value instead of an object, it is interpreted + to be the `loose` param. +- `includePrerelease` Set to suppress the [default + behavior](https://github.com/npm/node-semver#prerelease-tags) of + excluding prerelease tagged versions from ranges unless they are + explicitly opted into. + +Strict-mode Comparators and Ranges will be strict about the SemVer +strings that they parse. + +* `valid(v)`: Return the parsed version, or null if it's not valid. +* `inc(v, release)`: Return the version incremented by the release + type (`major`, `premajor`, `minor`, `preminor`, `patch`, + `prepatch`, or `prerelease`), or null if it's not valid + * `premajor` in one call will bump the version up to the next major + version and down to a prerelease of that major version. + `preminor`, and `prepatch` work the same way. + * If called from a non-prerelease version, the `prerelease` will work the + same as `prepatch`. It increments the patch version, then makes a + prerelease. If the input version is already a prerelease it simply + increments it. +* `prerelease(v)`: Returns an array of prerelease components, or null + if none exist. Example: `prerelease('1.2.3-alpha.1') -> ['alpha', 1]` +* `major(v)`: Return the major version number. +* `minor(v)`: Return the minor version number. +* `patch(v)`: Return the patch version number. +* `intersects(r1, r2, loose)`: Return true if the two supplied ranges + or comparators intersect. +* `parse(v)`: Attempt to parse a string as a semantic version, returning either + a `SemVer` object or `null`. + +### Comparison + +* `gt(v1, v2)`: `v1 > v2` +* `gte(v1, v2)`: `v1 >= v2` +* `lt(v1, v2)`: `v1 < v2` +* `lte(v1, v2)`: `v1 <= v2` +* `eq(v1, v2)`: `v1 == v2` This is true if they're logically equivalent, + even if they're not the exact same string. You already know how to + compare strings. +* `neq(v1, v2)`: `v1 != v2` The opposite of `eq`. +* `cmp(v1, comparator, v2)`: Pass in a comparison string, and it'll call + the corresponding function above. `"==="` and `"!=="` do simple + string comparison, but are included for completeness. Throws if an + invalid comparison string is provided. +* `compare(v1, v2)`: Return `0` if `v1 == v2`, or `1` if `v1` is greater, or `-1` if + `v2` is greater. Sorts in ascending order if passed to `Array.sort()`. +* `rcompare(v1, v2)`: The reverse of compare. Sorts an array of versions + in descending order when passed to `Array.sort()`. +* `diff(v1, v2)`: Returns difference between two versions by the release type + (`major`, `premajor`, `minor`, `preminor`, `patch`, `prepatch`, or `prerelease`), + or null if the versions are the same. + +### Comparators + +* `intersects(comparator)`: Return true if the comparators intersect + +### Ranges + +* `validRange(range)`: Return the valid range or null if it's not valid +* `satisfies(version, range)`: Return true if the version satisfies the + range. +* `maxSatisfying(versions, range)`: Return the highest version in the list + that satisfies the range, or `null` if none of them do. +* `minSatisfying(versions, range)`: Return the lowest version in the list + that satisfies the range, or `null` if none of them do. +* `minVersion(range)`: Return the lowest version that can possibly match + the given range. +* `gtr(version, range)`: Return `true` if version is greater than all the + versions possible in the range. +* `ltr(version, range)`: Return `true` if version is less than all the + versions possible in the range. +* `outside(version, range, hilo)`: Return true if the version is outside + the bounds of the range in either the high or low direction. The + `hilo` argument must be either the string `'>'` or `'<'`. (This is + the function called by `gtr` and `ltr`.) +* `intersects(range)`: Return true if any of the ranges comparators intersect + +Note that, since ranges may be non-contiguous, a version might not be +greater than a range, less than a range, *or* satisfy a range! For +example, the range `1.2 <1.2.9 || >2.0.0` would have a hole from `1.2.9` +until `2.0.0`, so the version `1.2.10` would not be greater than the +range (because `2.0.1` satisfies, which is higher), nor less than the +range (since `1.2.8` satisfies, which is lower), and it also does not +satisfy the range. + +If you want to know if a version satisfies or does not satisfy a +range, use the `satisfies(version, range)` function. + +### Coercion + +* `coerce(version)`: Coerces a string to semver if possible + +This aims to provide a very forgiving translation of a non-semver string to +semver. It looks for the first digit in a string, and consumes all +remaining characters which satisfy at least a partial semver (e.g., `1`, +`1.2`, `1.2.3`) up to the max permitted length (256 characters). Longer +versions are simply truncated (`4.6.3.9.2-alpha2` becomes `4.6.3`). All +surrounding text is simply ignored (`v3.4 replaces v3.3.1` becomes +`3.4.0`). Only text which lacks digits will fail coercion (`version one` +is not valid). The maximum length for any semver component considered for +coercion is 16 characters; longer components will be ignored +(`10000000000000000.4.7.4` becomes `4.7.4`). The maximum value for any +semver component is `Number.MAX_SAFE_INTEGER || (2**53 - 1)`; higher value +components are invalid (`9999999999999999.4.7.4` is likely invalid). diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/bin/semver b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/bin/semver new file mode 100644 index 0000000..801e77f --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/bin/semver @@ -0,0 +1,160 @@ +#!/usr/bin/env node +// Standalone semver comparison program. +// Exits successfully and prints matching version(s) if +// any supplied version is valid and passes all tests. + +var argv = process.argv.slice(2) + +var versions = [] + +var range = [] + +var inc = null + +var version = require('../package.json').version + +var loose = false + +var includePrerelease = false + +var coerce = false + +var identifier + +var semver = require('../semver') + +var reverse = false + +var options = {} + +main() + +function main () { + if (!argv.length) return help() + while (argv.length) { + var a = argv.shift() + var indexOfEqualSign = a.indexOf('=') + if (indexOfEqualSign !== -1) { + a = a.slice(0, indexOfEqualSign) + argv.unshift(a.slice(indexOfEqualSign + 1)) + } + switch (a) { + case '-rv': case '-rev': case '--rev': case '--reverse': + reverse = true + break + case '-l': case '--loose': + loose = true + break + case '-p': case '--include-prerelease': + includePrerelease = true + break + case '-v': case '--version': + versions.push(argv.shift()) + break + case '-i': case '--inc': case '--increment': + switch (argv[0]) { + case 'major': case 'minor': case 'patch': case 'prerelease': + case 'premajor': case 'preminor': case 'prepatch': + inc = argv.shift() + break + default: + inc = 'patch' + break + } + break + case '--preid': + identifier = argv.shift() + break + case '-r': case '--range': + range.push(argv.shift()) + break + case '-c': case '--coerce': + coerce = true + break + case '-h': case '--help': case '-?': + return help() + default: + versions.push(a) + break + } + } + + var options = { loose: loose, includePrerelease: includePrerelease } + + versions = versions.map(function (v) { + return coerce ? (semver.coerce(v) || { version: v }).version : v + }).filter(function (v) { + return semver.valid(v) + }) + if (!versions.length) return fail() + if (inc && (versions.length !== 1 || range.length)) { return failInc() } + + for (var i = 0, l = range.length; i < l; i++) { + versions = versions.filter(function (v) { + return semver.satisfies(v, range[i], options) + }) + if (!versions.length) return fail() + } + return success(versions) +} + +function failInc () { + console.error('--inc can only be used on a single version with no range') + fail() +} + +function fail () { process.exit(1) } + +function success () { + var compare = reverse ? 'rcompare' : 'compare' + versions.sort(function (a, b) { + return semver[compare](a, b, options) + }).map(function (v) { + return semver.clean(v, options) + }).map(function (v) { + return inc ? semver.inc(v, inc, options, identifier) : v + }).forEach(function (v, i, _) { console.log(v) }) +} + +function help () { + console.log(['SemVer ' + version, + '', + 'A JavaScript implementation of the https://semver.org/ specification', + 'Copyright Isaac Z. Schlueter', + '', + 'Usage: semver [options] [ [...]]', + 'Prints valid versions sorted by SemVer precedence', + '', + 'Options:', + '-r --range ', + ' Print versions that match the specified range.', + '', + '-i --increment []', + ' Increment a version by the specified level. Level can', + ' be one of: major, minor, patch, premajor, preminor,', + " prepatch, or prerelease. Default level is 'patch'.", + ' Only one version may be specified.', + '', + '--preid ', + ' Identifier to be used to prefix premajor, preminor,', + ' prepatch or prerelease version increments.', + '', + '-l --loose', + ' Interpret versions and ranges loosely', + '', + '-p --include-prerelease', + ' Always include prerelease versions in range matching', + '', + '-c --coerce', + ' Coerce a string into SemVer if possible', + ' (does not imply --loose)', + '', + 'Program exits successfully if any valid version satisfies', + 'all supplied ranges, and prints all satisfying versions.', + '', + 'If no satisfying versions are found, then exits failure.', + '', + 'Versions are printed in ascending order, so supplying', + 'multiple versions to the utility will just sort them.' + ].join('\n')) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/package.json new file mode 100644 index 0000000..ea70c0b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/package.json @@ -0,0 +1,60 @@ +{ + "_from": "semver@^5.6.0", + "_id": "semver@5.7.1", + "_inBundle": false, + "_integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "_location": "/semver", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "semver@^5.6.0", + "name": "semver", + "escapedName": "semver", + "rawSpec": "^5.6.0", + "saveSpec": null, + "fetchSpec": "^5.6.0" + }, + "_requiredBy": [ + "/jsonwebtoken" + ], + "_resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "_shasum": "a954f931aeba508d307bbf069eff0c01c96116f7", + "_spec": "semver@^5.6.0", + "_where": "D:\\xm\\online-code\\hellounicloud\\uni_modules\\uni-id-pages\\uniCloud\\cloudfunctions\\uni-id-co\\node_modules\\jsonwebtoken", + "bin": { + "semver": "bin/semver" + }, + "bugs": { + "url": "https://github.com/npm/node-semver/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "The semantic version parser used by npm.", + "devDependencies": { + "tap": "^13.0.0-rc.18" + }, + "files": [ + "bin", + "range.bnf", + "semver.js" + ], + "homepage": "https://github.com/npm/node-semver#readme", + "license": "ISC", + "main": "semver.js", + "name": "semver", + "repository": { + "type": "git", + "url": "git+https://github.com/npm/node-semver.git" + }, + "scripts": { + "postpublish": "git push origin --all; git push origin --tags", + "postversion": "npm publish", + "preversion": "npm test", + "test": "tap" + }, + "tap": { + "check-coverage": true + }, + "version": "5.7.1" +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/range.bnf b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/range.bnf new file mode 100644 index 0000000..d4c6ae0 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/range.bnf @@ -0,0 +1,16 @@ +range-set ::= range ( logical-or range ) * +logical-or ::= ( ' ' ) * '||' ( ' ' ) * +range ::= hyphen | simple ( ' ' simple ) * | '' +hyphen ::= partial ' - ' partial +simple ::= primitive | partial | tilde | caret +primitive ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial +partial ::= xr ( '.' xr ( '.' xr qualifier ? )? )? +xr ::= 'x' | 'X' | '*' | nr +nr ::= '0' | [1-9] ( [0-9] ) * +tilde ::= '~' partial +caret ::= '^' partial +qualifier ::= ( '-' pre )? ( '+' build )? +pre ::= parts +build ::= parts +parts ::= part ( '.' part ) * +part ::= nr | [-0-9A-Za-z]+ diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/semver.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/semver.js new file mode 100644 index 0000000..d315d5d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/semver/semver.js @@ -0,0 +1,1483 @@ +exports = module.exports = SemVer + +var debug +/* istanbul ignore next */ +if (typeof process === 'object' && + process.env && + process.env.NODE_DEBUG && + /\bsemver\b/i.test(process.env.NODE_DEBUG)) { + debug = function () { + var args = Array.prototype.slice.call(arguments, 0) + args.unshift('SEMVER') + console.log.apply(console, args) + } +} else { + debug = function () {} +} + +// Note: this is the semver.org version of the spec that it implements +// Not necessarily the package version of this code. +exports.SEMVER_SPEC_VERSION = '2.0.0' + +var MAX_LENGTH = 256 +var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || + /* istanbul ignore next */ 9007199254740991 + +// Max safe segment length for coercion. +var MAX_SAFE_COMPONENT_LENGTH = 16 + +// The actual regexps go on exports.re +var re = exports.re = [] +var src = exports.src = [] +var R = 0 + +// The following Regular Expressions can be used for tokenizing, +// validating, and parsing SemVer version strings. + +// ## Numeric Identifier +// A single `0`, or a non-zero digit followed by zero or more digits. + +var NUMERICIDENTIFIER = R++ +src[NUMERICIDENTIFIER] = '0|[1-9]\\d*' +var NUMERICIDENTIFIERLOOSE = R++ +src[NUMERICIDENTIFIERLOOSE] = '[0-9]+' + +// ## Non-numeric Identifier +// Zero or more digits, followed by a letter or hyphen, and then zero or +// more letters, digits, or hyphens. + +var NONNUMERICIDENTIFIER = R++ +src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*' + +// ## Main Version +// Three dot-separated numeric identifiers. + +var MAINVERSION = R++ +src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' + + '(' + src[NUMERICIDENTIFIER] + ')\\.' + + '(' + src[NUMERICIDENTIFIER] + ')' + +var MAINVERSIONLOOSE = R++ +src[MAINVERSIONLOOSE] = '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + + '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + + '(' + src[NUMERICIDENTIFIERLOOSE] + ')' + +// ## Pre-release Version Identifier +// A numeric identifier, or a non-numeric identifier. + +var PRERELEASEIDENTIFIER = R++ +src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] + + '|' + src[NONNUMERICIDENTIFIER] + ')' + +var PRERELEASEIDENTIFIERLOOSE = R++ +src[PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[NUMERICIDENTIFIERLOOSE] + + '|' + src[NONNUMERICIDENTIFIER] + ')' + +// ## Pre-release Version +// Hyphen, followed by one or more dot-separated pre-release version +// identifiers. + +var PRERELEASE = R++ +src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] + + '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))' + +var PRERELEASELOOSE = R++ +src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] + + '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))' + +// ## Build Metadata Identifier +// Any combination of digits, letters, or hyphens. + +var BUILDIDENTIFIER = R++ +src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+' + +// ## Build Metadata +// Plus sign, followed by one or more period-separated build metadata +// identifiers. + +var BUILD = R++ +src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] + + '(?:\\.' + src[BUILDIDENTIFIER] + ')*))' + +// ## Full Version String +// A main version, followed optionally by a pre-release version and +// build metadata. + +// Note that the only major, minor, patch, and pre-release sections of +// the version string are capturing groups. The build metadata is not a +// capturing group, because it should not ever be used in version +// comparison. + +var FULL = R++ +var FULLPLAIN = 'v?' + src[MAINVERSION] + + src[PRERELEASE] + '?' + + src[BUILD] + '?' + +src[FULL] = '^' + FULLPLAIN + '$' + +// like full, but allows v1.2.3 and =1.2.3, which people do sometimes. +// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty +// common in the npm registry. +var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] + + src[PRERELEASELOOSE] + '?' + + src[BUILD] + '?' + +var LOOSE = R++ +src[LOOSE] = '^' + LOOSEPLAIN + '$' + +var GTLT = R++ +src[GTLT] = '((?:<|>)?=?)' + +// Something like "2.*" or "1.2.x". +// Note that "x.x" is a valid xRange identifer, meaning "any version" +// Only the first item is strictly required. +var XRANGEIDENTIFIERLOOSE = R++ +src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*' +var XRANGEIDENTIFIER = R++ +src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*' + +var XRANGEPLAIN = R++ +src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + + '(?:' + src[PRERELEASE] + ')?' + + src[BUILD] + '?' + + ')?)?' + +var XRANGEPLAINLOOSE = R++ +src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + + '(?:' + src[PRERELEASELOOSE] + ')?' + + src[BUILD] + '?' + + ')?)?' + +var XRANGE = R++ +src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$' +var XRANGELOOSE = R++ +src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$' + +// Coercion. +// Extract anything that could conceivably be a part of a valid semver +var COERCE = R++ +src[COERCE] = '(?:^|[^\\d])' + + '(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '})' + + '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + + '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + + '(?:$|[^\\d])' + +// Tilde ranges. +// Meaning is "reasonably at or greater than" +var LONETILDE = R++ +src[LONETILDE] = '(?:~>?)' + +var TILDETRIM = R++ +src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+' +re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g') +var tildeTrimReplace = '$1~' + +var TILDE = R++ +src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$' +var TILDELOOSE = R++ +src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$' + +// Caret ranges. +// Meaning is "at least and backwards compatible with" +var LONECARET = R++ +src[LONECARET] = '(?:\\^)' + +var CARETTRIM = R++ +src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+' +re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g') +var caretTrimReplace = '$1^' + +var CARET = R++ +src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$' +var CARETLOOSE = R++ +src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$' + +// A simple gt/lt/eq thing, or just "" to indicate "any version" +var COMPARATORLOOSE = R++ +src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$' +var COMPARATOR = R++ +src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$' + +// An expression to strip any whitespace between the gtlt and the thing +// it modifies, so that `> 1.2.3` ==> `>1.2.3` +var COMPARATORTRIM = R++ +src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] + + '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')' + +// this one has to use the /g flag +re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g') +var comparatorTrimReplace = '$1$2$3' + +// Something like `1.2.3 - 1.2.4` +// Note that these all use the loose form, because they'll be +// checked against either the strict or loose comparator form +// later. +var HYPHENRANGE = R++ +src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' + + '\\s+-\\s+' + + '(' + src[XRANGEPLAIN] + ')' + + '\\s*$' + +var HYPHENRANGELOOSE = R++ +src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' + + '\\s+-\\s+' + + '(' + src[XRANGEPLAINLOOSE] + ')' + + '\\s*$' + +// Star ranges basically just allow anything at all. +var STAR = R++ +src[STAR] = '(<|>)?=?\\s*\\*' + +// Compile to actual regexp objects. +// All are flag-free, unless they were created above with a flag. +for (var i = 0; i < R; i++) { + debug(i, src[i]) + if (!re[i]) { + re[i] = new RegExp(src[i]) + } +} + +exports.parse = parse +function parse (version, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } + + if (version instanceof SemVer) { + return version + } + + if (typeof version !== 'string') { + return null + } + + if (version.length > MAX_LENGTH) { + return null + } + + var r = options.loose ? re[LOOSE] : re[FULL] + if (!r.test(version)) { + return null + } + + try { + return new SemVer(version, options) + } catch (er) { + return null + } +} + +exports.valid = valid +function valid (version, options) { + var v = parse(version, options) + return v ? v.version : null +} + +exports.clean = clean +function clean (version, options) { + var s = parse(version.trim().replace(/^[=v]+/, ''), options) + return s ? s.version : null +} + +exports.SemVer = SemVer + +function SemVer (version, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } + if (version instanceof SemVer) { + if (version.loose === options.loose) { + return version + } else { + version = version.version + } + } else if (typeof version !== 'string') { + throw new TypeError('Invalid Version: ' + version) + } + + if (version.length > MAX_LENGTH) { + throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters') + } + + if (!(this instanceof SemVer)) { + return new SemVer(version, options) + } + + debug('SemVer', version, options) + this.options = options + this.loose = !!options.loose + + var m = version.trim().match(options.loose ? re[LOOSE] : re[FULL]) + + if (!m) { + throw new TypeError('Invalid Version: ' + version) + } + + this.raw = version + + // these are actually numbers + this.major = +m[1] + this.minor = +m[2] + this.patch = +m[3] + + if (this.major > MAX_SAFE_INTEGER || this.major < 0) { + throw new TypeError('Invalid major version') + } + + if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) { + throw new TypeError('Invalid minor version') + } + + if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) { + throw new TypeError('Invalid patch version') + } + + // numberify any prerelease numeric ids + if (!m[4]) { + this.prerelease = [] + } else { + this.prerelease = m[4].split('.').map(function (id) { + if (/^[0-9]+$/.test(id)) { + var num = +id + if (num >= 0 && num < MAX_SAFE_INTEGER) { + return num + } + } + return id + }) + } + + this.build = m[5] ? m[5].split('.') : [] + this.format() +} + +SemVer.prototype.format = function () { + this.version = this.major + '.' + this.minor + '.' + this.patch + if (this.prerelease.length) { + this.version += '-' + this.prerelease.join('.') + } + return this.version +} + +SemVer.prototype.toString = function () { + return this.version +} + +SemVer.prototype.compare = function (other) { + debug('SemVer.compare', this.version, this.options, other) + if (!(other instanceof SemVer)) { + other = new SemVer(other, this.options) + } + + return this.compareMain(other) || this.comparePre(other) +} + +SemVer.prototype.compareMain = function (other) { + if (!(other instanceof SemVer)) { + other = new SemVer(other, this.options) + } + + return compareIdentifiers(this.major, other.major) || + compareIdentifiers(this.minor, other.minor) || + compareIdentifiers(this.patch, other.patch) +} + +SemVer.prototype.comparePre = function (other) { + if (!(other instanceof SemVer)) { + other = new SemVer(other, this.options) + } + + // NOT having a prerelease is > having one + if (this.prerelease.length && !other.prerelease.length) { + return -1 + } else if (!this.prerelease.length && other.prerelease.length) { + return 1 + } else if (!this.prerelease.length && !other.prerelease.length) { + return 0 + } + + var i = 0 + do { + var a = this.prerelease[i] + var b = other.prerelease[i] + debug('prerelease compare', i, a, b) + if (a === undefined && b === undefined) { + return 0 + } else if (b === undefined) { + return 1 + } else if (a === undefined) { + return -1 + } else if (a === b) { + continue + } else { + return compareIdentifiers(a, b) + } + } while (++i) +} + +// preminor will bump the version up to the next minor release, and immediately +// down to pre-release. premajor and prepatch work the same way. +SemVer.prototype.inc = function (release, identifier) { + switch (release) { + case 'premajor': + this.prerelease.length = 0 + this.patch = 0 + this.minor = 0 + this.major++ + this.inc('pre', identifier) + break + case 'preminor': + this.prerelease.length = 0 + this.patch = 0 + this.minor++ + this.inc('pre', identifier) + break + case 'prepatch': + // If this is already a prerelease, it will bump to the next version + // drop any prereleases that might already exist, since they are not + // relevant at this point. + this.prerelease.length = 0 + this.inc('patch', identifier) + this.inc('pre', identifier) + break + // If the input is a non-prerelease version, this acts the same as + // prepatch. + case 'prerelease': + if (this.prerelease.length === 0) { + this.inc('patch', identifier) + } + this.inc('pre', identifier) + break + + case 'major': + // If this is a pre-major version, bump up to the same major version. + // Otherwise increment major. + // 1.0.0-5 bumps to 1.0.0 + // 1.1.0 bumps to 2.0.0 + if (this.minor !== 0 || + this.patch !== 0 || + this.prerelease.length === 0) { + this.major++ + } + this.minor = 0 + this.patch = 0 + this.prerelease = [] + break + case 'minor': + // If this is a pre-minor version, bump up to the same minor version. + // Otherwise increment minor. + // 1.2.0-5 bumps to 1.2.0 + // 1.2.1 bumps to 1.3.0 + if (this.patch !== 0 || this.prerelease.length === 0) { + this.minor++ + } + this.patch = 0 + this.prerelease = [] + break + case 'patch': + // If this is not a pre-release version, it will increment the patch. + // If it is a pre-release it will bump up to the same patch version. + // 1.2.0-5 patches to 1.2.0 + // 1.2.0 patches to 1.2.1 + if (this.prerelease.length === 0) { + this.patch++ + } + this.prerelease = [] + break + // This probably shouldn't be used publicly. + // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction. + case 'pre': + if (this.prerelease.length === 0) { + this.prerelease = [0] + } else { + var i = this.prerelease.length + while (--i >= 0) { + if (typeof this.prerelease[i] === 'number') { + this.prerelease[i]++ + i = -2 + } + } + if (i === -1) { + // didn't increment anything + this.prerelease.push(0) + } + } + if (identifier) { + // 1.2.0-beta.1 bumps to 1.2.0-beta.2, + // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 + if (this.prerelease[0] === identifier) { + if (isNaN(this.prerelease[1])) { + this.prerelease = [identifier, 0] + } + } else { + this.prerelease = [identifier, 0] + } + } + break + + default: + throw new Error('invalid increment argument: ' + release) + } + this.format() + this.raw = this.version + return this +} + +exports.inc = inc +function inc (version, release, loose, identifier) { + if (typeof (loose) === 'string') { + identifier = loose + loose = undefined + } + + try { + return new SemVer(version, loose).inc(release, identifier).version + } catch (er) { + return null + } +} + +exports.diff = diff +function diff (version1, version2) { + if (eq(version1, version2)) { + return null + } else { + var v1 = parse(version1) + var v2 = parse(version2) + var prefix = '' + if (v1.prerelease.length || v2.prerelease.length) { + prefix = 'pre' + var defaultResult = 'prerelease' + } + for (var key in v1) { + if (key === 'major' || key === 'minor' || key === 'patch') { + if (v1[key] !== v2[key]) { + return prefix + key + } + } + } + return defaultResult // may be undefined + } +} + +exports.compareIdentifiers = compareIdentifiers + +var numeric = /^[0-9]+$/ +function compareIdentifiers (a, b) { + var anum = numeric.test(a) + var bnum = numeric.test(b) + + if (anum && bnum) { + a = +a + b = +b + } + + return a === b ? 0 + : (anum && !bnum) ? -1 + : (bnum && !anum) ? 1 + : a < b ? -1 + : 1 +} + +exports.rcompareIdentifiers = rcompareIdentifiers +function rcompareIdentifiers (a, b) { + return compareIdentifiers(b, a) +} + +exports.major = major +function major (a, loose) { + return new SemVer(a, loose).major +} + +exports.minor = minor +function minor (a, loose) { + return new SemVer(a, loose).minor +} + +exports.patch = patch +function patch (a, loose) { + return new SemVer(a, loose).patch +} + +exports.compare = compare +function compare (a, b, loose) { + return new SemVer(a, loose).compare(new SemVer(b, loose)) +} + +exports.compareLoose = compareLoose +function compareLoose (a, b) { + return compare(a, b, true) +} + +exports.rcompare = rcompare +function rcompare (a, b, loose) { + return compare(b, a, loose) +} + +exports.sort = sort +function sort (list, loose) { + return list.sort(function (a, b) { + return exports.compare(a, b, loose) + }) +} + +exports.rsort = rsort +function rsort (list, loose) { + return list.sort(function (a, b) { + return exports.rcompare(a, b, loose) + }) +} + +exports.gt = gt +function gt (a, b, loose) { + return compare(a, b, loose) > 0 +} + +exports.lt = lt +function lt (a, b, loose) { + return compare(a, b, loose) < 0 +} + +exports.eq = eq +function eq (a, b, loose) { + return compare(a, b, loose) === 0 +} + +exports.neq = neq +function neq (a, b, loose) { + return compare(a, b, loose) !== 0 +} + +exports.gte = gte +function gte (a, b, loose) { + return compare(a, b, loose) >= 0 +} + +exports.lte = lte +function lte (a, b, loose) { + return compare(a, b, loose) <= 0 +} + +exports.cmp = cmp +function cmp (a, op, b, loose) { + switch (op) { + case '===': + if (typeof a === 'object') + a = a.version + if (typeof b === 'object') + b = b.version + return a === b + + case '!==': + if (typeof a === 'object') + a = a.version + if (typeof b === 'object') + b = b.version + return a !== b + + case '': + case '=': + case '==': + return eq(a, b, loose) + + case '!=': + return neq(a, b, loose) + + case '>': + return gt(a, b, loose) + + case '>=': + return gte(a, b, loose) + + case '<': + return lt(a, b, loose) + + case '<=': + return lte(a, b, loose) + + default: + throw new TypeError('Invalid operator: ' + op) + } +} + +exports.Comparator = Comparator +function Comparator (comp, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } + + if (comp instanceof Comparator) { + if (comp.loose === !!options.loose) { + return comp + } else { + comp = comp.value + } + } + + if (!(this instanceof Comparator)) { + return new Comparator(comp, options) + } + + debug('comparator', comp, options) + this.options = options + this.loose = !!options.loose + this.parse(comp) + + if (this.semver === ANY) { + this.value = '' + } else { + this.value = this.operator + this.semver.version + } + + debug('comp', this) +} + +var ANY = {} +Comparator.prototype.parse = function (comp) { + var r = this.options.loose ? re[COMPARATORLOOSE] : re[COMPARATOR] + var m = comp.match(r) + + if (!m) { + throw new TypeError('Invalid comparator: ' + comp) + } + + this.operator = m[1] + if (this.operator === '=') { + this.operator = '' + } + + // if it literally is just '>' or '' then allow anything. + if (!m[2]) { + this.semver = ANY + } else { + this.semver = new SemVer(m[2], this.options.loose) + } +} + +Comparator.prototype.toString = function () { + return this.value +} + +Comparator.prototype.test = function (version) { + debug('Comparator.test', version, this.options.loose) + + if (this.semver === ANY) { + return true + } + + if (typeof version === 'string') { + version = new SemVer(version, this.options) + } + + return cmp(version, this.operator, this.semver, this.options) +} + +Comparator.prototype.intersects = function (comp, options) { + if (!(comp instanceof Comparator)) { + throw new TypeError('a Comparator is required') + } + + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } + + var rangeTmp + + if (this.operator === '') { + rangeTmp = new Range(comp.value, options) + return satisfies(this.value, rangeTmp, options) + } else if (comp.operator === '') { + rangeTmp = new Range(this.value, options) + return satisfies(comp.semver, rangeTmp, options) + } + + var sameDirectionIncreasing = + (this.operator === '>=' || this.operator === '>') && + (comp.operator === '>=' || comp.operator === '>') + var sameDirectionDecreasing = + (this.operator === '<=' || this.operator === '<') && + (comp.operator === '<=' || comp.operator === '<') + var sameSemVer = this.semver.version === comp.semver.version + var differentDirectionsInclusive = + (this.operator === '>=' || this.operator === '<=') && + (comp.operator === '>=' || comp.operator === '<=') + var oppositeDirectionsLessThan = + cmp(this.semver, '<', comp.semver, options) && + ((this.operator === '>=' || this.operator === '>') && + (comp.operator === '<=' || comp.operator === '<')) + var oppositeDirectionsGreaterThan = + cmp(this.semver, '>', comp.semver, options) && + ((this.operator === '<=' || this.operator === '<') && + (comp.operator === '>=' || comp.operator === '>')) + + return sameDirectionIncreasing || sameDirectionDecreasing || + (sameSemVer && differentDirectionsInclusive) || + oppositeDirectionsLessThan || oppositeDirectionsGreaterThan +} + +exports.Range = Range +function Range (range, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } + + if (range instanceof Range) { + if (range.loose === !!options.loose && + range.includePrerelease === !!options.includePrerelease) { + return range + } else { + return new Range(range.raw, options) + } + } + + if (range instanceof Comparator) { + return new Range(range.value, options) + } + + if (!(this instanceof Range)) { + return new Range(range, options) + } + + this.options = options + this.loose = !!options.loose + this.includePrerelease = !!options.includePrerelease + + // First, split based on boolean or || + this.raw = range + this.set = range.split(/\s*\|\|\s*/).map(function (range) { + return this.parseRange(range.trim()) + }, this).filter(function (c) { + // throw out any that are not relevant for whatever reason + return c.length + }) + + if (!this.set.length) { + throw new TypeError('Invalid SemVer Range: ' + range) + } + + this.format() +} + +Range.prototype.format = function () { + this.range = this.set.map(function (comps) { + return comps.join(' ').trim() + }).join('||').trim() + return this.range +} + +Range.prototype.toString = function () { + return this.range +} + +Range.prototype.parseRange = function (range) { + var loose = this.options.loose + range = range.trim() + // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4` + var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE] + range = range.replace(hr, hyphenReplace) + debug('hyphen replace', range) + // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` + range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace) + debug('comparator trim', range, re[COMPARATORTRIM]) + + // `~ 1.2.3` => `~1.2.3` + range = range.replace(re[TILDETRIM], tildeTrimReplace) + + // `^ 1.2.3` => `^1.2.3` + range = range.replace(re[CARETTRIM], caretTrimReplace) + + // normalize spaces + range = range.split(/\s+/).join(' ') + + // At this point, the range is completely trimmed and + // ready to be split into comparators. + + var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR] + var set = range.split(' ').map(function (comp) { + return parseComparator(comp, this.options) + }, this).join(' ').split(/\s+/) + if (this.options.loose) { + // in loose mode, throw out any that are not valid comparators + set = set.filter(function (comp) { + return !!comp.match(compRe) + }) + } + set = set.map(function (comp) { + return new Comparator(comp, this.options) + }, this) + + return set +} + +Range.prototype.intersects = function (range, options) { + if (!(range instanceof Range)) { + throw new TypeError('a Range is required') + } + + return this.set.some(function (thisComparators) { + return thisComparators.every(function (thisComparator) { + return range.set.some(function (rangeComparators) { + return rangeComparators.every(function (rangeComparator) { + return thisComparator.intersects(rangeComparator, options) + }) + }) + }) + }) +} + +// Mostly just for testing and legacy API reasons +exports.toComparators = toComparators +function toComparators (range, options) { + return new Range(range, options).set.map(function (comp) { + return comp.map(function (c) { + return c.value + }).join(' ').trim().split(' ') + }) +} + +// comprised of xranges, tildes, stars, and gtlt's at this point. +// already replaced the hyphen ranges +// turn into a set of JUST comparators. +function parseComparator (comp, options) { + debug('comp', comp, options) + comp = replaceCarets(comp, options) + debug('caret', comp) + comp = replaceTildes(comp, options) + debug('tildes', comp) + comp = replaceXRanges(comp, options) + debug('xrange', comp) + comp = replaceStars(comp, options) + debug('stars', comp) + return comp +} + +function isX (id) { + return !id || id.toLowerCase() === 'x' || id === '*' +} + +// ~, ~> --> * (any, kinda silly) +// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0 +// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0 +// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0 +// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0 +// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0 +function replaceTildes (comp, options) { + return comp.trim().split(/\s+/).map(function (comp) { + return replaceTilde(comp, options) + }).join(' ') +} + +function replaceTilde (comp, options) { + var r = options.loose ? re[TILDELOOSE] : re[TILDE] + return comp.replace(r, function (_, M, m, p, pr) { + debug('tilde', comp, _, M, m, p, pr) + var ret + + if (isX(M)) { + ret = '' + } else if (isX(m)) { + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0' + } else if (isX(p)) { + // ~1.2 == >=1.2.0 <1.3.0 + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0' + } else if (pr) { + debug('replaceTilde pr', pr) + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + M + '.' + (+m + 1) + '.0' + } else { + // ~1.2.3 == >=1.2.3 <1.3.0 + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + (+m + 1) + '.0' + } + + debug('tilde return', ret) + return ret + }) +} + +// ^ --> * (any, kinda silly) +// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0 +// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0 +// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0 +// ^1.2.3 --> >=1.2.3 <2.0.0 +// ^1.2.0 --> >=1.2.0 <2.0.0 +function replaceCarets (comp, options) { + return comp.trim().split(/\s+/).map(function (comp) { + return replaceCaret(comp, options) + }).join(' ') +} + +function replaceCaret (comp, options) { + debug('caret', comp, options) + var r = options.loose ? re[CARETLOOSE] : re[CARET] + return comp.replace(r, function (_, M, m, p, pr) { + debug('caret', comp, _, M, m, p, pr) + var ret + + if (isX(M)) { + ret = '' + } else if (isX(m)) { + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0' + } else if (isX(p)) { + if (M === '0') { + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0' + } else { + ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0' + } + } else if (pr) { + debug('replaceCaret pr', pr) + if (M === '0') { + if (m === '0') { + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + M + '.' + m + '.' + (+p + 1) + } else { + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + M + '.' + (+m + 1) + '.0' + } + } else { + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + (+M + 1) + '.0.0' + } + } else { + debug('no pr') + if (M === '0') { + if (m === '0') { + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + m + '.' + (+p + 1) + } else { + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + (+m + 1) + '.0' + } + } else { + ret = '>=' + M + '.' + m + '.' + p + + ' <' + (+M + 1) + '.0.0' + } + } + + debug('caret return', ret) + return ret + }) +} + +function replaceXRanges (comp, options) { + debug('replaceXRanges', comp, options) + return comp.split(/\s+/).map(function (comp) { + return replaceXRange(comp, options) + }).join(' ') +} + +function replaceXRange (comp, options) { + comp = comp.trim() + var r = options.loose ? re[XRANGELOOSE] : re[XRANGE] + return comp.replace(r, function (ret, gtlt, M, m, p, pr) { + debug('xRange', comp, ret, gtlt, M, m, p, pr) + var xM = isX(M) + var xm = xM || isX(m) + var xp = xm || isX(p) + var anyX = xp + + if (gtlt === '=' && anyX) { + gtlt = '' + } + + if (xM) { + if (gtlt === '>' || gtlt === '<') { + // nothing is allowed + ret = '<0.0.0' + } else { + // nothing is forbidden + ret = '*' + } + } else if (gtlt && anyX) { + // we know patch is an x, because we have any x at all. + // replace X with 0 + if (xm) { + m = 0 + } + p = 0 + + if (gtlt === '>') { + // >1 => >=2.0.0 + // >1.2 => >=1.3.0 + // >1.2.3 => >= 1.2.4 + gtlt = '>=' + if (xm) { + M = +M + 1 + m = 0 + p = 0 + } else { + m = +m + 1 + p = 0 + } + } else if (gtlt === '<=') { + // <=0.7.x is actually <0.8.0, since any 0.7.x should + // pass. Similarly, <=7.x is actually <8.0.0, etc. + gtlt = '<' + if (xm) { + M = +M + 1 + } else { + m = +m + 1 + } + } + + ret = gtlt + M + '.' + m + '.' + p + } else if (xm) { + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0' + } else if (xp) { + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0' + } + + debug('xRange return', ret) + + return ret + }) +} + +// Because * is AND-ed with everything else in the comparator, +// and '' means "any version", just remove the *s entirely. +function replaceStars (comp, options) { + debug('replaceStars', comp, options) + // Looseness is ignored here. star is always as loose as it gets! + return comp.trim().replace(re[STAR], '') +} + +// This function is passed to string.replace(re[HYPHENRANGE]) +// M, m, patch, prerelease, build +// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5 +// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do +// 1.2 - 3.4 => >=1.2.0 <3.5.0 +function hyphenReplace ($0, + from, fM, fm, fp, fpr, fb, + to, tM, tm, tp, tpr, tb) { + if (isX(fM)) { + from = '' + } else if (isX(fm)) { + from = '>=' + fM + '.0.0' + } else if (isX(fp)) { + from = '>=' + fM + '.' + fm + '.0' + } else { + from = '>=' + from + } + + if (isX(tM)) { + to = '' + } else if (isX(tm)) { + to = '<' + (+tM + 1) + '.0.0' + } else if (isX(tp)) { + to = '<' + tM + '.' + (+tm + 1) + '.0' + } else if (tpr) { + to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr + } else { + to = '<=' + to + } + + return (from + ' ' + to).trim() +} + +// if ANY of the sets match ALL of its comparators, then pass +Range.prototype.test = function (version) { + if (!version) { + return false + } + + if (typeof version === 'string') { + version = new SemVer(version, this.options) + } + + for (var i = 0; i < this.set.length; i++) { + if (testSet(this.set[i], version, this.options)) { + return true + } + } + return false +} + +function testSet (set, version, options) { + for (var i = 0; i < set.length; i++) { + if (!set[i].test(version)) { + return false + } + } + + if (version.prerelease.length && !options.includePrerelease) { + // Find the set of versions that are allowed to have prereleases + // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0 + // That should allow `1.2.3-pr.2` to pass. + // However, `1.2.4-alpha.notready` should NOT be allowed, + // even though it's within the range set by the comparators. + for (i = 0; i < set.length; i++) { + debug(set[i].semver) + if (set[i].semver === ANY) { + continue + } + + if (set[i].semver.prerelease.length > 0) { + var allowed = set[i].semver + if (allowed.major === version.major && + allowed.minor === version.minor && + allowed.patch === version.patch) { + return true + } + } + } + + // Version has a -pre, but it's not one of the ones we like. + return false + } + + return true +} + +exports.satisfies = satisfies +function satisfies (version, range, options) { + try { + range = new Range(range, options) + } catch (er) { + return false + } + return range.test(version) +} + +exports.maxSatisfying = maxSatisfying +function maxSatisfying (versions, range, options) { + var max = null + var maxSV = null + try { + var rangeObj = new Range(range, options) + } catch (er) { + return null + } + versions.forEach(function (v) { + if (rangeObj.test(v)) { + // satisfies(v, range, options) + if (!max || maxSV.compare(v) === -1) { + // compare(max, v, true) + max = v + maxSV = new SemVer(max, options) + } + } + }) + return max +} + +exports.minSatisfying = minSatisfying +function minSatisfying (versions, range, options) { + var min = null + var minSV = null + try { + var rangeObj = new Range(range, options) + } catch (er) { + return null + } + versions.forEach(function (v) { + if (rangeObj.test(v)) { + // satisfies(v, range, options) + if (!min || minSV.compare(v) === 1) { + // compare(min, v, true) + min = v + minSV = new SemVer(min, options) + } + } + }) + return min +} + +exports.minVersion = minVersion +function minVersion (range, loose) { + range = new Range(range, loose) + + var minver = new SemVer('0.0.0') + if (range.test(minver)) { + return minver + } + + minver = new SemVer('0.0.0-0') + if (range.test(minver)) { + return minver + } + + minver = null + for (var i = 0; i < range.set.length; ++i) { + var comparators = range.set[i] + + comparators.forEach(function (comparator) { + // Clone to avoid manipulating the comparator's semver object. + var compver = new SemVer(comparator.semver.version) + switch (comparator.operator) { + case '>': + if (compver.prerelease.length === 0) { + compver.patch++ + } else { + compver.prerelease.push(0) + } + compver.raw = compver.format() + /* fallthrough */ + case '': + case '>=': + if (!minver || gt(minver, compver)) { + minver = compver + } + break + case '<': + case '<=': + /* Ignore maximum versions */ + break + /* istanbul ignore next */ + default: + throw new Error('Unexpected operation: ' + comparator.operator) + } + }) + } + + if (minver && range.test(minver)) { + return minver + } + + return null +} + +exports.validRange = validRange +function validRange (range, options) { + try { + // Return '*' instead of '' so that truthiness works. + // This will throw if it's invalid anyway + return new Range(range, options).range || '*' + } catch (er) { + return null + } +} + +// Determine if version is less than all the versions possible in the range +exports.ltr = ltr +function ltr (version, range, options) { + return outside(version, range, '<', options) +} + +// Determine if version is greater than all the versions possible in the range. +exports.gtr = gtr +function gtr (version, range, options) { + return outside(version, range, '>', options) +} + +exports.outside = outside +function outside (version, range, hilo, options) { + version = new SemVer(version, options) + range = new Range(range, options) + + var gtfn, ltefn, ltfn, comp, ecomp + switch (hilo) { + case '>': + gtfn = gt + ltefn = lte + ltfn = lt + comp = '>' + ecomp = '>=' + break + case '<': + gtfn = lt + ltefn = gte + ltfn = gt + comp = '<' + ecomp = '<=' + break + default: + throw new TypeError('Must provide a hilo val of "<" or ">"') + } + + // If it satisifes the range it is not outside + if (satisfies(version, range, options)) { + return false + } + + // From now on, variable terms are as if we're in "gtr" mode. + // but note that everything is flipped for the "ltr" function. + + for (var i = 0; i < range.set.length; ++i) { + var comparators = range.set[i] + + var high = null + var low = null + + comparators.forEach(function (comparator) { + if (comparator.semver === ANY) { + comparator = new Comparator('>=0.0.0') + } + high = high || comparator + low = low || comparator + if (gtfn(comparator.semver, high.semver, options)) { + high = comparator + } else if (ltfn(comparator.semver, low.semver, options)) { + low = comparator + } + }) + + // If the edge version comparator has a operator then our version + // isn't outside it + if (high.operator === comp || high.operator === ecomp) { + return false + } + + // If the lowest version comparator has an operator and our version + // is less than it then it isn't higher than the range + if ((!low.operator || low.operator === comp) && + ltefn(version, low.semver)) { + return false + } else if (low.operator === ecomp && ltfn(version, low.semver)) { + return false + } + } + return true +} + +exports.prerelease = prerelease +function prerelease (version, options) { + var parsed = parse(version, options) + return (parsed && parsed.prerelease.length) ? parsed.prerelease : null +} + +exports.intersects = intersects +function intersects (r1, r2, options) { + r1 = new Range(r1, options) + r2 = new Range(r2, options) + return r1.intersects(r2) +} + +exports.coerce = coerce +function coerce (version) { + if (version instanceof SemVer) { + return version + } + + if (typeof version !== 'string') { + return null + } + + var match = version.match(re[COERCE]) + + if (match == null) { + return null + } + + return parse(match[1] + + '.' + (match[2] || '0') + + '.' + (match[3] || '0')) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/LICENSE.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/LICENSE.md new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/LICENSE.md @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/fonts/font.ttf b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/fonts/font.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a60ce88613704bc7fe02dbff52043c3757a0c9d7 GIT binary patch literal 7080 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 literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/index.js new file mode 100644 index 0000000..b170e62 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/index.js @@ -0,0 +1 @@ +"use strict";var e=require("assert"),t=require("path");function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var o=n(e),r=n(t);const s={10001:"uni-captcha-create-fail",10002:"uni-captcha-verify-fail",10003:"uni-captcha-refresh-fail",10101:"uni-captcha-deviceId-empty",10102:"uni-captcha-text-required",10103:"uni-captcha-verify-overdue",10104:"uni-captcha-verify-fail",50403:"uni-captcha-interior-fail"};function a(e){const t=.2*Math.random()-.1;switch(e.type){case"M":case"L":e.x+=t,e.y+=t;break;case"Q":case"C":e.x+=t,e.y+=t,e.x1+=t,e.y1+=t}return e}function i(e,t,n,o,r,s,a){let i,l,c,u,p,h;if(e<=0||e>=1)throw RangeError("spliteCurveAt requires position > 0 && position < 1");return u=[],p=0,i={},l={},c={},i.x=t,i.y=n,l.x=o,l.y=r,c.x=s,c.y=a,h=e,u[p++]=i.x,u[p++]=i.y,u[p++]=i.x+=(l.x-i.x)*h,u[p++]=i.y+=(l.y-i.y)*h,l.x+=(c.x-l.x)*h,l.y+=(c.y-l.y)*h,u[p++]=i.x+(l.x-i.x)*h,u[p++]=i.y+(l.y-i.y)*h,u[p++]=l.x,u[p++]=l.y,u[p++]=c.x,u[p++]=c.y,u}function l(e,t){return Math.random()*(t-e)+e}var c=function(e,t){const n=e[0];o.default(n,"expect a string");const r=t.fontSize,s=r/t.font.unitsPerEm,c=t.font.charToGlyph(n),u=c.advanceWidth?c.advanceWidth*s:0,p=t.x-u/2,h=(t.ascender+t.descender)*s,f=t.y+h/2,d=c.getPath(p,f,r);d.commands.forEach(a),d.commands=function(e,t){const n=[];for(let o=0;ot.truncateLineProbability){const e=l(-.1,.1);n.push(r),n.push({type:"L",x:(r.x+s.x)/2+e,y:(r.y+s.y)/2+e})}else n.push(r)}else if("Q"===r.type&&o>=1){const s=e[o-1];if(("L"===s.type||"M"===s.type)&&Math.random()>t.truncateCurveProbability){const e=s.x,o=s.y,a=l(-.1,.1),c=r.x1+a,u=r.y1+a,p=r.x+a,h=r.y+a,f=i(l(t.truncateCurvePositionMin,t.truncateCurvePositionMax),e,o,c,u,p,h),d={type:"Q",x1:f[2],y1:f[3],x:f[4],y:f[5]},g={type:"L",x:f[4],y:f[5]},m={type:"Q",x1:f[6],y1:f[7],x:f[8],y:f[9]},y={type:"L",x:f[8],y:f[9]};n.push(d),n.push(g),n.push(m),n.push(y)}}else n.push(r)}return n}(d.commands,t);return d.toPathData()};function u(){this.table=new Uint16Array(16),this.trans=new Uint16Array(288)}function p(e,t){this.source=e,this.sourceIndex=0,this.tag=0,this.bitcount=0,this.dest=t,this.destLen=0,this.ltree=new u,this.dtree=new u}var h=new u,f=new u,d=new Uint8Array(30),g=new Uint16Array(30),m=new Uint8Array(30),y=new Uint16Array(30),v=new Uint8Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),b=new u,S=new Uint8Array(320);function x(e,t,n,o){var r,s;for(r=0;r>>=1,t}function O(e,t,n){if(!t)return n;for(;e.bitcount<24;)e.tag|=e.source[e.sourceIndex++]<>>16-t;return e.tag>>>=t,e.bitcount-=t,o+n}function w(e,t){for(;e.bitcount<24;)e.tag|=e.source[e.sourceIndex++]<>>=1,++r,n+=t.table[r],o-=t.table[r]}while(o>=0);return e.tag=s,e.bitcount-=r,t.trans[n+o]}function k(e,t,n){var o,r,s,a,i,l;for(o=O(e,5,257),r=O(e,5,1),s=O(e,4,4),a=0;a<19;++a)S[a]=0;for(a=0;a8;)e.sourceIndex--,e.bitcount-=8;if((t=256*(t=e.source[e.sourceIndex+1])+e.source[e.sourceIndex])!==(65535&~(256*e.source[e.sourceIndex+3]+e.source[e.sourceIndex+2])))return-3;for(e.sourceIndex+=4,n=t;n;--n)e.dest[e.destLen++]=e.source[e.sourceIndex++];return e.bitcount=0,0}!function(e,t){var n;for(n=0;n<7;++n)e.table[n]=0;for(e.table[7]=24,e.table[8]=152,e.table[9]=112,n=0;n<24;++n)e.trans[n]=256+n;for(n=0;n<144;++n)e.trans[24+n]=n;for(n=0;n<8;++n)e.trans[168+n]=280+n;for(n=0;n<112;++n)e.trans[176+n]=144+n;for(n=0;n<5;++n)t.table[n]=0;for(t.table[5]=32,n=0;n<32;++n)t.trans[n]=n}(h,f),x(d,g,4,3),x(m,y,2,1),d[28]=0,g[28]=258;var C=function(e,t){var n,o,r=new p(e,t);do{switch(n=E(r),O(r,2,0)){case 0:o=D(r);break;case 1:o=R(r,h,f);break;case 2:k(r,r.ltree,r.dtree),o=R(r,r.ltree,r.dtree);break;default:o=-3}if(0!==o)throw new Error("Data error")}while(!n);return r.destLenthis.x2&&(this.x2=e)),"number"==typeof t&&((isNaN(this.y1)||isNaN(this.y2))&&(this.y1=t,this.y2=t),tthis.y2&&(this.y2=t))},I.prototype.addX=function(e){this.addPoint(e,null)},I.prototype.addY=function(e){this.addPoint(null,e)},I.prototype.addBezier=function(e,t,n,o,r,s,a,i){const l=[e,t],c=[n,o],u=[r,s],p=[a,i];this.addPoint(e,t),this.addPoint(a,i);for(let e=0;e<=1;e++){const t=6*l[e]-12*c[e]+6*u[e],n=-3*l[e]+9*c[e]-9*u[e]+3*p[e],o=3*c[e]-3*l[e];if(0===n){if(0===t)continue;const n=-o/t;0=0&&n>0&&(e+=" "),e+=t(o)}return e}e=void 0!==e?e:2;let o="";for(let e=0;e=0&&e<=255,"Byte value should be between 0 and 255."),[e]},F.BYTE=H(1),A.CHAR=function(e){return[e.charCodeAt(0)]},F.CHAR=H(1),A.CHARARRAY=function(e){const t=[];for(let n=0;n>8&255,255&e]},F.USHORT=H(2),A.SHORT=function(e){return e>=32768&&(e=-(65536-e)),[e>>8&255,255&e]},F.SHORT=H(2),A.UINT24=function(e){return[e>>16&255,e>>8&255,255&e]},F.UINT24=H(3),A.ULONG=function(e){return[e>>24&255,e>>16&255,e>>8&255,255&e]},F.ULONG=H(4),A.LONG=function(e){return e>=2147483648&&(e=-(4294967296-e)),[e>>24&255,e>>16&255,e>>8&255,255&e]},F.LONG=H(4),A.FIXED=A.ULONG,F.FIXED=F.ULONG,A.FWORD=A.SHORT,F.FWORD=F.SHORT,A.UFWORD=A.USHORT,F.UFWORD=F.USHORT,A.LONGDATETIME=function(e){return[0,0,0,0,e>>24&255,e>>16&255,e>>8&255,255&e]},F.LONGDATETIME=H(8),A.TAG=function(e){return N.argument(4===e.length,"Tag should be exactly 4 ASCII characters."),[e.charCodeAt(0),e.charCodeAt(1),e.charCodeAt(2),e.charCodeAt(3)]},F.TAG=H(4),A.Card8=A.BYTE,F.Card8=F.BYTE,A.Card16=A.USHORT,F.Card16=F.USHORT,A.OffSize=A.BYTE,F.OffSize=F.BYTE,A.SID=A.USHORT,F.SID=F.USHORT,A.NUMBER=function(e){return e>=-107&&e<=107?[e+139]:e>=108&&e<=1131?[247+((e-=108)>>8),255&e]:e>=-1131&&e<=-108?[251+((e=-e-108)>>8),255&e]:e>=-32768&&e<=32767?A.NUMBER16(e):A.NUMBER32(e)},F.NUMBER=function(e){return A.NUMBER(e).length},A.NUMBER16=function(e){return[28,e>>8&255,255&e]},F.NUMBER16=H(3),A.NUMBER32=function(e){return[29,e>>24&255,e>>16&255,e>>8&255,255&e]},F.NUMBER32=H(5),A.REAL=function(e){let t=e.toString();const n=/\.(\d*?)(?:9{5,20}|0{5,20})\d{0,2}(?:e(.+)|$)/.exec(t);if(n){const o=parseFloat("1e"+((n[2]?+n[2]:0)+n[1].length));t=(Math.round(e*o)/o).toString()}let o="";for(let e=0,n=t.length;e>8&255,t[t.length]=255&o}return t},F.UTF16=function(e){return 2*e.length};const z={"x-mac-croatian":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®Š™´¨≠ŽØ∞±≤≥∆µ∂∑∏š∫ªºΩžø¿¡¬√ƒ≈Ć«Č… ÀÃÕŒœĐ—“”‘’÷◊©⁄€‹›Æ»–·‚„‰ÂćÁčÈÍÎÏÌÓÔđÒÚÛÙıˆ˜¯πË˚¸Êæˇ","x-mac-cyrillic":"АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ†°Ґ£§•¶І®©™Ђђ≠Ѓѓ∞±≤≥іµґЈЄєЇїЉљЊњјЅ¬√ƒ≈∆«»… ЋћЌќѕ–—“”‘’÷„ЎўЏџ№Ёёяабвгдежзийклмнопрстуфхцчшщъыьэю","x-mac-gaelic":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØḂ±≤≥ḃĊċḊḋḞḟĠġṀæøṁṖṗɼƒſṠ«»… ÀÃÕŒœ–—“”‘’ṡẛÿŸṪ€‹›Ŷŷṫ·Ỳỳ⁊ÂÊÁËÈÍÎÏÌÓÔ♣ÒÚÛÙıÝýŴŵẄẅẀẁẂẃ","x-mac-greek":"Ĺ²É³ÖÜ΅àâä΄¨çéèê룙î‰ôö¦€ùûü†ΓΔΘΛΞΠß®©ΣΪ§≠°·Α±≤≥¥ΒΕΖΗΙΚΜΦΫΨΩάΝ¬ΟΡ≈Τ«»… ΥΧΆΈœ–―“”‘’÷ΉΊΌΎέήίόΏύαβψδεφγηιξκλμνοπώρστθωςχυζϊϋΐΰ­","x-mac-icelandic":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûüÝ°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€ÐðÞþý·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ","x-mac-inuit":"ᐃᐄᐅᐆᐊᐋᐱᐲᐳᐴᐸᐹᑉᑎᑏᑐᑑᑕᑖᑦᑭᑮᑯᑰᑲᑳᒃᒋᒌᒍᒎᒐᒑ°ᒡᒥᒦ•¶ᒧ®©™ᒨᒪᒫᒻᓂᓃᓄᓅᓇᓈᓐᓯᓰᓱᓲᓴᓵᔅᓕᓖᓗᓘᓚᓛᓪᔨᔩᔪᔫᔭ… ᔮᔾᕕᕖᕗ–—“”‘’ᕘᕙᕚᕝᕆᕇᕈᕉᕋᕌᕐᕿᖀᖁᖂᖃᖄᖅᖏᖐᖑᖒᖓᖔᖕᙱᙲᙳᙴᙵᙶᖖᖠᖡᖢᖣᖤᖥᖦᕼŁł","x-mac-ce":"ÄĀāÉĄÖÜáąČäčĆć鏟ĎíďĒēĖóėôöõúĚěü†°Ę£§•¶ß®©™ę¨≠ģĮįĪ≤≥īĶ∂∑łĻļĽľĹĺŅņѬ√ńŇ∆«»… ňŐÕőŌ–—“”‘’÷◊ōŔŕŘ‹›řŖŗŠ‚„šŚśÁŤťÍŽžŪÓÔūŮÚůŰűŲųÝýķŻŁżĢˇ",macintosh:"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€‹›fifl‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ","x-mac-romanian":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ĂȘ∞±≤≥¥µ∂∑∏π∫ªºΩăș¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€‹›Țț‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ","x-mac-turkish":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸĞğİıŞş‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙˆ˜¯˘˙˚¸˝˛ˇ"};P.MACSTRING=function(e,t,n,o){const r=z[o];if(void 0===r)return;let s="";for(let o=0;o=-128&&e<=127}function X(e,t,n){let o=0;const r=e.length;for(;t>8&255,t+256&255)}return s}A.MACSTRING=function(e,t){const n=function(e){if(!_){_={};for(let e in z)_[e]=new String(e)}const t=_[e];if(void 0===t)return;if(W){const e=W.get(t);if(void 0!==e)return e}const n=z[e];if(void 0===n)return;const o={};for(let e=0;e=128&&(r=n[r],void 0===r))return;o[t]=r}return o},F.MACSTRING=function(e,t){const n=A.MACSTRING(e,t);return void 0!==n?n.length:0},A.VARDELTAS=function(e){let t=0;const n=[];for(;t=-128&&o<=127?V(e,t,n):j(e,t,n)}return n},A.INDEX=function(e){let t=1;const n=[t],o=[];for(let r=0;r>8,t[s+1]=255&a,t=t.concat(o[n])}return t},F.TABLE=function(e){let t=0;const n=e.fields.length;for(let o=0;o0)return new ce(this.data,this.offset+t).parseStruct(e)},ce.prototype.parseListOfLists=function(e){const t=this.parseOffset16List(),n=t.length,o=this.relativeOffset,r=new Array(n);for(let o=0;o=0;r-=1){const n=pe.getUShort(e,t+4+8*r),s=pe.getUShort(e,t+4+8*r+2);if(3===n&&(0===s||1===s||10===s)){o=pe.getULong(e,t+4+8*r+4);break}}if(-1===o)throw new Error("No valid cmap sub-tables found.");const r=new pe.Parser(e,t+o);if(n.format=r.parseUShort(),12===n.format)!function(e,t){let n;t.parseUShort(),e.length=t.parseULong(),e.language=t.parseULong(),e.groupCount=n=t.parseULong(),e.glyphIndexMap={};for(let o=0;o>1,t.skip("uShort",3),e.glyphIndexMap={};const a=new pe.Parser(n,o+r+14),i=new pe.Parser(n,o+r+16+2*s),l=new pe.Parser(n,o+r+16+4*s),c=new pe.Parser(n,o+r+16+6*s);let u=o+r+16+8*s;for(let t=0;t0?(s=e.parseByte(),0==(t&r)&&(s=-s),s=n+s):s=(t&r)>0?n:n+e.parseShort(),s}function Ee(e,t,n){const o=new pe.Parser(t,n);let r,s;if(e.numberOfContours=o.parseShort(),e._xMin=o.parseShort(),e._yMin=o.parseShort(),e._xMax=o.parseShort(),e._yMax=o.parseShort(),e.numberOfContours>0){const t=e.endPointIndices=[];for(let n=0;n0){const t=o.parseByte();for(let n=0;n0){const a=[];let i;if(n>0){for(let e=0;e=0,a.push(i);let e=0;for(let t=0;t0?(2&r)>0?(n.dx=o.parseShort(),n.dy=o.parseShort()):n.matchedPoints=[o.parseUShort(),o.parseUShort()]:(2&r)>0?(n.dx=o.parseChar(),n.dy=o.parseChar()):n.matchedPoints=[o.parseByte(),o.parseByte()],(8&r)>0?n.xScale=n.yScale=o.parseF2Dot14():(64&r)>0?(n.xScale=o.parseF2Dot14(),n.yScale=o.parseF2Dot14()):(128&r)>0&&(n.xScale=o.parseF2Dot14(),n.scale01=o.parseF2Dot14(),n.scale10=o.parseF2Dot14(),n.yScale=o.parseF2Dot14()),e.components.push(n),t=!!(32&r)}if(256&r){e.instructionLength=o.parseUShort(),e.instructions=[];for(let t=0;tt.points.length-1||o.matchedPoints[1]>r.points.length-1)throw Error("Matched points out of range in "+t.name);const n=t.points[o.matchedPoints[0]];let s=r.points[o.matchedPoints[1]];const a={xScale:o.xScale,scale01:o.scale01,scale10:o.scale10,yScale:o.yScale,dx:0,dy:0};s=Oe([s],a)[0],a.dx=n.x-s.x,a.dy=n.y-s.y,e=Oe(r.points,a)}t.points=t.points.concat(e)}}return we(t.points)}var Re={getPath:we,parse:function(e,t,n,o){const r=new Ie.GlyphSet(o);for(let s=0;s>4,s=15&o;if(15===r)break;if(t+=n[r],15===s)break;t+=n[s]}return parseFloat(t)}(e);if(t>=32&&t<=246)return t-139;if(t>=247&&t<=250)return n=e.parseByte(),256*(t-247)+n+108;if(t>=251&&t<=254)return n=e.parseByte(),256*-(t-251)-n-108;throw new Error("Invalid b0 "+t)}function Pe(e,t,n){t=void 0!==t?t:0;const o=new pe.Parser(e,t),r=[];let s=[];for(n=void 0!==n?n:e.length;o.relativeOffset>1,l.length=0,d=!0}return function n(p){let x,U,T,E,O,w,k,R,D,C,L,I,M=0;for(;M1&&!d&&(v=l.shift()+h,d=!0),y+=l.pop(),b(m,y);break;case 5:for(;l.length>0;)m+=l.shift(),y+=l.shift(),i.lineTo(m,y);break;case 6:for(;l.length>0&&(m+=l.shift(),i.lineTo(m,y),0!==l.length);)y+=l.shift(),i.lineTo(m,y);break;case 7:for(;l.length>0&&(y+=l.shift(),i.lineTo(m,y),0!==l.length);)m+=l.shift(),i.lineTo(m,y);break;case 8:for(;l.length>0;)o=m+l.shift(),r=y+l.shift(),s=o+l.shift(),a=r+l.shift(),m=s+l.shift(),y=a+l.shift(),i.curveTo(o,r,s,a,m,y);break;case 10:O=l.pop()+u,w=c[O],w&&n(w);break;case 11:return;case 12:switch(B=p[M],M+=1,B){case 35:o=m+l.shift(),r=y+l.shift(),s=o+l.shift(),a=r+l.shift(),k=s+l.shift(),R=a+l.shift(),D=k+l.shift(),C=R+l.shift(),L=D+l.shift(),I=C+l.shift(),m=L+l.shift(),y=I+l.shift(),l.shift(),i.curveTo(o,r,s,a,k,R),i.curveTo(D,C,L,I,m,y);break;case 34:o=m+l.shift(),r=y,s=o+l.shift(),a=r+l.shift(),k=s+l.shift(),R=a,D=k+l.shift(),C=a,L=D+l.shift(),I=y,m=L+l.shift(),i.curveTo(o,r,s,a,k,R),i.curveTo(D,C,L,I,m,y);break;case 36:o=m+l.shift(),r=y+l.shift(),s=o+l.shift(),a=r+l.shift(),k=s+l.shift(),R=a,D=k+l.shift(),C=a,L=D+l.shift(),I=C+l.shift(),m=L+l.shift(),i.curveTo(o,r,s,a,k,R),i.curveTo(D,C,L,I,m,y);break;case 37:o=m+l.shift(),r=y+l.shift(),s=o+l.shift(),a=r+l.shift(),k=s+l.shift(),R=a+l.shift(),D=k+l.shift(),C=R+l.shift(),L=D+l.shift(),I=C+l.shift(),Math.abs(L-m)>Math.abs(I-y)?m=L+l.shift():y=I+l.shift(),i.curveTo(o,r,s,a,k,R),i.curveTo(D,C,L,I,m,y);break;default:console.log("Glyph "+t.index+": unknown operator 1200"+B),l.length=0}break;case 14:l.length>0&&!d&&(v=l.shift()+h,d=!0),g&&(i.closePath(),g=!1);break;case 18:S();break;case 19:case 20:S(),M+=f+7>>3;break;case 21:l.length>2&&!d&&(v=l.shift()+h,d=!0),y+=l.pop(),m+=l.pop(),b(m,y);break;case 22:l.length>1&&!d&&(v=l.shift()+h,d=!0),m+=l.pop(),b(m,y);break;case 23:S();break;case 24:for(;l.length>2;)o=m+l.shift(),r=y+l.shift(),s=o+l.shift(),a=r+l.shift(),m=s+l.shift(),y=a+l.shift(),i.curveTo(o,r,s,a,m,y);m+=l.shift(),y+=l.shift(),i.lineTo(m,y);break;case 25:for(;l.length>6;)m+=l.shift(),y+=l.shift(),i.lineTo(m,y);o=m+l.shift(),r=y+l.shift(),s=o+l.shift(),a=r+l.shift(),m=s+l.shift(),y=a+l.shift(),i.curveTo(o,r,s,a,m,y);break;case 26:for(l.length%2&&(m+=l.shift());l.length>0;)o=m,r=y+l.shift(),s=o+l.shift(),a=r+l.shift(),m=s,y=a+l.shift(),i.curveTo(o,r,s,a,m,y);break;case 27:for(l.length%2&&(y+=l.shift());l.length>0;)o=m+l.shift(),r=y,s=o+l.shift(),a=r+l.shift(),m=s+l.shift(),y=a,i.curveTo(o,r,s,a,m,y);break;case 28:x=p[M],U=p[M+1],l.push((x<<24|U<<16)>>16),M+=2;break;case 29:O=l.pop()+e.gsubrsBias,w=e.gsubrs[O],w&&n(w);break;case 30:for(;l.length>0&&(o=m,r=y+l.shift(),s=o+l.shift(),a=r+l.shift(),m=s+l.shift(),y=a+(1===l.length?l.shift():0),i.curveTo(o,r,s,a,m,y),0!==l.length);)o=m+l.shift(),r=y,s=o+l.shift(),a=r+l.shift(),y=a+l.shift(),m=s+(1===l.length?l.shift():0),i.curveTo(o,r,s,a,m,y);break;case 31:for(;l.length>0&&(o=m+l.shift(),r=y,s=o+l.shift(),a=r+l.shift(),y=a+l.shift(),m=s+(1===l.length?l.shift():0),i.curveTo(o,r,s,a,m,y),0!==l.length);)o=m,r=y+l.shift(),s=o+l.shift(),a=r+l.shift(),m=s+l.shift(),y=a+(1===l.length?l.shift():0),i.curveTo(o,r,s,a,m,y);break;default:B<32?console.log("Glyph "+t.index+": unknown operator "+B):B<247?l.push(B-139):B<251?(x=p[M],M+=1,l.push(256*(B-247)+x+108)):B<255?(x=p[M],M+=1,l.push(256*-(B-251)-x-108)):(x=p[M],U=p[M+1],T=p[M+2],E=p[M+3],M+=4,l.push((x<<24|U<<16|T<<8|E)/65536))}}}(n),t.advanceWidth=v,i}function Ve(e,t){let n,o=de.indexOf(e);return o>=0&&(n=o),o=t.indexOf(e),o>=0?n=o+de.length:(n=de.length+t.length,t.push(e)),n}function je(e,t,n){const o={};for(let r=0;r=o)throw new Error("CFF table CID Font FDSelect has bad FD index value "+s+" (FD count "+o+")");r.push(s)}else{if(3!==i)throw new Error("CFF Table CID Font FDSelect table has unsupported format "+i);{const e=a.parseCard16();let t,i=a.parseCard16();if(0!==i)throw new Error("CFF Table CID Font FDSelect format 3 range has bad initial GID "+i);for(let l=0;l=o)throw new Error("CFF table CID Font FDSelect has bad FD index value "+s+" (FD count "+o+")");if(t>n)throw new Error("CFF Table CID Font FDSelect format 3 range has bad GID "+t);for(;i=1&&(n.ulCodePageRange1=o.parseULong(),n.ulCodePageRange2=o.parseULong()),n.version>=2&&(n.sxHeight=o.parseShort(),n.sCapHeight=o.parseShort(),n.usDefaultChar=o.parseUShort(),n.usBreakChar=o.parseUShort(),n.usMaxContent=o.parseUShort()),n},make:function(e){return new oe.Table("OS/2",[{name:"version",type:"USHORT",value:3},{name:"xAvgCharWidth",type:"SHORT",value:0},{name:"usWeightClass",type:"USHORT",value:0},{name:"usWidthClass",type:"USHORT",value:0},{name:"fsType",type:"USHORT",value:0},{name:"ySubscriptXSize",type:"SHORT",value:650},{name:"ySubscriptYSize",type:"SHORT",value:699},{name:"ySubscriptXOffset",type:"SHORT",value:0},{name:"ySubscriptYOffset",type:"SHORT",value:140},{name:"ySuperscriptXSize",type:"SHORT",value:650},{name:"ySuperscriptYSize",type:"SHORT",value:699},{name:"ySuperscriptXOffset",type:"SHORT",value:0},{name:"ySuperscriptYOffset",type:"SHORT",value:479},{name:"yStrikeoutSize",type:"SHORT",value:49},{name:"yStrikeoutPosition",type:"SHORT",value:258},{name:"sFamilyClass",type:"SHORT",value:0},{name:"bFamilyType",type:"BYTE",value:0},{name:"bSerifStyle",type:"BYTE",value:0},{name:"bWeight",type:"BYTE",value:0},{name:"bProportion",type:"BYTE",value:0},{name:"bContrast",type:"BYTE",value:0},{name:"bStrokeVariation",type:"BYTE",value:0},{name:"bArmStyle",type:"BYTE",value:0},{name:"bLetterform",type:"BYTE",value:0},{name:"bMidline",type:"BYTE",value:0},{name:"bXHeight",type:"BYTE",value:0},{name:"ulUnicodeRange1",type:"ULONG",value:0},{name:"ulUnicodeRange2",type:"ULONG",value:0},{name:"ulUnicodeRange3",type:"ULONG",value:0},{name:"ulUnicodeRange4",type:"ULONG",value:0},{name:"achVendID",type:"CHARARRAY",value:"XXXX"},{name:"fsSelection",type:"USHORT",value:0},{name:"usFirstCharIndex",type:"USHORT",value:0},{name:"usLastCharIndex",type:"USHORT",value:0},{name:"sTypoAscender",type:"SHORT",value:0},{name:"sTypoDescender",type:"SHORT",value:0},{name:"sTypoLineGap",type:"SHORT",value:0},{name:"usWinAscent",type:"USHORT",value:0},{name:"usWinDescent",type:"USHORT",value:0},{name:"ulCodePageRange1",type:"ULONG",value:0},{name:"ulCodePageRange2",type:"ULONG",value:0},{name:"sxHeight",type:"SHORT",value:0},{name:"sCapHeight",type:"SHORT",value:0},{name:"usDefaultChar",type:"USHORT",value:0},{name:"usBreakChar",type:"USHORT",value:0},{name:"usMaxContext",type:"USHORT",value:0}],e)},unicodeRanges:gt,getUnicodeRange:function(e){for(let t=0;t=n.begin&&e=ye.length){const e=o.parseChar();n.names.push(o.parseString(e))}break;case 2.5:n.numberOfGlyphs=o.parseUShort(),n.offset=new Array(n.numberOfGlyphs);for(let e=0;et.value.tag?1:-1})),t.fields=t.fields.concat(o),t.fields=t.fields.concat(r),t}function kt(e,t,n){for(let n=0;n0){return e.glyphs.get(o).getMetrics()}}return n}function Rt(e){let t=0;for(let n=0;nm||void 0===l)&&m>0&&(l=m),c 123 are reserved for internal usage");f|=1<0?tt.make(w):void 0,D=yt.make(),C=$e.make(e.glyphs,{version:e.getEnglishName("version"),fullName:T,familyName:x,weightName:U,postScriptName:E,unitsPerEm:e.unitsPerEm,fontBBox:[0,d.yMin,d.ascender,d.advanceWidthMax]}),L=e.metas&&Object.keys(e.metas).length>0?Ut.make(e.metas):void 0,I=[g,m,y,v,k,S,D,C,b];R&&I.push(R),e.tables.gsub&&I.push(xt.make(e.tables.gsub)),L&&I.push(L);const M=wt(I),B=Et(M.encode()),G=M.fields;let N=!1;for(let e=0;e>>1,s=e[r].tag;if(s===t)return r;s>>1,s=e[r];if(s===t)return r;s=0)return o[r].script;if(t){const t={tag:e,script:{defaultLangSys:{reserved:0,reqFeatureIndex:65535,featureIndexes:[]},langSysRecords:[]}};return o.splice(-1-r,0,t),t.script}}},getLangSysTable:function(e,t,n){const o=this.getScriptTable(e,n);if(o){if(!t||"dflt"===t||"DFLT"===t)return o.defaultLangSys;const e=Ct(o.langSysRecords,t);if(e>=0)return o.langSysRecords[e].langSys;if(n){const n={tag:t,langSys:{reserved:0,reqFeatureIndex:65535,featureIndexes:[]}};return o.langSysRecords.splice(-1-e,0,n),n.langSys}}},getFeatureTable:function(e,t,n,o){const r=this.getLangSysTable(e,t,o);if(r){let e;const t=r.featureIndexes,s=this.font.tables[this.tableName].features;for(let o=0;o=s[o-1].tag,"Features must be added in alphabetical order."),e={tag:n,feature:{params:0,lookupListIndexes:[]}},s.push(e),t.push(o),e.feature}}},getLookupTables:function(e,t,n,o,r){const s=this.getFeatureTable(e,t,n,r),a=[];if(s){let e;const t=s.lookupListIndexes,n=this.font.tables[this.tableName].lookups;for(let r=0;r=0){const e=s.ligatureSets[c];for(let t=0;t0&&e<0?n:o<0&&e>0?-n:e*o},Zt={x:1,y:0,axis:"x",distance:function(e,t,n,o){return(n?e.xo:e.x)-(o?t.xo:t.x)},interpolate:function(e,t,n,o){let r,s,a,i,l,c,u;if(!o||o===this)return r=e.xo-t.xo,s=e.xo-n.xo,l=t.x-t.xo,c=n.x-n.xo,a=Math.abs(r),i=Math.abs(s),u=a+i,0===u?void(e.x=e.xo+(l+c)/2):void(e.x=e.xo+(l*i+c*a)/u);r=o.distance(e,t,!0,!0),s=o.distance(e,n,!0,!0),l=o.distance(t,t,!1,!0),c=o.distance(n,n,!1,!0),a=Math.abs(r),i=Math.abs(s),u=a+i,0!==u?Zt.setRelative(e,e,(l*i+c*a)/u,o,!0):Zt.setRelative(e,e,(l+c)/2,o,!0)},normalSlope:Number.NEGATIVE_INFINITY,setRelative:function(e,t,n,o,r){if(!o||o===this)return void(e.x=(r?t.xo:t.x)+n);const s=r?t.xo:t.x,a=r?t.yo:t.y,i=s+n*o.x,l=a+n*o.y;e.x=i+(e.y-l)/o.normalSlope},slope:0,touch:function(e){e.xTouched=!0},touched:function(e){return e.xTouched},untouch:function(e){e.xTouched=!1}},Qt={x:0,y:1,axis:"y",distance:function(e,t,n,o){return(n?e.yo:e.y)-(o?t.yo:t.y)},interpolate:function(e,t,n,o){let r,s,a,i,l,c,u;if(!o||o===this)return r=e.yo-t.yo,s=e.yo-n.yo,l=t.y-t.yo,c=n.y-n.yo,a=Math.abs(r),i=Math.abs(s),u=a+i,0===u?void(e.y=e.yo+(l+c)/2):void(e.y=e.yo+(l*i+c*a)/u);r=o.distance(e,t,!0,!0),s=o.distance(e,n,!0,!0),l=o.distance(t,t,!1,!0),c=o.distance(n,n,!1,!0),a=Math.abs(r),i=Math.abs(s),u=a+i,0!==u?Qt.setRelative(e,e,(l*i+c*a)/u,o,!0):Qt.setRelative(e,e,(l+c)/2,o,!0)},normalSlope:0,setRelative:function(e,t,n,o,r){if(!o||o===this)return void(e.y=(r?t.yo:t.y)+n);const s=r?t.xo:t.x,a=r?t.yo:t.y,i=s+n*o.x,l=a+n*o.y;e.y=l+o.normalSlope*(e.x-i)},slope:Number.POSITIVE_INFINITY,touch:function(e){e.yTouched=!0},touched:function(e){return e.yTouched},untouch:function(e){e.yTouched=!1}};function $t(e,t){this.x=e,this.y=t,this.axis=void 0,this.slope=t/e,this.normalSlope=-e/t,Object.freeze(this)}function Kt(e,t){const n=Math.sqrt(e*e+t*t);return t/=n,1===(e/=n)&&0===t?Zt:0===e&&1===t?Qt:new $t(e,t)}function Jt(e,t,n,o){this.x=this.xo=Math.round(64*e)/64,this.y=this.yo=Math.round(64*t)/64,this.lastPointOfContour=n,this.onCurve=o,this.prevPointOnContour=void 0,this.nextPointOnContour=void 0,this.xTouched=!1,this.yTouched=!1,Object.preventExtensions(this)}Object.freeze(Zt),Object.freeze(Qt),$t.prototype.distance=function(e,t,n,o){return this.x*Zt.distance(e,t,n,o)+this.y*Qt.distance(e,t,n,o)},$t.prototype.interpolate=function(e,t,n,o){let r,s,a,i,l,c,u;a=o.distance(e,t,!0,!0),i=o.distance(e,n,!0,!0),r=o.distance(t,t,!1,!0),s=o.distance(n,n,!1,!0),l=Math.abs(a),c=Math.abs(i),u=l+c,0!==u?this.setRelative(e,e,(r*c+s*l)/u,o,!0):this.setRelative(e,e,(r+s)/2,o,!0)},$t.prototype.setRelative=function(e,t,n,o,r){o=o||this;const s=r?t.xo:t.x,a=r?t.yo:t.y,i=s+n*o.x,l=a+n*o.y,c=o.normalSlope,u=this.slope,p=e.x,h=e.y;e.x=(u*p-c*i+l-h)/(u-c),e.y=u*(e.x-p)+h},$t.prototype.touch=function(e){e.xTouched=!0,e.yTouched=!0},Jt.prototype.nextTouched=function(e){let t=this.nextPointOnContour;for(;!e.touched(t)&&t!==this;)t=t.nextPointOnContour;return t},Jt.prototype.prevTouched=function(e){let t=this.prevPointOnContour;for(;!e.touched(t)&&t!==this;)t=t.prevPointOnContour;return t};const en=Object.freeze(new Jt(0,0)),tn={cvCutIn:17/16,deltaBase:9,deltaShift:.125,loop:1,minDis:1,autoFlip:!0};function nn(e,t){switch(this.env=e,this.stack=[],this.prog=t,e){case"glyf":this.zp0=this.zp1=this.zp2=1,this.rp0=this.rp1=this.rp2=0;case"prep":this.fv=this.pv=this.dpv=Zt,this.round=_t}}function on(e){const t=e.tZone=new Array(e.gZone.length);for(let e=0;e=176&&o<=183)r+=o-176+1;else if(o>=184&&o<=191)r+=2*(o-184+1);else if(t&&1===s&&27===o)break}while(s>0);e.ip=r}function sn(e,t){exports.DEBUG&&console.log(t.step,"SVTCA["+e.axis+"]"),t.fv=t.pv=t.dpv=e}function an(e,t){exports.DEBUG&&console.log(t.step,"SPVTCA["+e.axis+"]"),t.pv=t.dpv=e}function ln(e,t){exports.DEBUG&&console.log(t.step,"SFVTCA["+e.axis+"]"),t.fv=e}function cn(e,t){const n=t.stack,o=n.pop(),r=n.pop(),s=t.z2[o],a=t.z1[r];let i,l;exports.DEBUG&&console.log("SPVTL["+e+"]",o,r),e?(i=s.y-a.y,l=a.x-s.x):(i=a.x-s.x,l=a.y-s.y),t.pv=t.dpv=Kt(i,l)}function un(e,t){const n=t.stack,o=n.pop(),r=n.pop(),s=t.z2[o],a=t.z1[r];let i,l;exports.DEBUG&&console.log("SFVTL["+e+"]",o,r),e?(i=s.y-a.y,l=a.x-s.x):(i=a.x-s.x,l=a.y-s.y),t.fv=Kt(i,l)}function pn(e){exports.DEBUG&&console.log(e.step,"POP[]"),e.stack.pop()}function hn(e,t){const n=t.stack.pop(),o=t.z0[n],r=t.fv,s=t.pv;exports.DEBUG&&console.log(t.step,"MDAP["+e+"]",n);let a=s.distance(o,en);e&&(a=t.round(a)),r.setRelative(o,en,a,s),r.touch(o),t.rp0=t.rp1=n}function fn(e,t){const n=t.z2,o=n.length-2;let r,s,a;exports.DEBUG&&console.log(t.step,"IUP["+e.axis+"]");for(let t=0;t1?"loop "+(t.loop-i)+": ":"")+"SHP["+(e?"rp1":"rp2")+"]",o)}t.loop=1}function gn(e,t){const n=t.stack,o=e?t.rp1:t.rp2,r=(e?t.z0:t.z1)[o],s=t.fv,a=t.pv,i=n.pop(),l=t.z2[t.contours[i]];let c=l;exports.DEBUG&&console.log(t.step,"SHC["+e+"]",i);const u=a.distance(r,r,!1,!0);do{c!==r&&s.setRelative(c,c,u,a),c=c.nextPointOnContour}while(c!==l)}function mn(e,t){const n=t.stack,o=e?t.rp1:t.rp2,r=(e?t.z0:t.z1)[o],s=t.fv,a=t.pv,i=n.pop();let l,c;switch(exports.DEBUG&&console.log(t.step,"SHZ["+e+"]",i),i){case 0:l=t.tZone;break;case 1:l=t.gZone;break;default:throw new Error("Invalid zone")}const u=a.distance(r,r,!1,!0),p=l.length-2;for(let e=0;e",i),t.stack.push(Math.round(64*i))}function xn(e,t){const n=t.stack,o=n.pop(),r=t.fv,s=t.pv,a=t.ppem,i=t.deltaBase+16*(e-1),l=t.deltaShift,c=t.z0;exports.DEBUG&&console.log(t.step,"DELTAP["+e+"]",o,n);for(let e=0;e>4)!==a)continue;let u=(15&o)-8;u>=0&&u++,exports.DEBUG&&console.log(t.step,"DELTAPFIX",e,"by",u*l);const p=c[e];r.setRelative(p,p,u*l,s)}}function Un(e,t){const n=t.stack,o=n.pop();exports.DEBUG&&console.log(t.step,"ROUND[]"),n.push(64*t.round(o/64))}function Tn(e,t){const n=t.stack,o=n.pop(),r=t.ppem,s=t.deltaBase+16*(e-1),a=t.deltaShift;exports.DEBUG&&console.log(t.step,"DELTAC["+e+"]",o,n);for(let e=0;e>4)!==r)continue;let i=(15&o)-8;i>=0&&i++;const l=i*a;exports.DEBUG&&console.log(t.step,"DELTACFIX",e,"by",l),t.cvt[e]+=l}}function En(e,t){const n=t.stack,o=n.pop(),r=n.pop(),s=t.z2[o],a=t.z1[r];let i,l;exports.DEBUG&&console.log("SDPVTL["+e+"]",o,r),e?(i=s.y-a.y,l=a.x-s.x):(i=a.x-s.x,l=a.y-s.y),t.dpv=Kt(i,l)}function On(e,t){const n=t.stack,o=t.prog;let r=t.ip;exports.DEBUG&&console.log(t.step,"PUSHB["+e+"]");for(let t=0;t=0?1:-1,m=Math.abs(m),e&&(v=s.cvt[i],o&&Math.abs(m-v)":"_")+(o?"R":"_")+(0===r?"Gr":1===r?"Bl":2===r?"Wh":"")+"]",e?i+"("+s.cvt[i]+","+v+")":"",l,"(d =",g,"->",y*m,")"),s.rp1=s.rp0,s.rp2=l,t&&(s.rp0=l)}function Rn(e){(e=e||{}).empty||(Nt(e.familyName,"When creating a new Font object, familyName is required."),Nt(e.styleName,"When creating a new Font object, styleName is required."),Nt(e.unitsPerEm,"When creating a new Font object, unitsPerEm is required."),Nt(e.ascender,"When creating a new Font object, ascender is required."),Nt(e.descender,"When creating a new Font object, descender is required."),Nt(e.descender<0,"Descender should be negative (e.g. -512)."),this.names={fontFamily:{en:e.familyName||" "},fontSubfamily:{en:e.styleName||" "},fullName:{en:e.fullName||e.familyName+" "+e.styleName},postScriptName:{en:e.postScriptName||e.familyName+e.styleName},designer:{en:e.designer||" "},designerURL:{en:e.designerURL||" "},manufacturer:{en:e.manufacturer||" "},manufacturerURL:{en:e.manufacturerURL||" "},license:{en:e.license||" "},licenseURL:{en:e.licenseURL||" "},version:{en:e.version||"Version 0.1"},description:{en:e.description||" "},copyright:{en:e.copyright||" "},trademark:{en:e.trademark||" "}},this.unitsPerEm=e.unitsPerEm||1e3,this.ascender=e.ascender,this.descender=e.descender,this.createdTimestamp=e.createdTimestamp,this.tables={os2:{usWeightClass:e.weightClass||this.usWeightClasses.MEDIUM,usWidthClass:e.widthClass||this.usWidthClasses.MEDIUM,fsSelection:e.fsSelection||this.fsSelectionValues.REGULAR}}),this.supported=!0,this.glyphs=new Ie.GlyphSet(this,e.glyphs||[]),this.encoding=new ve(this),this.substitution=new It(this),this.tables=this.tables||{},Object.defineProperty(this,"hinting",{get:function(){return this._hinting?this._hinting:"truetype"===this.outlinesFormat?this._hinting=new zt(this):void 0}})}function Dn(e,t){const n=JSON.stringify(e);let o=256;for(let e in t){let r=parseInt(e);if(r&&!(r<256)){if(JSON.stringify(t[e])===n)return r;o<=r&&(o=r+1)}}return t[o]=e,o}function Cn(e,t,n){const o=Dn(t.name,n);return[{name:"tag_"+e,type:"TAG",value:t.tag},{name:"minValue_"+e,type:"FIXED",value:t.minValue<<16},{name:"defaultValue_"+e,type:"FIXED",value:t.defaultValue<<16},{name:"maxValue_"+e,type:"FIXED",value:t.maxValue<<16},{name:"flags_"+e,type:"USHORT",value:0},{name:"nameID_"+e,type:"USHORT",value:o}]}function Ln(e,t,n){const o={},r=new pe.Parser(e,t);return o.tag=r.parseTag(),o.minValue=r.parseFixed(),o.defaultValue=r.parseFixed(),o.maxValue=r.parseFixed(),r.skip("uShort",1),o.name=n[r.parseUShort()]||{},o}function In(e,t,n,o){const r=[{name:"nameID_"+e,type:"USHORT",value:Dn(t.name,o)},{name:"flags_"+e,type:"USHORT",value:0}];for(let o=0;o2)return;const n=this.font;let o=this._prepState;if(!o||o.ppem!==t){let e=this._fpgmState;if(!e){nn.prototype=tn,e=this._fpgmState=new nn("fpgm",n.tables.fpgm),e.funcs=[],e.font=n,exports.DEBUG&&(console.log("---EXEC FPGM---"),e.step=-1);try{At(e)}catch(e){return console.log("Hinting error in FPGM:"+e),void(this._errorState=3)}}nn.prototype=e,o=this._prepState=new nn("prep",n.tables.prep),o.ppem=t;const r=n.tables.cvt;if(r){const e=o.cvt=new Array(r.length),s=t/n.unitsPerEm;for(let t=0;t1))try{return Ft(e,o)}catch(e){return this._errorState<1&&(console.log("Hinting error:"+e),console.log("Note: further hinting errors are silenced")),void(this._errorState=1)}},Ft=function(e,t){const n=t.ppem/t.font.unitsPerEm,o=n;let r,s,a,i=e.components;if(nn.prototype=t,i){const l=t.font;s=[],r=[];for(let e=0;e1?"loop "+(e.loop-n)+": ":"")+"SHPIX[]",a,r),o.setRelative(i,i,r),o.touch(i)}e.loop=1},function(e){const t=e.stack,n=e.rp1,o=e.rp2;let r=e.loop;const s=e.z0[n],a=e.z1[o],i=e.fv,l=e.dpv,c=e.z2;for(;r--;){const u=t.pop(),p=c[u];exports.DEBUG&&console.log(e.step,(e.loop>1?"loop "+(e.loop-r)+": ":"")+"IP[]",u,n,"<->",o),i.interpolate(p,s,a,l),i.touch(p)}e.loop=1},yn.bind(void 0,0),yn.bind(void 0,1),function(e){const t=e.stack,n=e.rp0,o=e.z0[n];let r=e.loop;const s=e.fv,a=e.pv,i=e.z1;for(;r--;){const n=t.pop(),l=i[n];exports.DEBUG&&console.log(e.step,(e.loop>1?"loop "+(e.loop-r)+": ":"")+"ALIGNRP[]",n),s.setRelative(l,o,0,a),s.touch(l)}e.loop=1},function(e){exports.DEBUG&&console.log(e.step,"RTDG[]"),e.round=qt},vn.bind(void 0,0),vn.bind(void 0,1),function(e){const t=e.prog;let n=e.ip;const o=e.stack,r=t[++n];exports.DEBUG&&console.log(e.step,"NPUSHB[]",r);for(let e=0;en?1:0)},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"GTEQ[]",n,o),t.push(o>=n?1:0)},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"EQ[]",n,o),t.push(n===o?1:0)},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"NEQ[]",n,o),t.push(n!==o?1:0)},function(e){const t=e.stack,n=t.pop();exports.DEBUG&&console.log(e.step,"ODD[]",n),t.push(Math.trunc(n)%2?1:0)},function(e){const t=e.stack,n=t.pop();exports.DEBUG&&console.log(e.step,"EVEN[]",n),t.push(Math.trunc(n)%2?0:1)},function(e){let t=e.stack.pop();exports.DEBUG&&console.log(e.step,"IF[]",t),t||(rn(e,!0),exports.DEBUG&&console.log(e.step,"EIF[]"))},function(e){exports.DEBUG&&console.log(e.step,"EIF[]")},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"AND[]",n,o),t.push(n&&o?1:0)},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"OR[]",n,o),t.push(n||o?1:0)},function(e){const t=e.stack,n=t.pop();exports.DEBUG&&console.log(e.step,"NOT[]",n),t.push(n?0:1)},xn.bind(void 0,1),function(e){const t=e.stack.pop();exports.DEBUG&&console.log(e.step,"SDB[]",t),e.deltaBase=t},function(e){const t=e.stack.pop();exports.DEBUG&&console.log(e.step,"SDS[]",t),e.deltaShift=Math.pow(.5,t)},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"ADD[]",n,o),t.push(o+n)},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"SUB[]",n,o),t.push(o-n)},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"DIV[]",n,o),t.push(64*o/n)},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"MUL[]",n,o),t.push(o*n/64)},function(e){const t=e.stack,n=t.pop();exports.DEBUG&&console.log(e.step,"ABS[]",n),t.push(Math.abs(n))},function(e){const t=e.stack;let n=t.pop();exports.DEBUG&&console.log(e.step,"NEG[]",n),t.push(-n)},function(e){const t=e.stack,n=t.pop();exports.DEBUG&&console.log(e.step,"FLOOR[]",n),t.push(64*Math.floor(n/64))},function(e){const t=e.stack,n=t.pop();exports.DEBUG&&console.log(e.step,"CEILING[]",n),t.push(64*Math.ceil(n/64))},Un.bind(void 0,0),Un.bind(void 0,1),Un.bind(void 0,2),Un.bind(void 0,3),void 0,void 0,void 0,void 0,function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"WCVTF[]",n,o),e.cvt[o]=n*e.ppem/e.font.unitsPerEm},xn.bind(void 0,2),xn.bind(void 0,3),Tn.bind(void 0,1),Tn.bind(void 0,2),Tn.bind(void 0,3),function(e){let t,n=e.stack.pop();switch(exports.DEBUG&&console.log(e.step,"SROUND[]",n),e.round=Yt,192&n){case 0:t=.5;break;case 64:t=1;break;case 128:t=2;break;default:throw new Error("invalid SROUND value")}switch(e.srPeriod=t,48&n){case 0:e.srPhase=0;break;case 16:e.srPhase=.25*t;break;case 32:e.srPhase=.5*t;break;case 48:e.srPhase=.75*t;break;default:throw new Error("invalid SROUND value")}n&=15,e.srThreshold=0===n?0:(n/8-.5)*t},function(e){let t,n=e.stack.pop();switch(exports.DEBUG&&console.log(e.step,"S45ROUND[]",n),e.round=Yt,192&n){case 0:t=Math.sqrt(2)/2;break;case 64:t=Math.sqrt(2);break;case 128:t=2*Math.sqrt(2);break;default:throw new Error("invalid S45ROUND value")}switch(e.srPeriod=t,48&n){case 0:e.srPhase=0;break;case 16:e.srPhase=.25*t;break;case 32:e.srPhase=.5*t;break;case 48:e.srPhase=.75*t;break;default:throw new Error("invalid S45ROUND value")}n&=15,e.srThreshold=0===n?0:(n/8-.5)*t},void 0,void 0,function(e){exports.DEBUG&&console.log(e.step,"ROFF[]"),e.round=Wt},void 0,function(e){exports.DEBUG&&console.log(e.step,"RUTG[]"),e.round=Vt},function(e){exports.DEBUG&&console.log(e.step,"RDTG[]"),e.round=jt},pn,pn,void 0,void 0,void 0,void 0,void 0,function(e){const t=e.stack.pop();exports.DEBUG&&console.log(e.step,"SCANCTRL[]",t)},En.bind(void 0,0),En.bind(void 0,1),function(e){const t=e.stack,n=t.pop();let o=0;exports.DEBUG&&console.log(e.step,"GETINFO[]",n),1&n&&(o=35),32&n&&(o|=4096),t.push(o)},void 0,function(e){const t=e.stack,n=t.pop(),o=t.pop(),r=t.pop();exports.DEBUG&&console.log(e.step,"ROLL[]"),t.push(o),t.push(n),t.push(r)},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"MAX[]",n,o),t.push(Math.max(o,n))},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"MIN[]",n,o),t.push(Math.min(o,n))},function(e){const t=e.stack.pop();exports.DEBUG&&console.log(e.step,"SCANTYPE[]",t)},function(e){const t=e.stack.pop();let n=e.stack.pop();switch(exports.DEBUG&&console.log(e.step,"INSTCTRL[]",t,n),t){case 1:return void(e.inhibitGridFit=!!n);case 2:return void(e.ignoreCvt=!!n);default:throw new Error("invalid INSTCTRL[] selector")}},void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,On.bind(void 0,1),On.bind(void 0,2),On.bind(void 0,3),On.bind(void 0,4),On.bind(void 0,5),On.bind(void 0,6),On.bind(void 0,7),On.bind(void 0,8),wn.bind(void 0,1),wn.bind(void 0,2),wn.bind(void 0,3),wn.bind(void 0,4),wn.bind(void 0,5),wn.bind(void 0,6),wn.bind(void 0,7),wn.bind(void 0,8),kn.bind(void 0,0,0,0,0,0),kn.bind(void 0,0,0,0,0,1),kn.bind(void 0,0,0,0,0,2),kn.bind(void 0,0,0,0,0,3),kn.bind(void 0,0,0,0,1,0),kn.bind(void 0,0,0,0,1,1),kn.bind(void 0,0,0,0,1,2),kn.bind(void 0,0,0,0,1,3),kn.bind(void 0,0,0,1,0,0),kn.bind(void 0,0,0,1,0,1),kn.bind(void 0,0,0,1,0,2),kn.bind(void 0,0,0,1,0,3),kn.bind(void 0,0,0,1,1,0),kn.bind(void 0,0,0,1,1,1),kn.bind(void 0,0,0,1,1,2),kn.bind(void 0,0,0,1,1,3),kn.bind(void 0,0,1,0,0,0),kn.bind(void 0,0,1,0,0,1),kn.bind(void 0,0,1,0,0,2),kn.bind(void 0,0,1,0,0,3),kn.bind(void 0,0,1,0,1,0),kn.bind(void 0,0,1,0,1,1),kn.bind(void 0,0,1,0,1,2),kn.bind(void 0,0,1,0,1,3),kn.bind(void 0,0,1,1,0,0),kn.bind(void 0,0,1,1,0,1),kn.bind(void 0,0,1,1,0,2),kn.bind(void 0,0,1,1,0,3),kn.bind(void 0,0,1,1,1,0),kn.bind(void 0,0,1,1,1,1),kn.bind(void 0,0,1,1,1,2),kn.bind(void 0,0,1,1,1,3),kn.bind(void 0,1,0,0,0,0),kn.bind(void 0,1,0,0,0,1),kn.bind(void 0,1,0,0,0,2),kn.bind(void 0,1,0,0,0,3),kn.bind(void 0,1,0,0,1,0),kn.bind(void 0,1,0,0,1,1),kn.bind(void 0,1,0,0,1,2),kn.bind(void 0,1,0,0,1,3),kn.bind(void 0,1,0,1,0,0),kn.bind(void 0,1,0,1,0,1),kn.bind(void 0,1,0,1,0,2),kn.bind(void 0,1,0,1,0,3),kn.bind(void 0,1,0,1,1,0),kn.bind(void 0,1,0,1,1,1),kn.bind(void 0,1,0,1,1,2),kn.bind(void 0,1,0,1,1,3),kn.bind(void 0,1,1,0,0,0),kn.bind(void 0,1,1,0,0,1),kn.bind(void 0,1,1,0,0,2),kn.bind(void 0,1,1,0,0,3),kn.bind(void 0,1,1,0,1,0),kn.bind(void 0,1,1,0,1,1),kn.bind(void 0,1,1,0,1,2),kn.bind(void 0,1,1,0,1,3),kn.bind(void 0,1,1,1,0,0),kn.bind(void 0,1,1,1,0,1),kn.bind(void 0,1,1,1,0,2),kn.bind(void 0,1,1,1,0,3),kn.bind(void 0,1,1,1,1,0),kn.bind(void 0,1,1,1,1,1),kn.bind(void 0,1,1,1,1,2),kn.bind(void 0,1,1,1,1,3)],Rn.prototype.hasChar=function(e){return null!==this.encoding.charToGlyphIndex(e)},Rn.prototype.charToGlyphIndex=function(e){return this.encoding.charToGlyphIndex(e)},Rn.prototype.charToGlyph=function(e){const t=this.charToGlyphIndex(e);let n=this.glyphs.get(t);return n||(n=this.glyphs.get(0)),n},Rn.prototype.stringToGlyphs=function(e,t){t=t||this.defaultRenderOptions;const n=[];for(let t=0;t>1;e1&&console.warn("Only the first kern subtable is supported."),e.skip("uLong");const n=255&e.parseUShort();if(e.skip("uShort"),0===n){const n=e.parseUShort();e.skip("uShort",3);for(let o=0;o{const t=jn.loadSync(e);Qn.font=t,Qn.ascender=t.ascender,Qn.descender=t.descender}};const Kn=$n.options,Jn=function(e,t){return Math.round(e+Math.random()*(t-e))};const eo=function(e,t){return{text:(e+t).toString(),equation:e+"+"+t}},to=function(e,t){return{text:(e-t).toString(),equation:e+"-"+t}};function no(e,t,n){return 6*(n=(n+1)%1)<1?e+(t-e)*n*6:2*n<1?t:3*n<2?e+(t-e)*(2/3-n)*6:e}var oo={int:Jn,greyColor:function(e,t){const n=Jn(e=e||1,t=t||9).toString(16);return`#${n}${n}${n}`},captchaText:function(e){"number"==typeof e&&(e={size:e});const t=(e=e||{}).size||4,n=e.ignoreChars||"";let o=-1,r="",s=e.charPreset||Kn.charPreset;n&&(s=function(e,t){return e.split("").filter(e=>-1===t.indexOf(e))}(s,n));const a=s.length-1;for(;++o>16,o=t>>8&255,r=255&t,s=Math.max(n,o,r),a=Math.min(n,o,r);return(s+a)/510}(e):1;let r,s;o>=.5?(r=Math.round(100*o)-45,s=Math.round(100*o)-25):(r=Math.round(100*o)+25,s=Math.round(100*o)+45);const a=Jn(r,s)/100,i=a<.5?a*(a+n):a+n-a*n,l=2*a-i,c=Math.floor(255*no(l,i,t+1/3)),u=Math.floor(255*no(l,i,t));return"#"+(Math.floor(255*no(l,i,t-1/3))|u<<8|c<<16|1<<24).toString(16).slice(1)}};const ro=$n.options,so=function(e,t){e=e||oo.captchaText();const n=(t=Object.assign({},ro,t)).width,o=t.height,r=t.background||t.backgroundColor;r&&(t.color=!0);const s=r?``:"",a=[].concat(function(e,t,n){const o=n.color,r=[],s=n.inverse?7:1,a=n.inverse?15:9;let i=-1;for(;++i`)}return r}(n,o,t)).concat(function(e,t,n,o,r){const s=e.length,a=(t-2)/(s+1),i=o.inverse?10:0,l=o.inverse?14:4;let u=-1;const p=[],h=r||o.color?oo.color(o.background):oo.greyColor(i,l);for(;++u`)}return p}(e,n,o,t)).sort(()=>Math.random()-.5).join("");return`${``}${s}${a}`};var ao=so,io=oo.captchaText,lo=function(e){const t=e.text||oo.captchaText(e);return{text:t,data:so(t,e)}},co=function(e){const t=oo.mathExpr(e.mathMin,e.mathMax,e.mathOperator);return{text:t.text,data:so(t.equation,e)}},uo=ro,po=$n.loadFont;ao.randomText=io,ao.create=lo,ao.createMathExpr=co,ao.options=uo,ao.loadFont=po;var ho=ao;const fo=Object.prototype.toString;function go(e){return"[object Object]"===fo.call(e)}function mo(){"development"===process.env.NODE_ENV&&console.log(...arguments)}const yo=async function(){};function vo(e){return yo.constructor===e.constructor?async function(){const t=await e.apply(this,arguments);return go(t)&&(t.msg&&(t.message=t.msg,t.errMsg=t.msg),0===t.code?t.errCode=t.code:t.errCode=s[t.code]||t.code),t}:function(){const t=e.apply(this,arguments);return go(t)&&(t.msg&&(t.message=t.msg,t.errMsg=t.msg),0===t.code?t.errCode=t.code:t.errCode=s[t.code]||t.code),t}}const bo=uniCloud.database().collection("opendb-verify-codes");class So{async setVerifyCode({deviceId:e,code:t,expiresDate:n,scene:o}){if(!e)return{code:10101,msg:"deviceId不可为空"};if(!t)return{code:10102,msg:"验证码不可为空"};n||(n=180);const r=Date.now(),s={deviceId:e,scene:o,code:t.toLocaleLowerCase(),state:0,ip:__ctx__.CLIENTIP,created_date:r,expired_date:r+1e3*n};return mo("addRes",await bo.add(s)),{code:0,deviceId:e}}async verifyCode({deviceId:e,code:t,scene:n}){if(!e)return{code:10101,msg:"deviceId不可为空"};if(!t)return{code:10102,msg:"验证码不可为空"};const o=Date.now(),r={deviceId:e,scene:n,code:t.toLocaleLowerCase(),state:0},s=await bo.where(r).orderBy("created_date","desc").limit(1).get();if(mo("verifyRecord:",s),s&&s.data&&s.data.length>0){const e=s.data[0];if(e.expired_date{e.scene&&delete e.scene,this.pluginConfig.scene[n]=Object.assign({},t,e[n])})}}}{constructor(){super(),this.DEVICEID2opts={}}mergeConfig(e){const t=go(this.pluginConfig.scene)?this.pluginConfig.scene[e.scene]:e.scene;return Object.assign({},go(t)?t:this.pluginConfig,e)}async create(e={}){if(!e.scene)throw new Error("scene验证码场景不可为空");e=this.mergeConfig(e);let{scene:t,expiresDate:n,deviceId:o,...r}=e;if(o=o||__ctx__.DEVICEID,!o)throw new Error("deviceId不可为空");const s=new So;try{const{text:a,base64:i}=function(e={}){const{uniPlatform:t=""}=e;let n;n=e.mathExpr?ho.createMathExpr(e):ho.create(e);let o="data:image/svg+xml;utf8,"+n.data.replace(/#/g,"%23");return(!t||"string"==typeof t&&-1===t.indexOf("mp-"))&&(o=o.replace(/"/g,"'").replace(//g,"%3E")),{text:n.text,base64:o}}(r),l=await s.setVerifyCode({deviceId:o,code:a,expiresDate:n,scene:t});return l.code>0?{...l,code:10001}:(this.DEVICEID2opts[o]=e,{code:0,msg:"验证码获取成功",captchaBase64:i})}catch(e){return{code:10001,msg:"验证码生成失败:"+e.message}}}async verify({deviceId:e,captcha:t,scene:n}){if(!(e=e||__ctx__.DEVICEID))throw new Error("deviceId不可为空");if(!n)throw new Error("scene验证码场景不可为空");const o=new So;try{const r=await o.verifyCode({deviceId:e,code:t,scene:n});return r.code>0?r:{code:0,msg:"验证码通过"}}catch(e){return{code:10002,msg:"验证码校验失败:"+e.message}}}async refresh(e={}){let{scene:t,expiresDate:n,deviceId:o,...r}=e;if(o=o||__ctx__.DEVICEID,!o)throw new Error("deviceId不可为空");if(!t)throw new Error("scene验证码场景不可为空");const s=await bo.where({deviceId:o,scene:t}).orderBy("created_date","desc").limit(1).get();if(s&&s.data&&s.data.length>0){const e=s.data[0];await bo.doc(e._id).update({state:2}),Object.keys(r).length>0&&(this.DEVICEID2opts[o]=Object.assign({},this.DEVICEID2opts[o],r));let a={};try{a=await this.create(Object.assign({},this.DEVICEID2opts[o],{deviceId:o,scene:t,expiresDate:n}))}catch(e){return{code:50403,msg:e.message}}return a.code>0?{...a,code:50403}:{code:0,msg:"验证码刷新成功",captchaBase64:a.captchaBase64}}return{code:10003,msg:`验证码刷新失败:无此设备在 ${t} 场景信息,请重新获取`}}}const To=new So;Object.keys(To).forEach(e=>{Uo.prototype[e]=vo(To[e])});const Eo=new Uo,Oo=new Proxy(Eo,{get(e,t){if(t in e)return"function"==typeof e[t]?vo(e[t]).bind(Oo):e[t]}});module.exports=Oo; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/node_modules/uni-config-center/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/node_modules/uni-config-center/index.js new file mode 100644 index 0000000..e14fb3b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-captcha/node_modules/uni-config-center/index.js @@ -0,0 +1 @@ +"use strict";var t=require("fs"),r=require("path");function e(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var n=e(t),o=e(r),i="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};var u=function(t){var r={exports:{}};return t(r,r.exports),r.exports}((function(t,r){var e="__lodash_hash_undefined__",n=9007199254740991,o="[object Arguments]",u="[object Function]",c="[object Object]",a=/^\[object .+?Constructor\]$/,f=/^(?:0|[1-9]\d*)$/,s={};s["[object Float32Array]"]=s["[object Float64Array]"]=s["[object Int8Array]"]=s["[object Int16Array]"]=s["[object Int32Array]"]=s["[object Uint8Array]"]=s["[object Uint8ClampedArray]"]=s["[object Uint16Array]"]=s["[object Uint32Array]"]=!0,s[o]=s["[object Array]"]=s["[object ArrayBuffer]"]=s["[object Boolean]"]=s["[object DataView]"]=s["[object Date]"]=s["[object Error]"]=s[u]=s["[object Map]"]=s["[object Number]"]=s[c]=s["[object RegExp]"]=s["[object Set]"]=s["[object String]"]=s["[object WeakMap]"]=!1;var l="object"==typeof i&&i&&i.Object===Object&&i,h="object"==typeof self&&self&&self.Object===Object&&self,p=l||h||Function("return this")(),_=r&&!r.nodeType&&r,v=_&&t&&!t.nodeType&&t,d=v&&v.exports===_,y=d&&l.process,g=function(){try{var t=v&&v.require&&v.require("util").types;return t||y&&y.binding&&y.binding("util")}catch(t){}}(),b=g&&g.isTypedArray;function j(t,r,e){switch(e.length){case 0:return t.call(r);case 1:return t.call(r,e[0]);case 2:return t.call(r,e[0],e[1]);case 3:return t.call(r,e[0],e[1],e[2])}return t.apply(r,e)}var w,O,m,A=Array.prototype,z=Function.prototype,M=Object.prototype,x=p["__core-js_shared__"],C=z.toString,F=M.hasOwnProperty,U=(w=/[^.]+$/.exec(x&&x.keys&&x.keys.IE_PROTO||""))?"Symbol(src)_1."+w:"",S=M.toString,I=C.call(Object),P=RegExp("^"+C.call(F).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),T=d?p.Buffer:void 0,q=p.Symbol,E=p.Uint8Array,$=T?T.allocUnsafe:void 0,D=(O=Object.getPrototypeOf,m=Object,function(t){return O(m(t))}),k=Object.create,B=M.propertyIsEnumerable,N=A.splice,L=q?q.toStringTag:void 0,R=function(){try{var t=_t(Object,"defineProperty");return t({},"",{}),t}catch(t){}}(),G=T?T.isBuffer:void 0,V=Math.max,W=Date.now,H=_t(p,"Map"),J=_t(Object,"create"),K=function(){function t(){}return function(r){if(!Mt(r))return{};if(k)return k(r);t.prototype=r;var e=new t;return t.prototype=void 0,e}}();function Q(t){var r=-1,e=null==t?0:t.length;for(this.clear();++r-1},X.prototype.set=function(t,r){var e=this.__data__,n=nt(e,t);return n<0?(++this.size,e.push([t,r])):e[n][1]=r,this},Y.prototype.clear=function(){this.size=0,this.__data__={hash:new Q,map:new(H||X),string:new Q}},Y.prototype.delete=function(t){var r=pt(this,t).delete(t);return this.size-=r?1:0,r},Y.prototype.get=function(t){return pt(this,t).get(t)},Y.prototype.has=function(t){return pt(this,t).has(t)},Y.prototype.set=function(t,r){var e=pt(this,t),n=e.size;return e.set(t,r),this.size+=e.size==n?0:1,this},Z.prototype.clear=function(){this.__data__=new X,this.size=0},Z.prototype.delete=function(t){var r=this.__data__,e=r.delete(t);return this.size=r.size,e},Z.prototype.get=function(t){return this.__data__.get(t)},Z.prototype.has=function(t){return this.__data__.has(t)},Z.prototype.set=function(t,r){var e=this.__data__;if(e instanceof X){var n=e.__data__;if(!H||n.length<199)return n.push([t,r]),this.size=++e.size,this;e=this.__data__=new Y(n)}return e.set(t,r),this.size=e.size,this};var it,ut=function(t,r,e){for(var n=-1,o=Object(t),i=e(t),u=i.length;u--;){var c=i[it?u:++n];if(!1===r(o[c],c,o))break}return t};function ct(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":L&&L in Object(t)?function(t){var r=F.call(t,L),e=t[L];try{t[L]=void 0;var n=!0}catch(t){}var o=S.call(t);n&&(r?t[L]=e:delete t[L]);return o}(t):function(t){return S.call(t)}(t)}function at(t){return xt(t)&&ct(t)==o}function ft(t){return!(!Mt(t)||function(t){return!!U&&U in t}(t))&&(At(t)?P:a).test(function(t){if(null!=t){try{return C.call(t)}catch(t){}try{return t+""}catch(t){}}return""}(t))}function st(t){if(!Mt(t))return function(t){var r=[];if(null!=t)for(var e in Object(t))r.push(e);return r}(t);var r=dt(t),e=[];for(var n in t)("constructor"!=n||!r&&F.call(t,n))&&e.push(n);return e}function lt(t,r,e,n,o){t!==r&&ut(r,(function(i,u){if(o||(o=new Z),Mt(i))!function(t,r,e,n,o,i,u){var a=yt(t,e),f=yt(r,e),s=u.get(f);if(s)return void rt(t,e,s);var l=i?i(a,f,e+"",t,r,u):void 0,h=void 0===l;if(h){var p=wt(f),_=!p&&mt(f),v=!p&&!_&&Ct(f);l=f,p||_||v?wt(a)?l=a:xt(j=a)&&Ot(j)?l=function(t,r){var e=-1,n=t.length;r||(r=Array(n));for(;++e-1&&t%1==0&&t0){if(++r>=800)return arguments[0]}else r=0;return t.apply(void 0,arguments)}}(R?function(t,r){return R(t,"toString",{configurable:!0,enumerable:!1,value:(e=r,function(){return e}),writable:!0});var e}:It);function bt(t,r){return t===r||t!=t&&r!=r}var jt=at(function(){return arguments}())?at:function(t){return xt(t)&&F.call(t,"callee")&&!B.call(t,"callee")},wt=Array.isArray;function Ot(t){return null!=t&&zt(t.length)&&!At(t)}var mt=G||function(){return!1};function At(t){if(!Mt(t))return!1;var r=ct(t);return r==u||"[object GeneratorFunction]"==r||"[object AsyncFunction]"==r||"[object Proxy]"==r}function zt(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=n}function Mt(t){var r=typeof t;return null!=t&&("object"==r||"function"==r)}function xt(t){return null!=t&&"object"==typeof t}var Ct=b?function(t){return function(r){return t(r)}}(b):function(t){return xt(t)&&zt(t.length)&&!!s[ct(t)]};function Ft(t){return Ot(t)?tt(t,!0):st(t)}var Ut,St=(Ut=function(t,r,e){lt(t,r,e)},ht((function(t,r){var e=-1,n=r.length,o=n>1?r[n-1]:void 0,i=n>2?r[2]:void 0;for(o=Ut.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,r,e){if(!Mt(e))return!1;var n=typeof r;return!!("number"==n?Ot(e)&&vt(r,e.length):"string"==n&&r in e)&&bt(e[r],t)}(r[0],r[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++ec.call(t,r);class f{constructor({pluginId:t,defaultConfig:r={},customMerge:e,root:n}){this.pluginId=t,this.defaultConfig=r,this.pluginConfigPath=o.default.resolve(n||__dirname,t),this.customMerge=e,this._config=void 0}resolve(t){return o.default.resolve(this.pluginConfigPath,t)}hasFile(t){return n.default.existsSync(this.resolve(t))}requireFile(t){try{return require(this.resolve(t))}catch(t){if("MODULE_NOT_FOUND"===t.code)return;throw t}}_getUserConfig(){return this.requireFile("config.json")}config(t,r){this._config||(this._config=(this.customMerge||u)(this.defaultConfig,this._getUserConfig()));let e=this._config;return t?function(t,r,e){if("number"==typeof r)return t[r];if("symbol"==typeof r)return a(t,r)?t[r]:e;const n="string"!=typeof(o=r)?o:o.split(".").reduce(((t,r)=>(r.split(/\[([^}]+)\]/g).forEach((r=>r&&t.push(r))),t)),[]);var o;let i=t;for(let t=0;t-1},X.prototype.set=function(t,r){var e=this.__data__,n=nt(e,t);return n<0?(++this.size,e.push([t,r])):e[n][1]=r,this},Y.prototype.clear=function(){this.size=0,this.__data__={hash:new Q,map:new(H||X),string:new Q}},Y.prototype.delete=function(t){var r=pt(this,t).delete(t);return this.size-=r?1:0,r},Y.prototype.get=function(t){return pt(this,t).get(t)},Y.prototype.has=function(t){return pt(this,t).has(t)},Y.prototype.set=function(t,r){var e=pt(this,t),n=e.size;return e.set(t,r),this.size+=e.size==n?0:1,this},Z.prototype.clear=function(){this.__data__=new X,this.size=0},Z.prototype.delete=function(t){var r=this.__data__,e=r.delete(t);return this.size=r.size,e},Z.prototype.get=function(t){return this.__data__.get(t)},Z.prototype.has=function(t){return this.__data__.has(t)},Z.prototype.set=function(t,r){var e=this.__data__;if(e instanceof X){var n=e.__data__;if(!H||n.length<199)return n.push([t,r]),this.size=++e.size,this;e=this.__data__=new Y(n)}return e.set(t,r),this.size=e.size,this};var it,ut=function(t,r,e){for(var n=-1,o=Object(t),i=e(t),u=i.length;u--;){var c=i[it?u:++n];if(!1===r(o[c],c,o))break}return t};function ct(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":L&&L in Object(t)?function(t){var r=F.call(t,L),e=t[L];try{t[L]=void 0;var n=!0}catch(t){}var o=S.call(t);n&&(r?t[L]=e:delete t[L]);return o}(t):function(t){return S.call(t)}(t)}function at(t){return xt(t)&&ct(t)==o}function ft(t){return!(!Mt(t)||function(t){return!!U&&U in t}(t))&&(At(t)?P:a).test(function(t){if(null!=t){try{return C.call(t)}catch(t){}try{return t+""}catch(t){}}return""}(t))}function st(t){if(!Mt(t))return function(t){var r=[];if(null!=t)for(var e in Object(t))r.push(e);return r}(t);var r=dt(t),e=[];for(var n in t)("constructor"!=n||!r&&F.call(t,n))&&e.push(n);return e}function lt(t,r,e,n,o){t!==r&&ut(r,(function(i,u){if(o||(o=new Z),Mt(i))!function(t,r,e,n,o,i,u){var a=yt(t,e),f=yt(r,e),s=u.get(f);if(s)return void rt(t,e,s);var l=i?i(a,f,e+"",t,r,u):void 0,h=void 0===l;if(h){var p=wt(f),_=!p&&mt(f),v=!p&&!_&&Ct(f);l=f,p||_||v?wt(a)?l=a:xt(j=a)&&Ot(j)?l=function(t,r){var e=-1,n=t.length;r||(r=Array(n));for(;++e-1&&t%1==0&&t0){if(++r>=800)return arguments[0]}else r=0;return t.apply(void 0,arguments)}}(R?function(t,r){return R(t,"toString",{configurable:!0,enumerable:!1,value:(e=r,function(){return e}),writable:!0});var e}:It);function bt(t,r){return t===r||t!=t&&r!=r}var jt=at(function(){return arguments}())?at:function(t){return xt(t)&&F.call(t,"callee")&&!B.call(t,"callee")},wt=Array.isArray;function Ot(t){return null!=t&&zt(t.length)&&!At(t)}var mt=G||function(){return!1};function At(t){if(!Mt(t))return!1;var r=ct(t);return r==u||"[object GeneratorFunction]"==r||"[object AsyncFunction]"==r||"[object Proxy]"==r}function zt(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=n}function Mt(t){var r=typeof t;return null!=t&&("object"==r||"function"==r)}function xt(t){return null!=t&&"object"==typeof t}var Ct=b?function(t){return function(r){return t(r)}}(b):function(t){return xt(t)&&zt(t.length)&&!!s[ct(t)]};function Ft(t){return Ot(t)?tt(t,!0):st(t)}var Ut,St=(Ut=function(t,r,e){lt(t,r,e)},ht((function(t,r){var e=-1,n=r.length,o=n>1?r[n-1]:void 0,i=n>2?r[2]:void 0;for(o=Ut.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,r,e){if(!Mt(e))return!1;var n=typeof r;return!!("number"==n?Ot(e)&&vt(r,e.length):"string"==n&&r in e)&&bt(e[r],t)}(r[0],r[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++ec.call(t,r);class f{constructor({pluginId:t,defaultConfig:r={},customMerge:e,root:n}){this.pluginId=t,this.defaultConfig=r,this.pluginConfigPath=o.default.resolve(n||__dirname,t),this.customMerge=e,this._config=void 0}resolve(t){return o.default.resolve(this.pluginConfigPath,t)}hasFile(t){return n.default.existsSync(this.resolve(t))}requireFile(t){try{return require(this.resolve(t))}catch(t){if("MODULE_NOT_FOUND"===t.code)return;throw t}}_getUserConfig(){return this.requireFile("config.json")}config(t,r){this._config||(this._config=(this.customMerge||u)(this.defaultConfig,this._getUserConfig()));let e=this._config;return t?function(t,r,e){if("number"==typeof r)return t[r];if("symbol"==typeof r)return a(t,r)?t[r]:e;const n="string"!=typeof(o=r)?o:o.split(".").reduce(((t,r)=>(r.split(/\[([^}]+)\]/g).forEach((r=>r&&t.push(r))),t)),[]);var o;let i=t;for(let t=0;tparseInt(e)):void 0}function o(e,t){const n=r(e),i=r(t);return n?i?function(e,t){const n=Math.max(e.length,t.length);for(let i=0;ir)return 1;if(ne)throw new Error("Config error, tokenExpiresThreshold should be less than tokenExpiresIn")}get customToken(){return this.uniId.interceptorMap.get("customToken")}isTokenInDb(e){return o(e,"1.0.10")>=0}async getUserRecord(){if(this.userRecord)return this.userRecord;const e=await C.doc(this.uid).get();if(this.userRecord=e.data[0],!this.userRecord)throw{errCode:n.ACCOUNT_NOT_EXISTS};switch(this.userRecord.status){case void 0:case 0:break;case 1:throw{errCode:n.ACCOUNT_BANNED};case 2:throw{errCode:n.ACCOUNT_AUDITING};case 3:throw{errCode:n.ACCOUNT_AUDIT_FAILED};case 4:throw{errCode:n.ACCOUNT_CLOSED}}if(this.oldTokenPayload){if(this.isTokenInDb(this.oldTokenPayload.uniIdVersion)){if(-1===(this.userRecord.token||[]).indexOf(this.oldToken))throw{errCode:n.CHECK_TOKEN_FAILED}}if(this.userRecord.valid_token_date&&this.userRecord.valid_token_date>1e3*this.oldTokenPayload.iat)throw{errCode:n.TOKEN_EXPIRED}}return this.userRecord}async updateUserRecord(e){await C.doc(this.uid).update(e)}async getUserPermission(){if(this.userPermission)return this.userPermission;const e=(await this.getUserRecord()).role||[];if(0===e.length)return this.userPermission={role:[],permission:[]},this.userPermission;if(e.includes("admin"))return this.userPermission={role:["admin"],permission:[]},this.userPermission;const t=await m.where({role_id:_.in(e)}).get(),n=(i=t.data.reduce((e,t)=>(t.permission&&e.push(...t.permission),e),[]),Array.from(new Set(i)));var i;return this.userPermission={role:e,permission:n},this.userPermission}async _createToken({uid:e,role:t,permission:i}={}){if(!t||!i){const e=await this.getUserPermission();t=e.role,i=e.permission}let r={uid:e,role:t,permission:i};if(this.uniId.interceptorMap.has("customToken")){const n=this.uniId.interceptorMap.get("customToken");if("function"!=typeof n)throw new Error("Invalid custom token file");r=await n({uid:e,role:t,permission:i})}const o=Date.now(),{tokenSecret:s,tokenExpiresIn:c}=this.config,a=g({...r,uniIdVersion:"1.0.13"},s,{expiresIn:c}),u=await this.getUserRecord(),d=(u.token||[]).filter(e=>{try{const t=this._checkToken(e);if(u.valid_token_date&&u.valid_token_date>1e3*t.iat)return!1}catch(e){if(e.errCode===n.TOKEN_EXPIRED)return!1}return!0});return d.push(a),await this.updateUserRecord({last_login_ip:this.clientInfo.clientIP,last_login_date:o,token:d}),{token:a,tokenExpired:o+1e3*c}}async createToken({uid:e,role:t,permission:i}={}){if(!e)throw{errCode:n.PARAM_REQUIRED,errMsgValue:{param:"uid"}};this.uid=e;const{token:r,tokenExpired:o}=await this._createToken({uid:e,role:t,permission:i});return{errCode:0,token:r,tokenExpired:o}}async refreshToken({token:e}={}){if(!e)throw{errCode:n.PARAM_REQUIRED,errMsgValue:{param:"token"}};this.oldToken=e;const t=this._checkToken(e);this.uid=t.uid,this.oldTokenPayload=t;const{uid:i}=t,{role:r,permission:o}=await this.getUserPermission(),{token:s,tokenExpired:c}=await this._createToken({uid:i,role:r,permission:o});return{errCode:0,token:s,tokenExpired:c}}_checkToken(e){const{tokenSecret:t}=this.config;let i;try{i=k(e,t)}catch(e){if("TokenExpiredError"===e.name)throw{errCode:n.TOKEN_EXPIRED};throw{errCode:n.CHECK_TOKEN_FAILED}}return i}async checkToken(e,{autoRefresh:t=!0}={}){if(!e)throw{errCode:n.PARAM_REQUIRED,errMsgValue:{param:"token"}};this.oldToken=e;const i=this._checkToken(e);this.uid=i.uid,this.oldTokenPayload=i;const{tokenExpiresThreshold:r}=this.config,{uid:o,role:s,permission:c}=i,a={role:s,permission:c};if(!s&&!c){const{role:e,permission:t}=await this.getUserPermission();a.role=e,a.permission=t}if(!r||!t){const e={code:0,errCode:0,...i,...a};return delete e.uniIdVersion,e}const u=Date.now();let d={};1e3*i.exp-u<1e3*r&&(d=await this._createToken({uid:o}));const l={code:0,errCode:0,...i,...a,...d};return delete l.uniIdVersion,l}}var E=Object.freeze({__proto__:null,checkToken:async function(e,{autoRefresh:t=!0}={}){return new T({uniId:this}).checkToken(e,{autoRefresh:t})},createToken:async function({uid:e,role:t,permission:n}={}){return new T({uniId:this}).createToken({uid:e,role:t,permission:n})},refreshToken:async function({token:e}={}){return new T({uniId:this}).refreshToken({token:e})}});const w=require("uni-config-center")({pluginId:"uni-id"});class A{constructor({context:e,clientInfo:t,config:n}={}){this._clientInfo=e?function(e){return{appId:e.APPID,platform:e.PLATFORM,locale:e.LOCALE,clientIP:e.CLIENTIP,deviceId:e.DEVICEID}}(e):t,this.config=n||this._getOriginConfig(),this.interceptorMap=new Map,w.hasFile("custom-token.js")&&this.setInterceptor("customToken",require(w.resolve("custom-token.js"))),this._i18n=uniCloud.initI18n({locale:this._clientInfo.locale,fallbackLocale:"zh-Hans",messages:d})}setInterceptor(e,t){this.interceptorMap.set(e,t)}_t(...e){return this._i18n.t(...e)}_parseOriginConfig(e){return Array.isArray(e)?e:e[0]?Object.values(e):e}_getOriginConfig(){if(w.hasFile("config.json")){let e;try{e=w.config()}catch(e){throw new Error("Invalid uni-id config file\n"+e.message)}return this._parseOriginConfig(e)}try{return this._parseOriginConfig(require("uni-id/config.json"))}catch(e){throw new Error("Invalid uni-id config file")}}_getAppConfig(){const e=this._getOriginConfig();return Array.isArray(e)?e.find(e=>e.dcloudAppid===this._clientInfo.appId)||e.find(e=>e.isDefaultConfig):e}_getPlatformConfig(){const e=this._getAppConfig();if(!e)throw new Error(`Config for current app (${this._clientInfo.appId}) was not found, please check your config file or client appId`);let t;switch("app-plus"===this._clientInfo.platform&&(this._clientInfo.platform="app"),"h5"===this._clientInfo.platform&&(this._clientInfo.platform="web"),this._clientInfo.platform){case"web":t="h5";break;case"app":t="app-plus"}const n=[{tokenExpiresIn:7200,tokenExpiresThreshold:1200,passwordErrorLimit:6,passwordErrorRetryTime:3600},e];t&&e[t]&&n.push(e[t]),n.push(e[this._clientInfo.platform]);const i=Object.assign(...n);return["tokenSecret","tokenExpiresIn"].forEach(e=>{if(!i||!i[e])throw new Error(`Config parameter missing, ${e} is required`)}),i}_getConfig(){return this._getPlatformConfig()}}for(const e in E)A.prototype[e]=E[e];function y(e){const t=new A(e);return new Proxy(t,{get(e,t){if(t in e&&0!==t.indexOf("_")){if("function"==typeof e[t])return(n=e[t],function(){let e;try{e=n.apply(this,arguments)}catch(e){if(a(e))return c.call(this,e),e;throw e}return i(e)?e.then(e=>(a(e)&&c.call(this,e),e),e=>{if(a(e))return c.call(this,e),e;throw e}):(a(e)&&c.call(this,e),e)}).bind(e);if("context"!==t&&"config"!==t)return e[t]}var n}})}A.prototype.createInstance=y;const x={createInstance:y};module.exports=x; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-id-common/node_modules/uni-config-center/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-id-common/node_modules/uni-config-center/index.js new file mode 100644 index 0000000..e14fb3b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-id-common/node_modules/uni-config-center/index.js @@ -0,0 +1 @@ +"use strict";var t=require("fs"),r=require("path");function e(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var n=e(t),o=e(r),i="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};var u=function(t){var r={exports:{}};return t(r,r.exports),r.exports}((function(t,r){var e="__lodash_hash_undefined__",n=9007199254740991,o="[object Arguments]",u="[object Function]",c="[object Object]",a=/^\[object .+?Constructor\]$/,f=/^(?:0|[1-9]\d*)$/,s={};s["[object Float32Array]"]=s["[object Float64Array]"]=s["[object Int8Array]"]=s["[object Int16Array]"]=s["[object Int32Array]"]=s["[object Uint8Array]"]=s["[object Uint8ClampedArray]"]=s["[object Uint16Array]"]=s["[object Uint32Array]"]=!0,s[o]=s["[object Array]"]=s["[object ArrayBuffer]"]=s["[object Boolean]"]=s["[object DataView]"]=s["[object Date]"]=s["[object Error]"]=s[u]=s["[object Map]"]=s["[object Number]"]=s[c]=s["[object RegExp]"]=s["[object Set]"]=s["[object String]"]=s["[object WeakMap]"]=!1;var l="object"==typeof i&&i&&i.Object===Object&&i,h="object"==typeof self&&self&&self.Object===Object&&self,p=l||h||Function("return this")(),_=r&&!r.nodeType&&r,v=_&&t&&!t.nodeType&&t,d=v&&v.exports===_,y=d&&l.process,g=function(){try{var t=v&&v.require&&v.require("util").types;return t||y&&y.binding&&y.binding("util")}catch(t){}}(),b=g&&g.isTypedArray;function j(t,r,e){switch(e.length){case 0:return t.call(r);case 1:return t.call(r,e[0]);case 2:return t.call(r,e[0],e[1]);case 3:return t.call(r,e[0],e[1],e[2])}return t.apply(r,e)}var w,O,m,A=Array.prototype,z=Function.prototype,M=Object.prototype,x=p["__core-js_shared__"],C=z.toString,F=M.hasOwnProperty,U=(w=/[^.]+$/.exec(x&&x.keys&&x.keys.IE_PROTO||""))?"Symbol(src)_1."+w:"",S=M.toString,I=C.call(Object),P=RegExp("^"+C.call(F).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),T=d?p.Buffer:void 0,q=p.Symbol,E=p.Uint8Array,$=T?T.allocUnsafe:void 0,D=(O=Object.getPrototypeOf,m=Object,function(t){return O(m(t))}),k=Object.create,B=M.propertyIsEnumerable,N=A.splice,L=q?q.toStringTag:void 0,R=function(){try{var t=_t(Object,"defineProperty");return t({},"",{}),t}catch(t){}}(),G=T?T.isBuffer:void 0,V=Math.max,W=Date.now,H=_t(p,"Map"),J=_t(Object,"create"),K=function(){function t(){}return function(r){if(!Mt(r))return{};if(k)return k(r);t.prototype=r;var e=new t;return t.prototype=void 0,e}}();function Q(t){var r=-1,e=null==t?0:t.length;for(this.clear();++r-1},X.prototype.set=function(t,r){var e=this.__data__,n=nt(e,t);return n<0?(++this.size,e.push([t,r])):e[n][1]=r,this},Y.prototype.clear=function(){this.size=0,this.__data__={hash:new Q,map:new(H||X),string:new Q}},Y.prototype.delete=function(t){var r=pt(this,t).delete(t);return this.size-=r?1:0,r},Y.prototype.get=function(t){return pt(this,t).get(t)},Y.prototype.has=function(t){return pt(this,t).has(t)},Y.prototype.set=function(t,r){var e=pt(this,t),n=e.size;return e.set(t,r),this.size+=e.size==n?0:1,this},Z.prototype.clear=function(){this.__data__=new X,this.size=0},Z.prototype.delete=function(t){var r=this.__data__,e=r.delete(t);return this.size=r.size,e},Z.prototype.get=function(t){return this.__data__.get(t)},Z.prototype.has=function(t){return this.__data__.has(t)},Z.prototype.set=function(t,r){var e=this.__data__;if(e instanceof X){var n=e.__data__;if(!H||n.length<199)return n.push([t,r]),this.size=++e.size,this;e=this.__data__=new Y(n)}return e.set(t,r),this.size=e.size,this};var it,ut=function(t,r,e){for(var n=-1,o=Object(t),i=e(t),u=i.length;u--;){var c=i[it?u:++n];if(!1===r(o[c],c,o))break}return t};function ct(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":L&&L in Object(t)?function(t){var r=F.call(t,L),e=t[L];try{t[L]=void 0;var n=!0}catch(t){}var o=S.call(t);n&&(r?t[L]=e:delete t[L]);return o}(t):function(t){return S.call(t)}(t)}function at(t){return xt(t)&&ct(t)==o}function ft(t){return!(!Mt(t)||function(t){return!!U&&U in t}(t))&&(At(t)?P:a).test(function(t){if(null!=t){try{return C.call(t)}catch(t){}try{return t+""}catch(t){}}return""}(t))}function st(t){if(!Mt(t))return function(t){var r=[];if(null!=t)for(var e in Object(t))r.push(e);return r}(t);var r=dt(t),e=[];for(var n in t)("constructor"!=n||!r&&F.call(t,n))&&e.push(n);return e}function lt(t,r,e,n,o){t!==r&&ut(r,(function(i,u){if(o||(o=new Z),Mt(i))!function(t,r,e,n,o,i,u){var a=yt(t,e),f=yt(r,e),s=u.get(f);if(s)return void rt(t,e,s);var l=i?i(a,f,e+"",t,r,u):void 0,h=void 0===l;if(h){var p=wt(f),_=!p&&mt(f),v=!p&&!_&&Ct(f);l=f,p||_||v?wt(a)?l=a:xt(j=a)&&Ot(j)?l=function(t,r){var e=-1,n=t.length;r||(r=Array(n));for(;++e-1&&t%1==0&&t0){if(++r>=800)return arguments[0]}else r=0;return t.apply(void 0,arguments)}}(R?function(t,r){return R(t,"toString",{configurable:!0,enumerable:!1,value:(e=r,function(){return e}),writable:!0});var e}:It);function bt(t,r){return t===r||t!=t&&r!=r}var jt=at(function(){return arguments}())?at:function(t){return xt(t)&&F.call(t,"callee")&&!B.call(t,"callee")},wt=Array.isArray;function Ot(t){return null!=t&&zt(t.length)&&!At(t)}var mt=G||function(){return!1};function At(t){if(!Mt(t))return!1;var r=ct(t);return r==u||"[object GeneratorFunction]"==r||"[object AsyncFunction]"==r||"[object Proxy]"==r}function zt(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=n}function Mt(t){var r=typeof t;return null!=t&&("object"==r||"function"==r)}function xt(t){return null!=t&&"object"==typeof t}var Ct=b?function(t){return function(r){return t(r)}}(b):function(t){return xt(t)&&zt(t.length)&&!!s[ct(t)]};function Ft(t){return Ot(t)?tt(t,!0):st(t)}var Ut,St=(Ut=function(t,r,e){lt(t,r,e)},ht((function(t,r){var e=-1,n=r.length,o=n>1?r[n-1]:void 0,i=n>2?r[2]:void 0;for(o=Ut.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,r,e){if(!Mt(e))return!1;var n=typeof r;return!!("number"==n?Ot(e)&&vt(r,e.length):"string"==n&&r in e)&&bt(e[r],t)}(r[0],r[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++ec.call(t,r);class f{constructor({pluginId:t,defaultConfig:r={},customMerge:e,root:n}){this.pluginId=t,this.defaultConfig=r,this.pluginConfigPath=o.default.resolve(n||__dirname,t),this.customMerge=e,this._config=void 0}resolve(t){return o.default.resolve(this.pluginConfigPath,t)}hasFile(t){return n.default.existsSync(this.resolve(t))}requireFile(t){try{return require(this.resolve(t))}catch(t){if("MODULE_NOT_FOUND"===t.code)return;throw t}}_getUserConfig(){return this.requireFile("config.json")}config(t,r){this._config||(this._config=(this.customMerge||u)(this.defaultConfig,this._getUserConfig()));let e=this._config;return t?function(t,r,e){if("number"==typeof r)return t[r];if("symbol"==typeof r)return a(t,r)?t[r]:e;const n="string"!=typeof(o=r)?o:o.split(".").reduce(((t,r)=>(r.split(/\[([^}]+)\]/g).forEach((r=>r&&t.push(r))),t)),[]);var o;let i=t;for(let t=0;t { + return (item.dcloudAppid === appid) + }) + } + return this._uniId + } + + get ready() { + return this._ready + } +} + +class AppConfig extends ConfigBase { + + constructor() { + super() + } + + get(appid, platform) { + if (!this.isSupport(platform)) { + return null + } + + let appConfig = this.getAppConfig(appid) + if (!appConfig) { + return null + } + + return this.getOauthConfig(appConfig, platform) + } + + isSupport(platformName) { + return (AppConfig.Support_Platforms.indexOf(platformName) >= 0) + } + + getOauthConfig(appConfig, platformName) { + let tree = OauthConfig[platformName] + let node = appConfig + for (let i = 0; i < tree.length; i++) { + let nodeName = tree[i] + if (node[nodeName]) { + node = node[nodeName] + } else { + node = null + break + } + } + + if (node && node.appid && node.appsecret) { + return { + appid: node.appid, + secret: node.appsecret + } + } + + return null + } +} + +AppConfig.Support_Platforms = [PlatformType.WEIXIN_MP, PlatformType.WEIXIN_H5] + + +module.exports = { + AppConfig +}; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/consts.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/consts.js new file mode 100644 index 0000000..6da817b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/consts.js @@ -0,0 +1,26 @@ +'use strict'; + +const TAG = "UNI_OPEN_BRIDGE" + +const HTTP_STATUS = { + SUCCESS: 200 +} + +const PlatformType = { + WEIXIN_MP: 'weixin-mp', + WEIXIN_H5: 'weixin-h5', + WEIXIN_APP: 'weixin-app', + WEIXIN_WEB: 'weixin-web', + QQ_MP: 'qq-mp', + QQ_APP: 'qq-app' +} + +const ErrorCodeType = { + SYSTEM_ERROR: TAG + "_SYSTEM_ERROR" +} + +module.exports = { + HTTP_STATUS, + PlatformType, + ErrorCodeType +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/index.js new file mode 100644 index 0000000..f39b0af --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/index.js @@ -0,0 +1,221 @@ +'use strict'; + +const { + PlatformType, + ErrorCodeType +} = require('./consts.js') + +const { + AppConfig +} = require('./config.js') + +const { + Storage, + Factory +} = require('./storage.js') + +const { + BridgeError +} = require('./bridge-error.js') + +const { + WeixinServer +} = require('./weixin-server.js') + +const appConfig = new AppConfig() + +class AccessToken extends Storage { + + constructor() { + super('access-token', ['dcloudAppid', 'platform']) + } + + async fallback(parameters) { + const oauthConfig = appConfig.get(parameters.dcloudAppid, parameters.platform) + let methodName + if (parameters.platform === PlatformType.WEIXIN_MP) { + methodName = 'GetMPAccessTokenData' + } else if (parameters.platform === PlatformType.WEIXIN_H5) { + methodName = 'GetH5AccessTokenData' + } else { + throw new BridgeError(ErrorCodeType.SYSTEM_ERROR, "platform invalid") + } + + const responseData = await WeixinServer[methodName](oauthConfig) + + const duration = responseData.expires_in || (60 * 60 * 2) + delete responseData.expires_in + + return { + value: responseData, + duration + } + } +} + +class UserAccessToken extends Storage { + + constructor() { + super('user-access-token', ['dcloudAppid', 'platform', 'openid']) + } +} + +class SessionKey extends Storage { + + constructor() { + super('session-key', ['dcloudAppid', 'platform', 'openid']) + } +} + +class Encryptkey extends Storage { + + constructor() { + super('encrypt-key', ['dcloudAppid', 'platform', 'openid']) + } + + getKeyString(key) { + return `${super.getKeyString(key)}-${key.version}` + } + + getExpiresIn(value) { + if (value <= 0) { + return 60 + } + return value + } + + async fallback(parameters) { + const accessToken = await Factory.Get(AccessToken, parameters) + const userSession = await Factory.Get(SessionKey, parameters) + + const responseData = await WeixinServer.GetUserEncryptKeyData({ + openid: parameters.openid, + access_token: accessToken.access_token, + session_key: userSession.session_key + }) + + const keyInfo = responseData.key_info_list.find((item) => { + return item.version = parameters.version + }) + + const value = { + encrypt_key: keyInfo.encrypt_key, + iv: keyInfo.iv + } + + return { + value, + duration: keyInfo.expire_in + } + } +} + +class Ticket extends Storage { + + constructor() { + super('ticket', ['dcloudAppid', 'platform']) + } + + async fallback(parameters) { + const accessToken = await Factory.Get(AccessToken, { + dcloudAppid: parameters.dcloudAppid, + platform: PlatformType.WEIXIN_H5 + }) + + const responseData = await WeixinServer.GetH5TicketData(accessToken) + + const duration = responseData.expires_in || (60 * 60 * 2) + delete responseData.expires_in + delete responseData.errcode + delete responseData.errmsg + + return { + value: responseData, + duration + } + } +} + + +// exports + +async function getAccessToken(key, fallback) { + return await Factory.Get(AccessToken, key, fallback) +} + +async function setAccessToken(key, value, expiresIn) { + await Factory.Set(AccessToken, key, value, expiresIn) +} + +async function removeAccessToken(key) { + await Factory.Remove(AccessToken, key) +} + +async function getUserAccessToken(key, fallback) { + return await Factory.Get(UserAccessToken, key, fallback) +} + +async function setUserAccessToken(key, value, expiresIn) { + await Factory.Set(UserAccessToken, key, value, expiresIn) +} + +async function removeUserAccessToken(key) { + await Factory.Remove(UserAccessToken, key) +} + +async function getSessionKey(key, fallback) { + return await Factory.Get(SessionKey, key, fallback) +} + +async function setSessionKey(key, value, expiresIn) { + await Factory.Set(SessionKey, key, value, expiresIn) +} + +async function removeSessionKey(key) { + await Factory.Remove(SessionKey, key) +} + +async function getEncryptKey(key, fallback) { + return await Factory.Get(Encryptkey, key, fallback) +} + +async function setEncryptKey(key, value, expiresIn) { + await Factory.Set(Encryptkey, key, value, expiresIn) +} + +async function removeEncryptKey(key) { + await Factory.Remove(Encryptkey, key) +} + +async function getTicket(key, fallback) { + return await Factory.Get(Ticket, key, fallback) +} + +async function setTicket(key, value, expiresIn) { + await Factory.Set(Ticket, key, value, expiresIn) +} + +async function removeTicket(key) { + await Factory.Remove(Ticket, key) +} + +module.exports = { + getAccessToken, + setAccessToken, + removeAccessToken, + getUserAccessToken, + setUserAccessToken, + removeUserAccessToken, + getSessionKey, + setSessionKey, + removeSessionKey, + getEncryptKey, + setEncryptKey, + removeEncryptKey, + getTicket, + setTicket, + removeTicket, + PlatformType, + WeixinServer, + ErrorCodeType +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/node_modules/uni-config-center/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/node_modules/uni-config-center/index.js new file mode 100644 index 0000000..e14fb3b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/node_modules/uni-config-center/index.js @@ -0,0 +1 @@ +"use strict";var t=require("fs"),r=require("path");function e(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var n=e(t),o=e(r),i="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};var u=function(t){var r={exports:{}};return t(r,r.exports),r.exports}((function(t,r){var e="__lodash_hash_undefined__",n=9007199254740991,o="[object Arguments]",u="[object Function]",c="[object Object]",a=/^\[object .+?Constructor\]$/,f=/^(?:0|[1-9]\d*)$/,s={};s["[object Float32Array]"]=s["[object Float64Array]"]=s["[object Int8Array]"]=s["[object Int16Array]"]=s["[object Int32Array]"]=s["[object Uint8Array]"]=s["[object Uint8ClampedArray]"]=s["[object Uint16Array]"]=s["[object Uint32Array]"]=!0,s[o]=s["[object Array]"]=s["[object ArrayBuffer]"]=s["[object Boolean]"]=s["[object DataView]"]=s["[object Date]"]=s["[object Error]"]=s[u]=s["[object Map]"]=s["[object Number]"]=s[c]=s["[object RegExp]"]=s["[object Set]"]=s["[object String]"]=s["[object WeakMap]"]=!1;var l="object"==typeof i&&i&&i.Object===Object&&i,h="object"==typeof self&&self&&self.Object===Object&&self,p=l||h||Function("return this")(),_=r&&!r.nodeType&&r,v=_&&t&&!t.nodeType&&t,d=v&&v.exports===_,y=d&&l.process,g=function(){try{var t=v&&v.require&&v.require("util").types;return t||y&&y.binding&&y.binding("util")}catch(t){}}(),b=g&&g.isTypedArray;function j(t,r,e){switch(e.length){case 0:return t.call(r);case 1:return t.call(r,e[0]);case 2:return t.call(r,e[0],e[1]);case 3:return t.call(r,e[0],e[1],e[2])}return t.apply(r,e)}var w,O,m,A=Array.prototype,z=Function.prototype,M=Object.prototype,x=p["__core-js_shared__"],C=z.toString,F=M.hasOwnProperty,U=(w=/[^.]+$/.exec(x&&x.keys&&x.keys.IE_PROTO||""))?"Symbol(src)_1."+w:"",S=M.toString,I=C.call(Object),P=RegExp("^"+C.call(F).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),T=d?p.Buffer:void 0,q=p.Symbol,E=p.Uint8Array,$=T?T.allocUnsafe:void 0,D=(O=Object.getPrototypeOf,m=Object,function(t){return O(m(t))}),k=Object.create,B=M.propertyIsEnumerable,N=A.splice,L=q?q.toStringTag:void 0,R=function(){try{var t=_t(Object,"defineProperty");return t({},"",{}),t}catch(t){}}(),G=T?T.isBuffer:void 0,V=Math.max,W=Date.now,H=_t(p,"Map"),J=_t(Object,"create"),K=function(){function t(){}return function(r){if(!Mt(r))return{};if(k)return k(r);t.prototype=r;var e=new t;return t.prototype=void 0,e}}();function Q(t){var r=-1,e=null==t?0:t.length;for(this.clear();++r-1},X.prototype.set=function(t,r){var e=this.__data__,n=nt(e,t);return n<0?(++this.size,e.push([t,r])):e[n][1]=r,this},Y.prototype.clear=function(){this.size=0,this.__data__={hash:new Q,map:new(H||X),string:new Q}},Y.prototype.delete=function(t){var r=pt(this,t).delete(t);return this.size-=r?1:0,r},Y.prototype.get=function(t){return pt(this,t).get(t)},Y.prototype.has=function(t){return pt(this,t).has(t)},Y.prototype.set=function(t,r){var e=pt(this,t),n=e.size;return e.set(t,r),this.size+=e.size==n?0:1,this},Z.prototype.clear=function(){this.__data__=new X,this.size=0},Z.prototype.delete=function(t){var r=this.__data__,e=r.delete(t);return this.size=r.size,e},Z.prototype.get=function(t){return this.__data__.get(t)},Z.prototype.has=function(t){return this.__data__.has(t)},Z.prototype.set=function(t,r){var e=this.__data__;if(e instanceof X){var n=e.__data__;if(!H||n.length<199)return n.push([t,r]),this.size=++e.size,this;e=this.__data__=new Y(n)}return e.set(t,r),this.size=e.size,this};var it,ut=function(t,r,e){for(var n=-1,o=Object(t),i=e(t),u=i.length;u--;){var c=i[it?u:++n];if(!1===r(o[c],c,o))break}return t};function ct(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":L&&L in Object(t)?function(t){var r=F.call(t,L),e=t[L];try{t[L]=void 0;var n=!0}catch(t){}var o=S.call(t);n&&(r?t[L]=e:delete t[L]);return o}(t):function(t){return S.call(t)}(t)}function at(t){return xt(t)&&ct(t)==o}function ft(t){return!(!Mt(t)||function(t){return!!U&&U in t}(t))&&(At(t)?P:a).test(function(t){if(null!=t){try{return C.call(t)}catch(t){}try{return t+""}catch(t){}}return""}(t))}function st(t){if(!Mt(t))return function(t){var r=[];if(null!=t)for(var e in Object(t))r.push(e);return r}(t);var r=dt(t),e=[];for(var n in t)("constructor"!=n||!r&&F.call(t,n))&&e.push(n);return e}function lt(t,r,e,n,o){t!==r&&ut(r,(function(i,u){if(o||(o=new Z),Mt(i))!function(t,r,e,n,o,i,u){var a=yt(t,e),f=yt(r,e),s=u.get(f);if(s)return void rt(t,e,s);var l=i?i(a,f,e+"",t,r,u):void 0,h=void 0===l;if(h){var p=wt(f),_=!p&&mt(f),v=!p&&!_&&Ct(f);l=f,p||_||v?wt(a)?l=a:xt(j=a)&&Ot(j)?l=function(t,r){var e=-1,n=t.length;r||(r=Array(n));for(;++e-1&&t%1==0&&t0){if(++r>=800)return arguments[0]}else r=0;return t.apply(void 0,arguments)}}(R?function(t,r){return R(t,"toString",{configurable:!0,enumerable:!1,value:(e=r,function(){return e}),writable:!0});var e}:It);function bt(t,r){return t===r||t!=t&&r!=r}var jt=at(function(){return arguments}())?at:function(t){return xt(t)&&F.call(t,"callee")&&!B.call(t,"callee")},wt=Array.isArray;function Ot(t){return null!=t&&zt(t.length)&&!At(t)}var mt=G||function(){return!1};function At(t){if(!Mt(t))return!1;var r=ct(t);return r==u||"[object GeneratorFunction]"==r||"[object AsyncFunction]"==r||"[object Proxy]"==r}function zt(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=n}function Mt(t){var r=typeof t;return null!=t&&("object"==r||"function"==r)}function xt(t){return null!=t&&"object"==typeof t}var Ct=b?function(t){return function(r){return t(r)}}(b):function(t){return xt(t)&&zt(t.length)&&!!s[ct(t)]};function Ft(t){return Ot(t)?tt(t,!0):st(t)}var Ut,St=(Ut=function(t,r,e){lt(t,r,e)},ht((function(t,r){var e=-1,n=r.length,o=n>1?r[n-1]:void 0,i=n>2?r[2]:void 0;for(o=Ut.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,r,e){if(!Mt(e))return!1;var n=typeof r;return!!("number"==n?Ot(e)&&vt(r,e.length):"string"==n&&r in e)&&bt(e[r],t)}(r[0],r[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++ec.call(t,r);class f{constructor({pluginId:t,defaultConfig:r={},customMerge:e,root:n}){this.pluginId=t,this.defaultConfig=r,this.pluginConfigPath=o.default.resolve(n||__dirname,t),this.customMerge=e,this._config=void 0}resolve(t){return o.default.resolve(this.pluginConfigPath,t)}hasFile(t){return n.default.existsSync(this.resolve(t))}requireFile(t){try{return require(this.resolve(t))}catch(t){if("MODULE_NOT_FOUND"===t.code)return;throw t}}_getUserConfig(){return this.requireFile("config.json")}config(t,r){this._config||(this._config=(this.customMerge||u)(this.defaultConfig,this._getUserConfig()));let e=this._config;return t?function(t,r,e){if("number"==typeof r)return t[r];if("symbol"==typeof r)return a(t,r)?t[r]:e;const n="string"!=typeof(o=r)?o:o.split(".").reduce(((t,r)=>(r.split(/\[([^}]+)\]/g).forEach((r=>r&&t.push(r))),t)),[]);var o;let i=t;for(let t=0;t { + keyArray.push(key[name]) + }) + keyArray.push(this._type) + return keyArray.join(':') + } + + getValue(value) { + return value + } + + getExpiresIn(value) { + if (value !== undefined) { + return value + } + return -1 + } + + validateKey(key) { + Validator.Key(this._keys, key) + } + + validateValue(value) { + Validator.Value(value) + } + + create(key, fallback) { + const keyString = this.getKeyString(key) + const options = { + layers: [{ + type: 'database', + key: keyString + }, { + type: 'redis', + key: keyString + }] + } + if (fallback !== null) { + const fallbackFunction = fallback || this.fallback + if (fallbackFunction) { + options.fallback = async () => { + return await fallbackFunction(key) + } + } + } + return new CacheKeyCascade(options) + } +} +Storage.Prefix = "uni-id" + +const Factory = { + + async Get(T, key, fallback) { + return await Factory.MakeUnique(T).get(key, fallback) + }, + + async Set(T, key, value, expiresIn) { + await Factory.MakeUnique(T).set(key, value, expiresIn) + }, + + async Remove(T, key) { + await Factory.MakeUnique(T).remove(key) + }, + + MakeUnique(T) { + return new T() + } +} + +module.exports = { + Storage, + Factory +}; diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/uni-cloud-cache.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/uni-cloud-cache.js new file mode 100644 index 0000000..2e4286b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/uni-cloud-cache.js @@ -0,0 +1,324 @@ +const db = uniCloud.database() + +function getType(value) { + return Object.prototype.toString.call(value).slice(8, -1).toLowerCase() +} + +const validator = { + key: function(value) { + const err = new Error('Invalid key') + if (typeof value !== 'string') { + throw err + } + const valueTrim = value.trim() + if (!valueTrim || valueTrim !== value) { + throw err + } + }, + value: function(value) { + // 仅作简单校验 + const type = getType(value) + const validValueType = ['null', 'number', 'string', 'array', 'object'] + if (validValueType.indexOf(type) === -1) { + throw new Error('Invalid value type') + } + }, + duration: function(value) { + const err = new Error('Invalid duration') + if (value === undefined) { + return + } + if (typeof value !== 'number' || value === 0) { + throw err + } + } +} + +/** + * 入库时 expired 为过期时间对应的时间戳,永不过期用-1表示 + * 返回结果时 与redis对齐,-1表示永不过期,-2表示已过期或不存在 + */ +class DatabaseCache { + constructor({ + collection = 'opendb-open-data' + } = {}) { + this.type = 'db' + this.collection = db.collection(collection) + } + + _serializeValue(value) { + return value === undefined ? null : JSON.stringify(value) + } + + _deserializeValue(value) { + return value ? JSON.parse(value) : value + } + + async set(key, value, duration) { + validator.key(key) + validator.value(value) + validator.duration(duration) + value = this._serializeValue(value) + await this.collection.doc(key).set({ + value, + expired: duration && duration !== -1 ? Date.now() + (duration * 1000) : -1 + }) + } + + async _getWithDuration(key) { + const getKeyRes = await this.collection.doc(key).get() + const record = getKeyRes.data[0] + if (!record) { + return { + value: null, + duration: -2 + } + } + const value = this._deserializeValue(record.value) + const expired = record.expired + if (expired === -1) { + return { + value, + duration: -1 + } + } + const duration = expired - Date.now() + if (duration <= 0) { + await this.remove(key) + return { + value: null, + duration: -2 + } + } + return { + value, + duration: Math.floor(duration / 1000) + } + } + + async get(key, { + withDuration = true + } = {}) { + const result = await this._getWithDuration(key) + if (!withDuration) { + delete result.duration + } + return result + } + + async remove(key) { + await this.collection.doc(key).remove() + } +} + +class RedisCache { + constructor() { + this.type = 'redis' + this.redis = uniCloud.redis() + } + + _serializeValue(value) { + return value === undefined ? null : JSON.stringify(value) + } + + _deserializeValue(value) { + return value ? JSON.parse(value) : value + } + + async set(key, value, duration) { + validator.key(key) + validator.value(value) + validator.duration(duration) + value = this._serializeValue(value) + if (!duration || duration === -1) { + await this.redis.set(key, value) + } else { + await this.redis.set(key, value, 'EX', duration) + } + } + + async get(key, { + withDuration = false + } = {}) { + let value = await this.redis.get(key) + value = this._deserializeValue(value) + if (!withDuration) { + return { + value + } + } + const durationSecond = await this.redis.ttl(key) + let duration + switch (durationSecond) { + case -1: + duration = -1 + break + case -2: + duration = -2 + break + default: + duration = durationSecond + break + } + return { + value, + duration + } + } + + async remove(key) { + await this.redis.del(key) + } +} + +class Cache { + constructor({ + type, + collection + } = {}) { + if (type === 'database') { + return new DatabaseCache({ + collection + }) + } else if (type === 'redis') { + return new RedisCache() + } else { + throw new Error('Invalid cache type') + } + } +} + +class CacheKey { + constructor({ + type, + collection, + cache, + key, + fallback + } = {}) { + this.cache = cache || new Cache({ + type, + collection + }) + this.key = key + this.fallback = fallback + } + + async set(value, duration) { + await this.cache.set(this.key, value, duration) + } + + async setWithSync(value, duration, syncMethod) { + await Promise.all([ + this.set(this.key, value, duration), + syncMethod(value, duration) + ]) + } + + async get() { + let { + value, + duration + } = await this.cache.get(this.key) + if (value !== null && value !== undefined) { + return { + value, + duration + } + } + if (!this.fallback) { + return { + value: null, + duration: -2 + } + } + const fallbackResult = await this.fallback() + value = fallbackResult.value + duration = fallbackResult.duration + if (value !== null && duration !== undefined) { + await this.cache.set(this.key, value, duration) + } + return { + value, + duration + } + } + + async remove() { + await this.cache.remove(this.key) + } +} + +class CacheKeyCascade { + constructor({ + layers, // [{cache, type, collection, key}] 从低级到高级排序,[DbCacheKey, RedisCacheKey] + fallback + } = {}) { + this.layers = layers + this.cacheLayers = [] + let lastCacheKey + for (let i = 0; i < layers.length; i++) { + const { + type, + cache, + collection, + key + } = layers[i] + const lastCacheKeyTemp = lastCacheKey + try { + const currentCacheKey = new CacheKey({ + type, + collection, + cache, + key, + fallback: i === 0 ? fallback : function() { + return lastCacheKeyTemp.get() + } + }) + this.cacheLayers.push(currentCacheKey) + lastCacheKey = currentCacheKey + } catch (e) {} + } + this.highLevelCache = lastCacheKey + } + + async set(value, duration) { + return Promise.all( + this.cacheLayers.map(item => { + return item.set(value, duration) + }) + ) + } + + async setWithSync(value, duration, syncMethod) { + const setPromise = this.cacheLayers.map(item => { + return item.set(value, duration) + }) + return Promise.all( + [ + ...setPromise, + syncMethod(value, duration) + ] + ) + } + + async get() { + return this.highLevelCache.get() + } + + async remove() { + await Promise.all( + this.cacheLayers.map(cacheKeyItem => { + return cacheKeyItem.remove() + }) + ) + } +} + +module.exports = { + Cache, + DatabaseCache, + RedisCache, + CacheKey, + CacheKeyCascade +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/validator.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/validator.js new file mode 100644 index 0000000..47a455b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/validator.js @@ -0,0 +1,31 @@ +const Validator = { + + Key(keyArray, parameters) { + for (let i = 0; i < keyArray.length; i++) { + const keyName = keyArray[i] + if (typeof parameters[keyName] !== 'string') { + Validator.ThrowNewError(`Invalid ${keyName}`) + } + if (parameters[keyName].length < 1) { + Validator.ThrowNewError(`Invalid ${keyName}`) + } + } + }, + + Value(value) { + if (value === undefined) { + Validator.ThrowNewError('Invalid Value') + } + if (typeof value !== 'object') { + Validator.ThrowNewError('Invalid Value Type') + } + }, + + ThrowNewError(message) { + throw new Error(message) + } +} + +module.exports = { + Validator +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/weixin-server.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/weixin-server.js new file mode 100644 index 0000000..0a0c811 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/node_modules/uni-open-bridge-common/weixin-server.js @@ -0,0 +1,202 @@ +'use strict'; + +const crypto = require('crypto') + +const { + HTTP_STATUS +} = require('./consts.js') + +const { + BridgeError +} = require('./bridge-error.js') + +class WeixinServer { + + constructor(options = {}) { + this._appid = options.appid + this._secret = options.secret + } + + getAccessToken() { + return uniCloud.httpclient.request(WeixinServer.AccessToken_Url, { + dataType: 'json', + method: 'POST', + data: { + appid: this._appid, + secret: this._secret, + grant_type: "client_credential" + } + }) + } + + // 使用客户端获取的 code 从微信服务器换取 openid,code 仅可使用一次 + codeToSession(code) { + return uniCloud.httpclient.request(WeixinServer.Code2Session_Url, { + dataType: 'json', + data: { + appid: this._appid, + secret: this._secret, + js_code: code, + grant_type: 'authorization_code' + } + }) + } + + getUserEncryptKey({ + access_token, + openid, + session_key + }) { + console.log(access_token, openid, session_key); + const signature = crypto.createHmac('sha256', session_key).update('').digest('hex') + return uniCloud.httpclient.request(WeixinServer.User_Encrypt_Key_Url, { + dataType: 'json', + method: 'POST', + dataAsQueryString: true, + data: { + access_token, + openid: openid, + signature: signature, + sig_method: 'hmac_sha256' + } + }) + } + + getH5AccessToken() { + return uniCloud.httpclient.request(WeixinServer.AccessToken_H5_Url, { + dataType: 'json', + method: 'GET', + data: { + appid: this._appid, + secret: this._secret, + grant_type: "client_credential" + } + }) + } + + getH5Ticket(access_token) { + return uniCloud.httpclient.request(WeixinServer.Ticket_Url, { + dataType: 'json', + dataAsQueryString: true, + method: 'POST', + data: { + access_token + } + }) + } + + getH5AccessTokenForEip() { + return uniCloud.httpProxyForEip.postForm(WeixinServer.AccessToken_H5_Url, { + appid: this._appid, + secret: this._secret, + grant_type: "client_credential" + }, { + dataType: 'json' + }) + } + + getH5TicketForEip(access_token) { + return uniCloud.httpProxyForEip.postForm(WeixinServer.Ticket_Url, { + access_token + }, { + dataType: 'json', + dataAsQueryString: true + }) + } +} + +WeixinServer.AccessToken_Url = 'https://api.weixin.qq.com/cgi-bin/token' +WeixinServer.Code2Session_Url = 'https://api.weixin.qq.com/sns/jscode2session' +WeixinServer.User_Encrypt_Key_Url = 'https://api.weixin.qq.com/wxa/business/getuserencryptkey' +WeixinServer.AccessToken_H5_Url = 'https://api.weixin.qq.com/cgi-bin/token' +WeixinServer.Ticket_Url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi' + +WeixinServer.GetMPAccessToken = function(options) { + return new WeixinServer(options).getAccessToken() +} + +WeixinServer.GetCodeToSession = function(options) { + return new WeixinServer(options).codeToSession(options.code) +} + +WeixinServer.GetUserEncryptKey = function(options) { + return new WeixinServer(options).getUserEncryptKey(options) +} + +WeixinServer.GetH5AccessToken = function(options) { + return new WeixinServer(options).getH5AccessToken() +} + +WeixinServer.GetH5Ticket = function(options) { + return new WeixinServer(options).getH5Ticket(options.access_token) +} + +//////////////////////////////////////////////////////////////// + +function isAliyun() { + return (uniCloud.getCloudInfos()[0].provider === 'aliyun') +} + +WeixinServer.GetResponseData = function(response) { + console.log("WeixinServer::response", response) + + if (!(response.status === HTTP_STATUS.SUCCESS || response.statusCodeValue === HTTP_STATUS.SUCCESS)) { + throw new BridgeError(response.status || response.statusCodeValue, response.status || response.statusCodeValue) + } + + const responseData = response.data || response.body + + if (responseData.errcode !== undefined && responseData.errcode !== 0) { + throw new BridgeError(responseData.errcode, responseData.errmsg) + } + + return responseData +} + +WeixinServer.GetMPAccessTokenData = async function(options) { + const response = await new WeixinServer(options).getAccessToken() + return WeixinServer.GetResponseData(response) +} + +WeixinServer.GetCodeToSessionData = async function(options) { + const response = await new WeixinServer(options).codeToSession(options.code) + return WeixinServer.GetResponseData(response) +} + +WeixinServer.GetUserEncryptKeyData = async function(options) { + const response = await new WeixinServer(options).getUserEncryptKey(options) + return WeixinServer.GetResponseData(response) +} + +WeixinServer.GetH5AccessTokenData = async function(options) { + const ws = new WeixinServer(options) + let response + if (isAliyun()) { + response = await ws.getH5AccessTokenForEip() + if (typeof response === 'string') { + response = JSON.parse(response) + } + } else { + response = await ws.getH5AccessToken() + } + return WeixinServer.GetResponseData(response) +} + +WeixinServer.GetH5TicketData = async function(options) { + const ws = new WeixinServer(options) + let response + if (isAliyun()) { + response = await ws.getH5TicketForEip(options.access_token) + if (typeof response === 'string') { + response = JSON.parse(response) + } + } else { + response = await ws.getH5Ticket(options.access_token) + } + return WeixinServer.GetResponseData(response) +} + + +module.exports = { + WeixinServer +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package-lock.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package-lock.json new file mode 100644 index 0000000..56529b2 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package-lock.json @@ -0,0 +1,148 @@ +{ + "name": "uni-id-co", + "version": "1.0.27", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "uni-captcha": { + "version": "file:../../../../uni-captcha/uniCloud/cloudfunctions/common/uni-captcha", + "requires": { + "uni-config-center": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + }, + "dependencies": { + "uni-config-center": { + "version": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + } + } + }, + "uni-config-center": { + "version": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + }, + "uni-id-common": { + "version": "file:../../../../uni-id-common/uniCloud/cloudfunctions/common/uni-id-common", + "requires": { + "uni-config-center": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + }, + "dependencies": { + "uni-config-center": { + "version": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + } + } + }, + "uni-open-bridge-common": { + "version": "file:../../../../uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common", + "requires": { + "uni-config-center": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + }, + "dependencies": { + "uni-config-center": { + "version": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + } + } + } + } +} 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 new file mode 100644 index 0000000..6cd370a --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package.json @@ -0,0 +1,23 @@ +{ + "name": "uni-id-co", + "version": "1.0.27", + "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/opendb-device.schema.json b/uni_modules/uni-id-pages/uniCloud/database/opendb-device.schema.json new file mode 100644 index 0000000..c3591cc --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/database/opendb-device.schema.json @@ -0,0 +1,142 @@ +{ + "bsonType": "object", + "required": [], + "permission": { + "read": false, + "create": true, + "update": false, + "delete": false + }, + "properties": { + "_id": { + "description": "ID,系统自动生成" + }, + "appid": { + "bsonType": "string", + "description": "DCloud appid" + }, + "device_id": { + "bsonType": "string", + "description": "设备唯一标识" + }, + "vendor": { + "bsonType": "string", + "description": "设备厂商" + }, + "push_clientid": { + "bsonType": "string", + "description": "推送设备客户端标识" + }, + "imei": { + "bsonType": "string", + "description": "国际移动设备识别码IMEI(International Mobile Equipment Identity)" + }, + "oaid": { + "bsonType": "string", + "description": "移动智能设备标识公共服务平台提供的匿名设备标识符(OAID)" + }, + "idfa": { + "bsonType": "string", + "description": "iOS平台配置应用使用广告标识(IDFA)" + }, + "imsi": { + "bsonType": "string", + "description": "国际移动用户识别码(International Mobile Subscriber Identification Number)" + }, + "model": { + "bsonType": "string", + "description": "设备型号" + }, + "platform": { + "bsonType": "string", + "description": "平台类型" + }, + "uni_platform": { + "bsonType": "string", + "description": "uni-app 运行平台,与条件编译平台相同。" + }, + "os_name": { + "bsonType": "string", + "description": "ios|android|windows|mac|linux " + }, + "os_version": { + "bsonType": "string", + "description": "操作系统版本号 " + }, + "os_language": { + "bsonType": "string", + "description": "操作系统语言 " + }, + "os_theme": { + "bsonType": "string", + "description": "操作系统主题 light|dark" + }, + "pixel_ratio": { + "bsonType": "string", + "description": "设备像素比 " + }, + "network_model": { + "bsonType": "string", + "description": "设备网络型号wifi\/3G\/4G\/" + }, + "window_width": { + "bsonType": "string", + "description": "设备窗口宽度 " + }, + "window_height": { + "bsonType": "string", + "description": "设备窗口高度" + }, + "screen_width": { + "bsonType": "string", + "description": "设备屏幕宽度" + }, + "screen_height": { + "bsonType": "string", + "description": "设备屏幕高度" + }, + "rom_name": { + "bsonType": "string", + "description": "rom 名称" + }, + "rom_version": { + "bsonType": "string", + "description": "rom 版本" + }, + "location_latitude": { + "bsonType": "double", + "description": "纬度" + }, + "location_longitude": { + "bsonType": "double", + "description": "经度" + }, + "location_country": { + "bsonType": "string", + "description": "国家" + }, + "location_province": { + "bsonType": "string", + "description": "省份" + }, + "location_city": { + "bsonType": "string", + "description": "城市" + }, + "create_date": { + "bsonType": "timestamp", + "description": "创建时间", + "forceDefaultValue": { + "$env": "now" + } + }, + "last_update_date": { + "bsonType": "timestamp", + "description": "最后一次修改时间", + "forceDefaultValue": { + "$env": "now" + } + } + }, + "version": "0.0.1" +} \ No newline at end of file diff --git a/uni_modules/uni-id-pages/uniCloud/database/uni-id-device.schema.json b/uni_modules/uni-id-pages/uniCloud/database/uni-id-device.schema.json new file mode 100644 index 0000000..4981d75 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/database/uni-id-device.schema.json @@ -0,0 +1,83 @@ +{ + "bsonType": "object", + "required": [ + "user_id" + ], + "properties": { + "_id": { + "description": "ID,系统自动生成" + }, + "user_id": { + "bsonType": "string", + "description": "用户id,参考uni-id-users表" + }, + "ua": { + "bsonType": "string", + "description": "userAgent" + }, + "uuid": { + "bsonType": "string", + "description": "设备唯一标识(需要加密存储)" + }, + "os_name": { + "bsonType": "string", + "description": "ios|android|windows|mac|linux " + }, + "os_version": { + "bsonType": "string", + "description": "操作系统版本号 " + }, + "os_language": { + "bsonType": "string", + "description": "操作系统语言 " + }, + "os_theme": { + "bsonType": "string", + "description": "操作系统主题 light|dark" + }, + "vendor": { + "bsonType": "string", + "description": "设备厂商" + }, + "push_clientid": { + "bsonType": "string", + "description": "推送设备客户端标识" + }, + "imei": { + "bsonType": "string", + "description": "国际移动设备识别码IMEI(International Mobile Equipment Identity)" + }, + "oaid": { + "bsonType": "string", + "description": "移动智能设备标识公共服务平台提供的匿名设备标识符(OAID)" + }, + "idfa": { + "bsonType": "string", + "description": "iOS平台配置应用使用广告标识(IDFA)" + }, + "model": { + "bsonType": "string", + "description": "设备型号" + }, + "platform": { + "bsonType": "string", + "description": "平台类型" + }, + "create_date": { + "bsonType": "timestamp", + "description": "创建时间", + "forceDefaultValue": { + "$env": "now" + } + }, + "last_active_date": { + "bsonType": "timestamp", + "description": "最后登录时间" + }, + "last_active_ip": { + "bsonType": "string", + "description": "最后登录IP" + } + }, + "version": "0.0.1" +} \ No newline at end of file diff --git a/uni_modules/uni-id-pages/uniCloud/database/uni-id-log.schema.json b/uni_modules/uni-id-pages/uniCloud/database/uni-id-log.schema.json new file mode 100644 index 0000000..ff4f797 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/database/uni-id-log.schema.json @@ -0,0 +1,71 @@ +{ + "bsonType": "object", + "required": ["user_id"], + "permission": { + "read": "'READ_UNI_ID_LOG' in auth.permission" + }, + "properties": { + "_id": { + "description": "ID,系统自动生成" + }, + "create_date": { + "bsonType": "timestamp", + "description": "创建时间", + "forceDefaultValue": { + "$env": "now" + } + }, + "device_uuid": { + "bsonType": "string", + "description": "设备唯一标识" + }, + "ip": { + "bsonType": "string", + "description": "ip地址" + }, + "state": { + "bsonType": "int", + "description": "结果:0 失败、1 成功" + }, + "type": { + "bsonType": "string", + "description": "操作类型", + "enum": [ + "logout", + "login", + "register", + "reset-pwd", + "bind-mobile", + "bind-weixin", + "bind-qq", + "bind-apple", + "bind-alipay" + ] + }, + "ua": { + "bsonType": "string", + "description": "userAgent" + }, + "user_id": { + "bsonType": "string", + "foreignKey": "uni-id-users._id", + "description": "用户id,参考uni-id-users表" + }, + "username": { + "bsonType": "string", + "description": "用户名" + }, + "email": { + "bsonType": "string", + "description": "邮箱" + }, + "mobile": { + "bsonType": "string", + "description": "手机号" + }, + "appid": { + "bsonType": "string", + "description": "客户端DCloud AppId" + } + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/database/uni-id-permissions.schema.json b/uni_modules/uni-id-pages/uniCloud/database/uni-id-permissions.schema.json new file mode 100644 index 0000000..25209cb --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/database/uni-id-permissions.schema.json @@ -0,0 +1,52 @@ +{ + "bsonType": "object", + "required": ["permission_id", "permission_name"], + "permission": { + "read": "'READ_UNI_ID_PERMISSIONS' in auth.permission", + "create": "'CREATE_UNI_ID_PERMISSIONS' in auth.permission", + "update": "'UPDATE_UNI_ID_PERMISSIONS' in auth.permission", + "delete": "'DELETE_UNI_ID_PERMISSIONS' in auth.permission" + }, + "properties": { + "_id": { + "description": "存储文档 ID,系统自动生成" + }, + "comment": { + "bsonType": "string", + "component": { + "name": "textarea" + }, + "description": "备注", + "label": "备注", + "title": "备注", + "trim": "both" + }, + "create_date": { + "bsonType": "timestamp", + "description": "创建时间", + "forceDefaultValue": { + "$env": "now" + } + }, + "permission_id": { + "bsonType": "string", + "component": { + "name": "input" + }, + "description": "权限唯一标识,不可修改,不允许重复", + "label": "权限标识", + "title": "权限ID", + "trim": "both" + }, + "permission_name": { + "bsonType": "string", + "component": { + "name": "input" + }, + "description": "权限名称", + "label": "权限名称", + "title": "权限名称", + "trim": "both" + } + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/database/uni-id-roles.schema.json b/uni_modules/uni-id-pages/uniCloud/database/uni-id-roles.schema.json new file mode 100644 index 0000000..e2fe322 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/database/uni-id-roles.schema.json @@ -0,0 +1,50 @@ +{ + "bsonType": "object", + "required": ["role_id", "role_name"], + "permission": { + "read": "'READ_UNI_ID_ROLES' in auth.permission", + "create": "'CREATE_UNI_ID_ROLES' in auth.permission", + "update": "'UPDATE_UNI_ID_ROLES' in auth.permission", + "delete": "'DELETE_UNI_ID_ROLES' in auth.permission" + }, + "properties": { + "_id": { + "description": "存储文档 ID,系统自动生成" + }, + "comment": { + "title": "备注", + "bsonType": "string", + "description": "备注", + "trim": "both" + }, + "create_date": { + "bsonType": "timestamp", + "description": "创建时间", + "forceDefaultValue": { + "$env": "now" + } + }, + "permission": { + "title": "权限", + "bsonType": "array", + "foreignKey": "uni-id-permissions.permission_id", + "description": "角色拥有的权限列表", + "enum": { + "collection": "uni-id-permissions", + "field": "permission_name as text, permission_id as value" + } + }, + "role_id": { + "title": "唯一ID", + "bsonType": "string", + "description": "角色唯一标识,不可修改,不允许重复", + "trim": "both" + }, + "role_name": { + "title": "名称", + "bsonType": "string", + "description": "角色名称", + "trim": "both" + } + } +} 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 new file mode 100644 index 0000000..53cc584 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/database/uni-id-users.schema.json @@ -0,0 +1,456 @@ +{ + "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": "角色" + }, + "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": [] +} \ No newline at end of file diff --git a/uni_modules/uni-open-bridge-common/changelog.md b/uni_modules/uni-open-bridge-common/changelog.md new file mode 100644 index 0000000..b3a56b2 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/changelog.md @@ -0,0 +1,8 @@ +## 1.0.4(2022-09-21) +- 新增 支持使用阿里云固定IP获取微信公众号H5凭据 access_token、ticket,开发者需要在微信公众平台配置阿里云固定IP,[固定IP详情](https://uniapp.dcloud.net.cn/uniCloud/cf-functions.html#aliyun-eip) +## 1.0.3(2022-09-06) +- 修复 过期时间问题,容错 AccessToken 默认 fallback 逻辑,当微信服务器没有返回过期时间时设置为2小时后过期 +## 1.0.2(2022-09-02) +- 新增 依赖数据表schema opendb-open-data +## 1.0.0(2022-08-22) +- 首次发布 diff --git a/uni_modules/uni-open-bridge-common/package.json b/uni_modules/uni-open-bridge-common/package.json new file mode 100644 index 0000000..487f353 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/package.json @@ -0,0 +1,84 @@ +{ + "id": "uni-open-bridge-common", + "displayName": "uni-open-bridge-common", + "version": "1.0.4", + "description": "统一接管微信等三方平台认证凭据", + "keywords": [ + "uni-open-bridge-common", + "access_token", + "session_key", + "ticket" +], + "repository": "", + "engines": { + "HBuilderX": "^3.5.2" + }, + "dcloudext": { + "type": "unicloud-template-function", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "App": { + "app-vue": "u", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "u", + "Android Browser": "u", + "微信浏览器(Android)": "u", + "QQ浏览器(Android)": "u" + }, + "H5-pc": { + "Chrome": "u", + "IE": "u", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-open-bridge-common/readme.md b/uni_modules/uni-open-bridge-common/readme.md new file mode 100644 index 0000000..3892384 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/readme.md @@ -0,0 +1,5 @@ +# uni-open-bridge-common + +`uni-open-bridge-common` 是统一接管微信等三方平台认证凭据(包括但不限于`access_token`、`session_key`、`encrypt_key`、`ticket`)的开源库。 + +文档链接 [https://uniapp.dcloud.net.cn/uniCloud/uni-open-bridge#common](https://uniapp.dcloud.net.cn/uniCloud/uni-open-bridge#common) diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/bridge-error.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/bridge-error.js new file mode 100644 index 0000000..95160a4 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/bridge-error.js @@ -0,0 +1,26 @@ +'use strict'; + +class BridgeError extends Error { + + constructor(code, message) { + super(message) + + this._code = code + } + + get code() { + return this._code + } + + get errCode() { + return this._code + } + + get errMsg() { + return this.message + } +} + +module.exports = { + BridgeError +} diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/config.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/config.js new file mode 100644 index 0000000..2fb7d7b --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/config.js @@ -0,0 +1,95 @@ +'use strict'; + +const { + PlatformType +} = require('./consts.js') + +const configCenter = require('uni-config-center') + +const OauthConfig = { + 'weixin-mp': ['mp-weixin', 'oauth', 'weixin'], + 'weixin-h5': ['web', 'oauth', 'weixin-h5'] +} + +class ConfigBase { + + constructor() { + this._ready = false + this._uniId = null + + const uniIdConfig = configCenter({ + pluginId: 'uni-id' + }) + + this._uniId = uniIdConfig.config() + + this._ready = true + } + + getAppConfig(appid) { + if (Array.isArray(this._uniId)) { + return this._uniId.find((item) => { + return (item.dcloudAppid === appid) + }) + } + return this._uniId + } + + get ready() { + return this._ready + } +} + +class AppConfig extends ConfigBase { + + constructor() { + super() + } + + get(appid, platform) { + if (!this.isSupport(platform)) { + return null + } + + let appConfig = this.getAppConfig(appid) + if (!appConfig) { + return null + } + + return this.getOauthConfig(appConfig, platform) + } + + isSupport(platformName) { + return (AppConfig.Support_Platforms.indexOf(platformName) >= 0) + } + + getOauthConfig(appConfig, platformName) { + let tree = OauthConfig[platformName] + let node = appConfig + for (let i = 0; i < tree.length; i++) { + let nodeName = tree[i] + if (node[nodeName]) { + node = node[nodeName] + } else { + node = null + break + } + } + + if (node && node.appid && node.appsecret) { + return { + appid: node.appid, + secret: node.appsecret + } + } + + return null + } +} + +AppConfig.Support_Platforms = [PlatformType.WEIXIN_MP, PlatformType.WEIXIN_H5] + + +module.exports = { + AppConfig +}; diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/consts.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/consts.js new file mode 100644 index 0000000..6da817b --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/consts.js @@ -0,0 +1,26 @@ +'use strict'; + +const TAG = "UNI_OPEN_BRIDGE" + +const HTTP_STATUS = { + SUCCESS: 200 +} + +const PlatformType = { + WEIXIN_MP: 'weixin-mp', + WEIXIN_H5: 'weixin-h5', + WEIXIN_APP: 'weixin-app', + WEIXIN_WEB: 'weixin-web', + QQ_MP: 'qq-mp', + QQ_APP: 'qq-app' +} + +const ErrorCodeType = { + SYSTEM_ERROR: TAG + "_SYSTEM_ERROR" +} + +module.exports = { + HTTP_STATUS, + PlatformType, + ErrorCodeType +} diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/index.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/index.js new file mode 100644 index 0000000..f39b0af --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/index.js @@ -0,0 +1,221 @@ +'use strict'; + +const { + PlatformType, + ErrorCodeType +} = require('./consts.js') + +const { + AppConfig +} = require('./config.js') + +const { + Storage, + Factory +} = require('./storage.js') + +const { + BridgeError +} = require('./bridge-error.js') + +const { + WeixinServer +} = require('./weixin-server.js') + +const appConfig = new AppConfig() + +class AccessToken extends Storage { + + constructor() { + super('access-token', ['dcloudAppid', 'platform']) + } + + async fallback(parameters) { + const oauthConfig = appConfig.get(parameters.dcloudAppid, parameters.platform) + let methodName + if (parameters.platform === PlatformType.WEIXIN_MP) { + methodName = 'GetMPAccessTokenData' + } else if (parameters.platform === PlatformType.WEIXIN_H5) { + methodName = 'GetH5AccessTokenData' + } else { + throw new BridgeError(ErrorCodeType.SYSTEM_ERROR, "platform invalid") + } + + const responseData = await WeixinServer[methodName](oauthConfig) + + const duration = responseData.expires_in || (60 * 60 * 2) + delete responseData.expires_in + + return { + value: responseData, + duration + } + } +} + +class UserAccessToken extends Storage { + + constructor() { + super('user-access-token', ['dcloudAppid', 'platform', 'openid']) + } +} + +class SessionKey extends Storage { + + constructor() { + super('session-key', ['dcloudAppid', 'platform', 'openid']) + } +} + +class Encryptkey extends Storage { + + constructor() { + super('encrypt-key', ['dcloudAppid', 'platform', 'openid']) + } + + getKeyString(key) { + return `${super.getKeyString(key)}-${key.version}` + } + + getExpiresIn(value) { + if (value <= 0) { + return 60 + } + return value + } + + async fallback(parameters) { + const accessToken = await Factory.Get(AccessToken, parameters) + const userSession = await Factory.Get(SessionKey, parameters) + + const responseData = await WeixinServer.GetUserEncryptKeyData({ + openid: parameters.openid, + access_token: accessToken.access_token, + session_key: userSession.session_key + }) + + const keyInfo = responseData.key_info_list.find((item) => { + return item.version = parameters.version + }) + + const value = { + encrypt_key: keyInfo.encrypt_key, + iv: keyInfo.iv + } + + return { + value, + duration: keyInfo.expire_in + } + } +} + +class Ticket extends Storage { + + constructor() { + super('ticket', ['dcloudAppid', 'platform']) + } + + async fallback(parameters) { + const accessToken = await Factory.Get(AccessToken, { + dcloudAppid: parameters.dcloudAppid, + platform: PlatformType.WEIXIN_H5 + }) + + const responseData = await WeixinServer.GetH5TicketData(accessToken) + + const duration = responseData.expires_in || (60 * 60 * 2) + delete responseData.expires_in + delete responseData.errcode + delete responseData.errmsg + + return { + value: responseData, + duration + } + } +} + + +// exports + +async function getAccessToken(key, fallback) { + return await Factory.Get(AccessToken, key, fallback) +} + +async function setAccessToken(key, value, expiresIn) { + await Factory.Set(AccessToken, key, value, expiresIn) +} + +async function removeAccessToken(key) { + await Factory.Remove(AccessToken, key) +} + +async function getUserAccessToken(key, fallback) { + return await Factory.Get(UserAccessToken, key, fallback) +} + +async function setUserAccessToken(key, value, expiresIn) { + await Factory.Set(UserAccessToken, key, value, expiresIn) +} + +async function removeUserAccessToken(key) { + await Factory.Remove(UserAccessToken, key) +} + +async function getSessionKey(key, fallback) { + return await Factory.Get(SessionKey, key, fallback) +} + +async function setSessionKey(key, value, expiresIn) { + await Factory.Set(SessionKey, key, value, expiresIn) +} + +async function removeSessionKey(key) { + await Factory.Remove(SessionKey, key) +} + +async function getEncryptKey(key, fallback) { + return await Factory.Get(Encryptkey, key, fallback) +} + +async function setEncryptKey(key, value, expiresIn) { + await Factory.Set(Encryptkey, key, value, expiresIn) +} + +async function removeEncryptKey(key) { + await Factory.Remove(Encryptkey, key) +} + +async function getTicket(key, fallback) { + return await Factory.Get(Ticket, key, fallback) +} + +async function setTicket(key, value, expiresIn) { + await Factory.Set(Ticket, key, value, expiresIn) +} + +async function removeTicket(key) { + await Factory.Remove(Ticket, key) +} + +module.exports = { + getAccessToken, + setAccessToken, + removeAccessToken, + getUserAccessToken, + setUserAccessToken, + removeUserAccessToken, + getSessionKey, + setSessionKey, + removeSessionKey, + getEncryptKey, + setEncryptKey, + removeEncryptKey, + getTicket, + setTicket, + removeTicket, + PlatformType, + WeixinServer, + ErrorCodeType +} diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/node_modules/uni-config-center/index.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/node_modules/uni-config-center/index.js new file mode 100644 index 0000000..e14fb3b --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/node_modules/uni-config-center/index.js @@ -0,0 +1 @@ +"use strict";var t=require("fs"),r=require("path");function e(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var n=e(t),o=e(r),i="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};var u=function(t){var r={exports:{}};return t(r,r.exports),r.exports}((function(t,r){var e="__lodash_hash_undefined__",n=9007199254740991,o="[object Arguments]",u="[object Function]",c="[object Object]",a=/^\[object .+?Constructor\]$/,f=/^(?:0|[1-9]\d*)$/,s={};s["[object Float32Array]"]=s["[object Float64Array]"]=s["[object Int8Array]"]=s["[object Int16Array]"]=s["[object Int32Array]"]=s["[object Uint8Array]"]=s["[object Uint8ClampedArray]"]=s["[object Uint16Array]"]=s["[object Uint32Array]"]=!0,s[o]=s["[object Array]"]=s["[object ArrayBuffer]"]=s["[object Boolean]"]=s["[object DataView]"]=s["[object Date]"]=s["[object Error]"]=s[u]=s["[object Map]"]=s["[object Number]"]=s[c]=s["[object RegExp]"]=s["[object Set]"]=s["[object String]"]=s["[object WeakMap]"]=!1;var l="object"==typeof i&&i&&i.Object===Object&&i,h="object"==typeof self&&self&&self.Object===Object&&self,p=l||h||Function("return this")(),_=r&&!r.nodeType&&r,v=_&&t&&!t.nodeType&&t,d=v&&v.exports===_,y=d&&l.process,g=function(){try{var t=v&&v.require&&v.require("util").types;return t||y&&y.binding&&y.binding("util")}catch(t){}}(),b=g&&g.isTypedArray;function j(t,r,e){switch(e.length){case 0:return t.call(r);case 1:return t.call(r,e[0]);case 2:return t.call(r,e[0],e[1]);case 3:return t.call(r,e[0],e[1],e[2])}return t.apply(r,e)}var w,O,m,A=Array.prototype,z=Function.prototype,M=Object.prototype,x=p["__core-js_shared__"],C=z.toString,F=M.hasOwnProperty,U=(w=/[^.]+$/.exec(x&&x.keys&&x.keys.IE_PROTO||""))?"Symbol(src)_1."+w:"",S=M.toString,I=C.call(Object),P=RegExp("^"+C.call(F).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),T=d?p.Buffer:void 0,q=p.Symbol,E=p.Uint8Array,$=T?T.allocUnsafe:void 0,D=(O=Object.getPrototypeOf,m=Object,function(t){return O(m(t))}),k=Object.create,B=M.propertyIsEnumerable,N=A.splice,L=q?q.toStringTag:void 0,R=function(){try{var t=_t(Object,"defineProperty");return t({},"",{}),t}catch(t){}}(),G=T?T.isBuffer:void 0,V=Math.max,W=Date.now,H=_t(p,"Map"),J=_t(Object,"create"),K=function(){function t(){}return function(r){if(!Mt(r))return{};if(k)return k(r);t.prototype=r;var e=new t;return t.prototype=void 0,e}}();function Q(t){var r=-1,e=null==t?0:t.length;for(this.clear();++r-1},X.prototype.set=function(t,r){var e=this.__data__,n=nt(e,t);return n<0?(++this.size,e.push([t,r])):e[n][1]=r,this},Y.prototype.clear=function(){this.size=0,this.__data__={hash:new Q,map:new(H||X),string:new Q}},Y.prototype.delete=function(t){var r=pt(this,t).delete(t);return this.size-=r?1:0,r},Y.prototype.get=function(t){return pt(this,t).get(t)},Y.prototype.has=function(t){return pt(this,t).has(t)},Y.prototype.set=function(t,r){var e=pt(this,t),n=e.size;return e.set(t,r),this.size+=e.size==n?0:1,this},Z.prototype.clear=function(){this.__data__=new X,this.size=0},Z.prototype.delete=function(t){var r=this.__data__,e=r.delete(t);return this.size=r.size,e},Z.prototype.get=function(t){return this.__data__.get(t)},Z.prototype.has=function(t){return this.__data__.has(t)},Z.prototype.set=function(t,r){var e=this.__data__;if(e instanceof X){var n=e.__data__;if(!H||n.length<199)return n.push([t,r]),this.size=++e.size,this;e=this.__data__=new Y(n)}return e.set(t,r),this.size=e.size,this};var it,ut=function(t,r,e){for(var n=-1,o=Object(t),i=e(t),u=i.length;u--;){var c=i[it?u:++n];if(!1===r(o[c],c,o))break}return t};function ct(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":L&&L in Object(t)?function(t){var r=F.call(t,L),e=t[L];try{t[L]=void 0;var n=!0}catch(t){}var o=S.call(t);n&&(r?t[L]=e:delete t[L]);return o}(t):function(t){return S.call(t)}(t)}function at(t){return xt(t)&&ct(t)==o}function ft(t){return!(!Mt(t)||function(t){return!!U&&U in t}(t))&&(At(t)?P:a).test(function(t){if(null!=t){try{return C.call(t)}catch(t){}try{return t+""}catch(t){}}return""}(t))}function st(t){if(!Mt(t))return function(t){var r=[];if(null!=t)for(var e in Object(t))r.push(e);return r}(t);var r=dt(t),e=[];for(var n in t)("constructor"!=n||!r&&F.call(t,n))&&e.push(n);return e}function lt(t,r,e,n,o){t!==r&&ut(r,(function(i,u){if(o||(o=new Z),Mt(i))!function(t,r,e,n,o,i,u){var a=yt(t,e),f=yt(r,e),s=u.get(f);if(s)return void rt(t,e,s);var l=i?i(a,f,e+"",t,r,u):void 0,h=void 0===l;if(h){var p=wt(f),_=!p&&mt(f),v=!p&&!_&&Ct(f);l=f,p||_||v?wt(a)?l=a:xt(j=a)&&Ot(j)?l=function(t,r){var e=-1,n=t.length;r||(r=Array(n));for(;++e-1&&t%1==0&&t0){if(++r>=800)return arguments[0]}else r=0;return t.apply(void 0,arguments)}}(R?function(t,r){return R(t,"toString",{configurable:!0,enumerable:!1,value:(e=r,function(){return e}),writable:!0});var e}:It);function bt(t,r){return t===r||t!=t&&r!=r}var jt=at(function(){return arguments}())?at:function(t){return xt(t)&&F.call(t,"callee")&&!B.call(t,"callee")},wt=Array.isArray;function Ot(t){return null!=t&&zt(t.length)&&!At(t)}var mt=G||function(){return!1};function At(t){if(!Mt(t))return!1;var r=ct(t);return r==u||"[object GeneratorFunction]"==r||"[object AsyncFunction]"==r||"[object Proxy]"==r}function zt(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=n}function Mt(t){var r=typeof t;return null!=t&&("object"==r||"function"==r)}function xt(t){return null!=t&&"object"==typeof t}var Ct=b?function(t){return function(r){return t(r)}}(b):function(t){return xt(t)&&zt(t.length)&&!!s[ct(t)]};function Ft(t){return Ot(t)?tt(t,!0):st(t)}var Ut,St=(Ut=function(t,r,e){lt(t,r,e)},ht((function(t,r){var e=-1,n=r.length,o=n>1?r[n-1]:void 0,i=n>2?r[2]:void 0;for(o=Ut.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,r,e){if(!Mt(e))return!1;var n=typeof r;return!!("number"==n?Ot(e)&&vt(r,e.length):"string"==n&&r in e)&&bt(e[r],t)}(r[0],r[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++ec.call(t,r);class f{constructor({pluginId:t,defaultConfig:r={},customMerge:e,root:n}){this.pluginId=t,this.defaultConfig=r,this.pluginConfigPath=o.default.resolve(n||__dirname,t),this.customMerge=e,this._config=void 0}resolve(t){return o.default.resolve(this.pluginConfigPath,t)}hasFile(t){return n.default.existsSync(this.resolve(t))}requireFile(t){try{return require(this.resolve(t))}catch(t){if("MODULE_NOT_FOUND"===t.code)return;throw t}}_getUserConfig(){return this.requireFile("config.json")}config(t,r){this._config||(this._config=(this.customMerge||u)(this.defaultConfig,this._getUserConfig()));let e=this._config;return t?function(t,r,e){if("number"==typeof r)return t[r];if("symbol"==typeof r)return a(t,r)?t[r]:e;const n="string"!=typeof(o=r)?o:o.split(".").reduce(((t,r)=>(r.split(/\[([^}]+)\]/g).forEach((r=>r&&t.push(r))),t)),[]);var o;let i=t;for(let t=0;t { + keyArray.push(key[name]) + }) + keyArray.push(this._type) + return keyArray.join(':') + } + + getValue(value) { + return value + } + + getExpiresIn(value) { + if (value !== undefined) { + return value + } + return -1 + } + + validateKey(key) { + Validator.Key(this._keys, key) + } + + validateValue(value) { + Validator.Value(value) + } + + create(key, fallback) { + const keyString = this.getKeyString(key) + const options = { + layers: [{ + type: 'database', + key: keyString + }, { + type: 'redis', + key: keyString + }] + } + if (fallback !== null) { + const fallbackFunction = fallback || this.fallback + if (fallbackFunction) { + options.fallback = async () => { + return await fallbackFunction(key) + } + } + } + return new CacheKeyCascade(options) + } +} +Storage.Prefix = "uni-id" + +const Factory = { + + async Get(T, key, fallback) { + return await Factory.MakeUnique(T).get(key, fallback) + }, + + async Set(T, key, value, expiresIn) { + await Factory.MakeUnique(T).set(key, value, expiresIn) + }, + + async Remove(T, key) { + await Factory.MakeUnique(T).remove(key) + }, + + MakeUnique(T) { + return new T() + } +} + +module.exports = { + Storage, + Factory +}; diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/uni-cloud-cache.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/uni-cloud-cache.js new file mode 100644 index 0000000..2e4286b --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/uni-cloud-cache.js @@ -0,0 +1,324 @@ +const db = uniCloud.database() + +function getType(value) { + return Object.prototype.toString.call(value).slice(8, -1).toLowerCase() +} + +const validator = { + key: function(value) { + const err = new Error('Invalid key') + if (typeof value !== 'string') { + throw err + } + const valueTrim = value.trim() + if (!valueTrim || valueTrim !== value) { + throw err + } + }, + value: function(value) { + // 仅作简单校验 + const type = getType(value) + const validValueType = ['null', 'number', 'string', 'array', 'object'] + if (validValueType.indexOf(type) === -1) { + throw new Error('Invalid value type') + } + }, + duration: function(value) { + const err = new Error('Invalid duration') + if (value === undefined) { + return + } + if (typeof value !== 'number' || value === 0) { + throw err + } + } +} + +/** + * 入库时 expired 为过期时间对应的时间戳,永不过期用-1表示 + * 返回结果时 与redis对齐,-1表示永不过期,-2表示已过期或不存在 + */ +class DatabaseCache { + constructor({ + collection = 'opendb-open-data' + } = {}) { + this.type = 'db' + this.collection = db.collection(collection) + } + + _serializeValue(value) { + return value === undefined ? null : JSON.stringify(value) + } + + _deserializeValue(value) { + return value ? JSON.parse(value) : value + } + + async set(key, value, duration) { + validator.key(key) + validator.value(value) + validator.duration(duration) + value = this._serializeValue(value) + await this.collection.doc(key).set({ + value, + expired: duration && duration !== -1 ? Date.now() + (duration * 1000) : -1 + }) + } + + async _getWithDuration(key) { + const getKeyRes = await this.collection.doc(key).get() + const record = getKeyRes.data[0] + if (!record) { + return { + value: null, + duration: -2 + } + } + const value = this._deserializeValue(record.value) + const expired = record.expired + if (expired === -1) { + return { + value, + duration: -1 + } + } + const duration = expired - Date.now() + if (duration <= 0) { + await this.remove(key) + return { + value: null, + duration: -2 + } + } + return { + value, + duration: Math.floor(duration / 1000) + } + } + + async get(key, { + withDuration = true + } = {}) { + const result = await this._getWithDuration(key) + if (!withDuration) { + delete result.duration + } + return result + } + + async remove(key) { + await this.collection.doc(key).remove() + } +} + +class RedisCache { + constructor() { + this.type = 'redis' + this.redis = uniCloud.redis() + } + + _serializeValue(value) { + return value === undefined ? null : JSON.stringify(value) + } + + _deserializeValue(value) { + return value ? JSON.parse(value) : value + } + + async set(key, value, duration) { + validator.key(key) + validator.value(value) + validator.duration(duration) + value = this._serializeValue(value) + if (!duration || duration === -1) { + await this.redis.set(key, value) + } else { + await this.redis.set(key, value, 'EX', duration) + } + } + + async get(key, { + withDuration = false + } = {}) { + let value = await this.redis.get(key) + value = this._deserializeValue(value) + if (!withDuration) { + return { + value + } + } + const durationSecond = await this.redis.ttl(key) + let duration + switch (durationSecond) { + case -1: + duration = -1 + break + case -2: + duration = -2 + break + default: + duration = durationSecond + break + } + return { + value, + duration + } + } + + async remove(key) { + await this.redis.del(key) + } +} + +class Cache { + constructor({ + type, + collection + } = {}) { + if (type === 'database') { + return new DatabaseCache({ + collection + }) + } else if (type === 'redis') { + return new RedisCache() + } else { + throw new Error('Invalid cache type') + } + } +} + +class CacheKey { + constructor({ + type, + collection, + cache, + key, + fallback + } = {}) { + this.cache = cache || new Cache({ + type, + collection + }) + this.key = key + this.fallback = fallback + } + + async set(value, duration) { + await this.cache.set(this.key, value, duration) + } + + async setWithSync(value, duration, syncMethod) { + await Promise.all([ + this.set(this.key, value, duration), + syncMethod(value, duration) + ]) + } + + async get() { + let { + value, + duration + } = await this.cache.get(this.key) + if (value !== null && value !== undefined) { + return { + value, + duration + } + } + if (!this.fallback) { + return { + value: null, + duration: -2 + } + } + const fallbackResult = await this.fallback() + value = fallbackResult.value + duration = fallbackResult.duration + if (value !== null && duration !== undefined) { + await this.cache.set(this.key, value, duration) + } + return { + value, + duration + } + } + + async remove() { + await this.cache.remove(this.key) + } +} + +class CacheKeyCascade { + constructor({ + layers, // [{cache, type, collection, key}] 从低级到高级排序,[DbCacheKey, RedisCacheKey] + fallback + } = {}) { + this.layers = layers + this.cacheLayers = [] + let lastCacheKey + for (let i = 0; i < layers.length; i++) { + const { + type, + cache, + collection, + key + } = layers[i] + const lastCacheKeyTemp = lastCacheKey + try { + const currentCacheKey = new CacheKey({ + type, + collection, + cache, + key, + fallback: i === 0 ? fallback : function() { + return lastCacheKeyTemp.get() + } + }) + this.cacheLayers.push(currentCacheKey) + lastCacheKey = currentCacheKey + } catch (e) {} + } + this.highLevelCache = lastCacheKey + } + + async set(value, duration) { + return Promise.all( + this.cacheLayers.map(item => { + return item.set(value, duration) + }) + ) + } + + async setWithSync(value, duration, syncMethod) { + const setPromise = this.cacheLayers.map(item => { + return item.set(value, duration) + }) + return Promise.all( + [ + ...setPromise, + syncMethod(value, duration) + ] + ) + } + + async get() { + return this.highLevelCache.get() + } + + async remove() { + await Promise.all( + this.cacheLayers.map(cacheKeyItem => { + return cacheKeyItem.remove() + }) + ) + } +} + +module.exports = { + Cache, + DatabaseCache, + RedisCache, + CacheKey, + CacheKeyCascade +} diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/validator.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/validator.js new file mode 100644 index 0000000..47a455b --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/validator.js @@ -0,0 +1,31 @@ +const Validator = { + + Key(keyArray, parameters) { + for (let i = 0; i < keyArray.length; i++) { + const keyName = keyArray[i] + if (typeof parameters[keyName] !== 'string') { + Validator.ThrowNewError(`Invalid ${keyName}`) + } + if (parameters[keyName].length < 1) { + Validator.ThrowNewError(`Invalid ${keyName}`) + } + } + }, + + Value(value) { + if (value === undefined) { + Validator.ThrowNewError('Invalid Value') + } + if (typeof value !== 'object') { + Validator.ThrowNewError('Invalid Value Type') + } + }, + + ThrowNewError(message) { + throw new Error(message) + } +} + +module.exports = { + Validator +} diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/weixin-server.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/weixin-server.js new file mode 100644 index 0000000..0a0c811 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/weixin-server.js @@ -0,0 +1,202 @@ +'use strict'; + +const crypto = require('crypto') + +const { + HTTP_STATUS +} = require('./consts.js') + +const { + BridgeError +} = require('./bridge-error.js') + +class WeixinServer { + + constructor(options = {}) { + this._appid = options.appid + this._secret = options.secret + } + + getAccessToken() { + return uniCloud.httpclient.request(WeixinServer.AccessToken_Url, { + dataType: 'json', + method: 'POST', + data: { + appid: this._appid, + secret: this._secret, + grant_type: "client_credential" + } + }) + } + + // 使用客户端获取的 code 从微信服务器换取 openid,code 仅可使用一次 + codeToSession(code) { + return uniCloud.httpclient.request(WeixinServer.Code2Session_Url, { + dataType: 'json', + data: { + appid: this._appid, + secret: this._secret, + js_code: code, + grant_type: 'authorization_code' + } + }) + } + + getUserEncryptKey({ + access_token, + openid, + session_key + }) { + console.log(access_token, openid, session_key); + const signature = crypto.createHmac('sha256', session_key).update('').digest('hex') + return uniCloud.httpclient.request(WeixinServer.User_Encrypt_Key_Url, { + dataType: 'json', + method: 'POST', + dataAsQueryString: true, + data: { + access_token, + openid: openid, + signature: signature, + sig_method: 'hmac_sha256' + } + }) + } + + getH5AccessToken() { + return uniCloud.httpclient.request(WeixinServer.AccessToken_H5_Url, { + dataType: 'json', + method: 'GET', + data: { + appid: this._appid, + secret: this._secret, + grant_type: "client_credential" + } + }) + } + + getH5Ticket(access_token) { + return uniCloud.httpclient.request(WeixinServer.Ticket_Url, { + dataType: 'json', + dataAsQueryString: true, + method: 'POST', + data: { + access_token + } + }) + } + + getH5AccessTokenForEip() { + return uniCloud.httpProxyForEip.postForm(WeixinServer.AccessToken_H5_Url, { + appid: this._appid, + secret: this._secret, + grant_type: "client_credential" + }, { + dataType: 'json' + }) + } + + getH5TicketForEip(access_token) { + return uniCloud.httpProxyForEip.postForm(WeixinServer.Ticket_Url, { + access_token + }, { + dataType: 'json', + dataAsQueryString: true + }) + } +} + +WeixinServer.AccessToken_Url = 'https://api.weixin.qq.com/cgi-bin/token' +WeixinServer.Code2Session_Url = 'https://api.weixin.qq.com/sns/jscode2session' +WeixinServer.User_Encrypt_Key_Url = 'https://api.weixin.qq.com/wxa/business/getuserencryptkey' +WeixinServer.AccessToken_H5_Url = 'https://api.weixin.qq.com/cgi-bin/token' +WeixinServer.Ticket_Url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi' + +WeixinServer.GetMPAccessToken = function(options) { + return new WeixinServer(options).getAccessToken() +} + +WeixinServer.GetCodeToSession = function(options) { + return new WeixinServer(options).codeToSession(options.code) +} + +WeixinServer.GetUserEncryptKey = function(options) { + return new WeixinServer(options).getUserEncryptKey(options) +} + +WeixinServer.GetH5AccessToken = function(options) { + return new WeixinServer(options).getH5AccessToken() +} + +WeixinServer.GetH5Ticket = function(options) { + return new WeixinServer(options).getH5Ticket(options.access_token) +} + +//////////////////////////////////////////////////////////////// + +function isAliyun() { + return (uniCloud.getCloudInfos()[0].provider === 'aliyun') +} + +WeixinServer.GetResponseData = function(response) { + console.log("WeixinServer::response", response) + + if (!(response.status === HTTP_STATUS.SUCCESS || response.statusCodeValue === HTTP_STATUS.SUCCESS)) { + throw new BridgeError(response.status || response.statusCodeValue, response.status || response.statusCodeValue) + } + + const responseData = response.data || response.body + + if (responseData.errcode !== undefined && responseData.errcode !== 0) { + throw new BridgeError(responseData.errcode, responseData.errmsg) + } + + return responseData +} + +WeixinServer.GetMPAccessTokenData = async function(options) { + const response = await new WeixinServer(options).getAccessToken() + return WeixinServer.GetResponseData(response) +} + +WeixinServer.GetCodeToSessionData = async function(options) { + const response = await new WeixinServer(options).codeToSession(options.code) + return WeixinServer.GetResponseData(response) +} + +WeixinServer.GetUserEncryptKeyData = async function(options) { + const response = await new WeixinServer(options).getUserEncryptKey(options) + return WeixinServer.GetResponseData(response) +} + +WeixinServer.GetH5AccessTokenData = async function(options) { + const ws = new WeixinServer(options) + let response + if (isAliyun()) { + response = await ws.getH5AccessTokenForEip() + if (typeof response === 'string') { + response = JSON.parse(response) + } + } else { + response = await ws.getH5AccessToken() + } + return WeixinServer.GetResponseData(response) +} + +WeixinServer.GetH5TicketData = async function(options) { + const ws = new WeixinServer(options) + let response + if (isAliyun()) { + response = await ws.getH5TicketForEip(options.access_token) + if (typeof response === 'string') { + response = JSON.parse(response) + } + } else { + response = await ws.getH5Ticket(options.access_token) + } + return WeixinServer.GetResponseData(response) +} + + +module.exports = { + WeixinServer +} diff --git a/uni_modules/uni-open-bridge-common/uniCloud/database/opendb-open-data.schema.json b/uni_modules/uni-open-bridge-common/uniCloud/database/opendb-open-data.schema.json new file mode 100644 index 0000000..9fc8bf9 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/database/opendb-open-data.schema.json @@ -0,0 +1,19 @@ +// 文档教程: https://uniapp.dcloud.net.cn/uniCloud/schema +{ + "bsonType": "object", + "required": ["_id", "value"], + "properties": { + "_id": { + "bsonType": "string", + "description": "key,格式:uni-id:[dcloudAppid]:[platform]:[openid]:[access-token|user-access-token|session-key|encrypt-key-version|ticket]" + }, + "value": { + "bsonType": "object", + "description": "字段_id对应的值" + }, + "expired": { + "bsonType": "date", + "description": "过期时间" + } + } +} -- GitLab